Skip to content

Instantly share code, notes, and snippets.

@rdeioris
Created February 8, 2019 18:50
Show Gist options
  • Save rdeioris/32dfeaf4aab72085b5eed43049fdf59a to your computer and use it in GitHub Desktop.
Save rdeioris/32dfeaf4aab72085b5eed43049fdf59a to your computer and use it in GitHub Desktop.
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