Created
February 8, 2019 18:50
-
-
Save rdeioris/32dfeaf4aab72085b5eed43049fdf59a 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 numpy | |
| import struct | |
| import select | |
| COMMAND_JOIN = 0 | |
| COMMAND_SET_VELOCITY = 1 | |
| COMMAND_UPDATE_LOCATION = 2 | |
| HZ = 1.0 / 10 | |
| 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 | |
| #print('player {} {}'.format(self.address, self.location)) | |
| packet = struct.pack('=Bfff', COMMAND_UPDATE_LOCATION, self.location[0], self.location[1], self.location[2]) | |
| self.server.send_all_queue.append(packet) | |
| class GameServer: | |
| def __init__(self, address, port): | |
| self.address = address | |
| self.port = port | |
| self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) | |
| self.socket.setblocking(False) | |
| self.socket.bind((self.address, self.port)) | |
| self.commands_table = {} | |
| self.commands_table[COMMAND_JOIN] = self.join | |
| self.commands_table[COMMAND_SET_VELOCITY] = self.set_velocity | |
| self.players = {} | |
| self.next_wait = HZ | |
| self.send_all_queue = [] | |
| def tick_players(self, now): | |
| dead_clients = [] | |
| for player in self.players.values(): | |
| if now - player.last_packet_timestamp > 20: | |
| dead_clients.append(player.address) | |
| else: | |
| player.tick() | |
| for dead_client in dead_clients: | |
| del(self.players[dead_client]) | |
| print('{} is dead'.format(dead_client)) | |
| # send enqueued packets to all clients | |
| for packet in self.send_all_queue: | |
| for player in self.players.values(): | |
| self.socket.sendto(packet, player.address) | |
| self.send_all_queue = [] | |
| def tick(self): | |
| before = time.perf_counter() | |
| rlist, _, _ = select.select([self.socket], [], [], self.next_wait) | |
| after = time.perf_counter() | |
| self.next_wait -= after - before | |
| if self.socket not in rlist or self.next_wait <= 0: | |
| self.tick_players(time.perf_counter()) | |
| self.next_wait = HZ | |
| if self.socket not in rlist: | |
| return | |
| try: | |
| self.packet, self.sender = self.socket.recvfrom(64) | |
| except socket.error: | |
| return | |
| # check packet size | |
| if len(self.packet) <= 0: | |
| return | |
| command = self.packet[0] | |
| # dispatcher | |
| if command in self.commands_table: | |
| self.commands_table[command]() | |
| def join(self): | |
| if len(self.players) >= 5: | |
| return | |
| if self.sender in self.players: | |
| return | |
| self.players[self.sender] = GamePlayer(self, self.sender) | |
| print('{} joined the match ({} players)'.format(self.sender, len(self.players))) | |
| def set_velocity(self): | |
| if not self.sender in self.players: | |
| return | |
| 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