diff pytouhou/network.py @ 475:9d4d52793eca

Experimental netplay! Yay!
author Thibaut Girka <thib@sitedethib.com>
date Wed, 28 Dec 2011 18:45:09 +0100
parents
children e71b1bcf952a
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/pytouhou/network.py
@@ -0,0 +1,66 @@
+import socket
+import struct
+from select import select
+
+MSG_STRUCT = struct.Struct('!IHHB')
+
+class Network(object):
+    def __init__(self, port=8080, dest=None):
+        self.frame = 0
+        self.keystate = 0
+        self.old_keystate = 0
+
+        self.remote_addr = dest
+        self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
+        self.sock.setblocking(0)
+        self.sock.bind(('', port))
+
+
+    def read_messages(self):
+        messages = []
+
+        rlist, wlist, xlist = select([self.sock], [], [], 0)
+        while rlist:
+            msg, addr = rlist[0].recvfrom(MSG_STRUCT.size)
+            # Check whether the message comes from the right address
+            if self.remote_addr is None or addr == self.remote_addr:
+                self.remote_addr = addr
+
+                frame, keystate, old_keystate, checksum = MSG_STRUCT.unpack(msg)
+
+                # Check for well-formedness
+                if checksum == sum(ord(c) for c in msg[:-1]) & 0xFF:
+                    messages.append((frame, keystate, old_keystate, checksum))
+            else:
+                print('Mismatch', self.remote_addr, addr)
+
+            rlist, wlist, xlist = select(rlist, [], [], 0)
+
+        return messages
+
+
+    def send_message(self):
+        frame, keystate, old_keystate = self.frame, self.keystate, self.old_keystate
+        if self.remote_addr is not None:
+            checksum = frame + (frame >> 8) + (frame >> 16) + (frame >> 24)
+            checksum += keystate + (keystate >> 8)
+            checksum += old_keystate + (old_keystate >> 8)
+            checksum &= 0xFF
+            self.sock.sendto(MSG_STRUCT.pack(frame, keystate, old_keystate, checksum), self.remote_addr)
+
+
+    def run_iter(self, game, keystate):
+        if self.frame < game.frame:
+            self.old_keystate, self.keystate = self.keystate, keystate
+            self.frame = game.frame
+
+        for frame, keystate, old_keystate, checksum in self.read_messages():
+            if frame == game.frame:
+                game.run_iter([self.keystate, keystate])
+            elif frame == game.frame + 1:
+                print('Skipped')
+                game.run_iter([self.keystate, old_keystate])
+                game.run_iter([self.keystate, keystate])
+
+        self.send_message()
+