Start sync., delays improved

master
kaqu 2 years ago
parent aec4debea9
commit 399151f29b
  1. 4
      .vscode/launch.json
  2. 6
      game_objects/pong_constants.py
  3. 37
      game_objects/pong_player.py
  4. 1
      game_objects/pong_sound.py
  5. 6
      game_objects/pong_viewer.py
  6. 8
      game_objects/pong_viewserver.py
  7. 19
      pandemic_pong.py

@ -9,8 +9,8 @@
"type": "python",
"request": "launch",
"program": "${file}",
//"args": ["--sizeable", "--server"],
"args": ["--sizeable", "--player", "1", "127.0.0.1"],
"args": ["--sizeable", "--server"],
//"args": ["--sizeable", "--player", "1", "127.0.0.1"],
//"args": ["--sizeable", "--viewer", "127.0.0.1"],
"console": "integratedTerminal"
}

@ -61,7 +61,7 @@ MATCHWINSOUND = 7
PANDEMIC_PONG_PORT = 5050 # PP (Pandemic Pong!)
PACKETTYPE_ALLDATA = 0xffa0 # Packet start indicator
PACKETTYPE_PLAYER = 1
UDP_TRANSFER_FORMAT = "iiiffffii"
UDP_TRANSFER_FORMAT = "iiiiffffii"
TCP_TRANSFER_FORMAT = "i"+"iiiii"+"iiffffiii"+"iiffffiii"+"ffffffiii"
# Game: state, delay, p1_game, p2_game, playsound
# Player1: player_index, state, x, y, delta_x, delta_y, color, delay, score
@ -84,3 +84,7 @@ GAMEAREA_MIN_X = 0 # Game area left border
GAMEAREA_MAX_X = 1920 # Assume FHD resolution by default
GAMEAREA_MIN_Y = 15 # Game area top border
GAMEAREA_MAX_Y = 940 # Game area bottom range
"""Fine tuning thread yield"""
SLEEPSERVERMAINLOOP = 0.035 #0.04 # 0.025
SLEEPSERVERSTREAMINGTHREAD = 0.035 # 0.04 0.05

@ -7,7 +7,7 @@ Pandemic Pong Player Logic
"""
import os, fcntl
import os, fcntl, sys
import libevdev
import struct # Packing/unpacking
import socket # External communication
@ -69,6 +69,7 @@ class PongPlayer:
self.dev = libevdev.Device(self.fd) # Actual gamepad of this player
else:
self.dev = None
self.seqnum = 0 # Reset sequence#
self.player_index = player_index # Who am I?
self.player_server = player_server # IP of game server
if len(player_server) > 0: # IP provided
@ -190,7 +191,8 @@ class PongPlayer:
if bChanged and self.bUseServer:
bData = struct.pack(pgc.UDP_TRANSFER_FORMAT,
pgc.PACKETTYPE_PLAYER,
self.seqnum,
pgc.PACKETTYPE_PLAYER,
self.player_index,
self.state,
self.x,
@ -200,7 +202,11 @@ class PongPlayer:
self.color,
self.delay
)
self.socketUDP.sendto(bData, (self.player_server, pgc.PANDEMIC_PONG_PORT))
self.socketUDP.sendto(bData, (self.player_server, pgc.PANDEMIC_PONG_PORT))
if self.seqnum < 32767: # Increment seq# for next packet
self.seqnum += 1
else:
self.seqnum = 0
else: # This player is remote!
pass
@ -217,26 +223,14 @@ class PongPlayer:
global UDP_PACKET_SIZE, serverUDP
try: # Receive self.player_index data
data, addr = serverUDP.recvfrom(UDP_PACKET_SIZE) # blocks! buffer size is 1024 bytes
if data[0] == pgc.PACKETTYPE_ALLDATA:
data, addr = serverUDP.recvfrom(UDP_PACKET_SIZE)
if data[1] == pgc.PACKETTYPE_ALLDATA:
pass # Future extension reserve ...
else: # Player data
_, player_index, state, x, y, delta_x, delta_y, color, delay = struct.unpack(pgc.UDP_TRANSFER_FORMAT, data)
"""
print("({}) #{} S:{} X:{} Y:{} DX:{} DY:{} C:{} D:{}".format(
addr[0],
player_index,
state,
x,
y,
delta_x,
delta_y,
color,
delay)
)
"""
# TODO: Needs to be sent to other player ...
seqnum, _, player_index, state, x, y, delta_x, delta_y, color, delay = struct.unpack(pgc.UDP_TRANSFER_FORMAT, data)
#print("S#{}".format(seqnum), end=" ")
if player_index == self.player_index:
self.seqnum = seqnum
self.state = state
self.x = x
self.y = y
@ -245,6 +239,7 @@ class PongPlayer:
self.color = color
self.delay = delay
else:
other.seqnum = seqnum
other_player.state = state
other_player.x = x
other_player.y = y
@ -255,7 +250,7 @@ class PongPlayer:
return True # Change indication ...
except BlockingIOError:
except BlockingIOError:
pass
return False

@ -22,7 +22,6 @@ class AsyncSound(threading.Thread):
def run(self):
"""Called async.(!) from start() s.a.!"""
playsound(self.soundfile)
print("Played: {}".format(self.soundfile))
if __name__ == "__main__":

@ -93,7 +93,7 @@ class pongWindow(QMainWindow):
playsound(pgc.sounds[pgc.PLAYERMISSSOUND])
playsound(pgc.sounds[pgc.WALLCONTACTSOUND])
playsound(pgc.sounds[pgc.GAMEEXITSOUND])
time.sleep(0.5)
time.sleep(0.5) # Play sounds ...
playsound(pgc.sounds[pgc.GAMESPLASHSOUND])
self.timer = QTimer() # Start processing 'loop'
@ -137,7 +137,8 @@ class pongWindow(QMainWindow):
painter.drawText(int((pgc.GAMEAREA_MAX_X / 2 + 100) * scale_x), int(pgc.GAMEAREA_MAX_Y / 5 * 2 * scale_y), "to infect player,")
painter.drawText(int((pgc.GAMEAREA_MAX_X / 2 + 100) * scale_x), int(pgc.GAMEAREA_MAX_Y / 5 * 3 * scale_y), "view will pickup virus!")
painter.drawText(int((pgc.GAMEAREA_MAX_X / 2 + 100) * scale_x), int(pgc.GAMEAREA_MAX_Y / 5 * 4 * scale_y), "Match color to deflect!")
while self.viewserver.receive_data() == 1: # Empty receive queue (to sync. faster!)
pass
elif self.game.state == pgc.STATE_PLAY: # Actual play 'til score reaches 10 points
# Ball gives NO indication ...
painter.drawRect(int(self.ball.x * scale_x), int(self.ball.y * scale_y), int(self.ball.w * scale_x), int(self.ball.h * scale_y)) # Ball
@ -232,6 +233,7 @@ class pongWindow(QMainWindow):
if self.game.pong_game(self.ball, self.player1, self.player2) == False:
# Quit gracefully
print("Player exiting ...")
time.sleep(2)
self.player2.exit()
self.player1.exit()
sys.exit(0)

@ -185,7 +185,7 @@ class Handler(BaseHTTPRequestHandler):
sendgame.playsound = pgc.NOSOUND
if sendball.playsound != pgc.NOSOUND:
sendball.playsound = pgc.NOSOUND
time.sleep(0.05) # Minimum required on i7/3rd gen. machine
time.sleep(pgc.SLEEPSERVERSTREAMINGTHREAD) # Yield from 1 (of n) streaming threads
except BrokenPipeError:
print("Client terminated.")
bError = True
@ -194,8 +194,7 @@ class Handler(BaseHTTPRequestHandler):
class Thread(threading.Thread):
"""TCP service streaming game data"""
def __init__(self, i, game):
print("Starting thread #{} ...".format(i))
def __init__(self, i, game):
self.game = game
threading.Thread.__init__(self)
self.i = i
@ -210,8 +209,7 @@ class Thread(threading.Thread):
# Prevent the HTTP server from re-binding every handler.
# https://stackoverflow.com/questions/46210672/
httpd.socket = server_tcpsocket
httpd.server_bind = self.server_close = lambda self: None
print("Thread listening ...")
httpd.server_bind = self.server_close = lambda self: None
try:
httpd.serve_forever() # Never returns ...
except BrokenPipeError: # TODO: Not working?! May be removed alltogether?

@ -71,17 +71,7 @@ if __name__ == '__main__':
else: # Local version
print("*** PANDEMIC PONG (local) ***")
# Figure out 2 highest event queues as they are assumed to be the gamepads
# ls -al usb-0079_USB_Gamepad-event-joystick -> ../event7
sEventQueue1, sEventQueue2 = pickEventQueues()
"""
maxEvent = 0
for l in glob("/dev/input/event?"):
if int(l[-1]) > maxEvent:
maxEvent = int(l[-1])
sEventQueue1 = "/dev/input/event" + str(maxEvent-1)
sEventQueue2 = "/dev/input/event" + str(maxEvent)
"""
sEventQueue1, sEventQueue2 = pickEventQueues() # Search 'GAMEPAD ' entries (1 or 2 connected?)
if pgc.DEVLOCAL == False:
print("I'm a slow starter, please be patient!") # Caching actually ...
@ -91,9 +81,12 @@ if __name__ == '__main__':
game = PongGame(pgv.bIsServer)
ball = PongObject(pgc.GAMEAREA_MAX_X/2, pgc.GAMEAREA_MAX_Y/2, 20, 20, 8.0, 2.5)
if player_index == 0: # Local or viewer or server?
if (pgv.bIsServer == True) or (pgv.bIsViewer == True): # Server & viewer version, no gamepads locally avail.
if pgv.bIsServer == True: # Server, no gamepads locally avail.
player1 = PongPlayer(None, True, 1, "", 10, pgc.GAMEAREA_MAX_Y/2-50, 20, 160)
player2 = PongPlayer(None, True, 2, "", pgc.GAMEAREA_MAX_X-40, pgc.GAMEAREA_MAX_Y/2-50, 20, 160)
elif pgv.bIsViewer == True: # Viewer, no gamepads locally avail.
player1 = PongPlayer(None, False, 1, "", 10, pgc.GAMEAREA_MAX_Y/2-50, 20, 160)
player2 = PongPlayer(None, False, 2, "", pgc.GAMEAREA_MAX_X-40, pgc.GAMEAREA_MAX_Y/2-50, 20, 160)
else: # Local version (both gamepads assumed locally connected)
player1 = PongPlayer(sEventQueue1, False, 1, "", 10, pgc.GAMEAREA_MAX_Y/2-50, 20, 160)
player2 = PongPlayer(sEventQueue2, False, 2, "", pgc.GAMEAREA_MAX_X-40, pgc.GAMEAREA_MAX_Y/2-50, 20, 160)
@ -137,7 +130,7 @@ if __name__ == '__main__':
try:
if game.pong_game(ball, player1, player2) == False: # Player game ended
game.reinit() # Re-init on server
time.sleep(0.025) # Yield to other threads ...
time.sleep(pgc.SLEEPSERVERMAINLOOP) # Yield to other threads ...
except KeyboardInterrupt:
print("\rPandemic Pong Server stopped by user.")
break

Loading…
Cancel
Save