Created
February 8, 2019 18:53
-
-
Save rdeioris/2f992db1014bfb26534c177f625f432c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import socket | |
| import sys | |
| import time | |
| import select | |
| import numpy | |
| import struct | |
| HZ = 1.0 / 10 | |
| COMMAND_JOIN = 0 | |
| SET_VELOCITY = 1 | |
| UPDATE_POSITION = 2 | |
| class GamePlayer: | |
| def __init__(self, server, address): | |
| self.server = server | |
| self.address = address | |
| self.last_packet_timestamp = time.perf_counter() | |
| self.location = numpy.array((0.0, 0.0, 0.0)) | |
| self.velocity = numpy.array((0.0, 0.0, 0.0)) | |
| def tick(self): | |
| self.location += self.velocity * HZ | |
| packet = struct.pack('=Bfff', UPDATE_POSITION, self.location[0], self.location[1], self.location[2]) | |
| self.server.packets_to_send.append(packet) | |
| class GameServer: | |
| def __init__(self, address, port): | |
| self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) | |
| self.socket.setblocking(False) | |
| self.socket.bind((address, port)) | |
| self.commands_table = {} | |
| self.commands_table[COMMAND_JOIN] = self.join | |
| self.commands_table[SET_VELOCITY] = self.set_velocity | |
| self.players = {} | |
| self.time_to_wait = HZ | |
| self.packets_to_send = [] | |
| def tick(self): | |
| if self.time_to_wait < 0: | |
| self.time_to_wait = 0 | |
| before = time.perf_counter() | |
| # check if self.socket is ready | |
| rlist, wlist, xlist = select.select([self.socket], [], [], self.time_to_wait) | |
| after = time.perf_counter() | |
| # check how much time passed into select | |
| self.time_to_wait -= (after - before) | |
| has_received_packet = False | |
| # is self.socket ready ? | |
| if self.socket in rlist: | |
| try: | |
| self.packet, self.sender = self.socket.recvfrom(64) | |
| has_received_packet = True | |
| except socket.error: | |
| print('non-blocking exception!') | |
| else: | |
| self.time_to_wait = 0 | |
| if has_received_packet: | |
| # check the size of the packet (zero packet would require a KICK) | |
| if len(self.packet) < 1: | |
| return | |
| # check command availability | |
| if self.packet[0] not in self.commands_table: | |
| return | |
| # dispatch request | |
| self.commands_table[self.packet[0]]() | |
| for packet in self.packets_to_send: | |
| for player in self.players.values(): | |
| self.socket.sendto(packet, player.address) | |
| self.packets_to_send = [] | |
| if self.time_to_wait > 0: | |
| return | |
| #print('HZ elapsed') | |
| now = time.perf_counter() | |
| dead_players = [] | |
| for player in self.players.values(): | |
| # check last received packed | |
| if now - player.last_packet_timestamp >= 5: | |
| print('player {} is dead'.format(player.address)) | |
| dead_players.append(player.address) | |
| else: | |
| player.tick() | |
| # remove dead players | |
| for player_address in dead_players: | |
| del(self.players[player_address]) | |
| self.time_to_wait = HZ | |
| def join(self): | |
| if self.sender in self.players: | |
| return | |
| self.players[self.sender] = GamePlayer(self, self.sender) | |
| print('received join from {}'.format(self.sender)) | |
| def set_velocity(self): | |
| #print('set_velocity for {}'.format(self.sender)) | |
| # check if the player is known | |
| if self.sender not in self.players: | |
| return | |
| # check packet size | |
| if len(self.packet) != 13: | |
| return | |
| _, x, y, z = struct.unpack('=Bfff', self.packet) | |
| player = self.players[self.sender] | |
| player.last_packet_timestamp = time.perf_counter() | |
| player.velocity = numpy.array((x, y, z)) | |
| game_server = GameServer(sys.argv[1], int(sys.argv[2])) | |
| while True: | |
| game_server.tick() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment