-
Notifications
You must be signed in to change notification settings - Fork 3
/
playback.py
151 lines (146 loc) · 5.19 KB
/
playback.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
from __future__ import print_function
import sys
FILE_VERSION = 1
import argparse
parser = argparse.ArgumentParser(description="Playback some gameplay")
parser.add_argument('file', default='replay.demo', help="File to read from")
parser.add_argument('port', default=32887, type=int, help="The port to run on")
args = parser.parse_args()
import struct
with open(args.file, "rb") as fh:
fmt = "BB"
fmtlen = struct.calcsize(fmt)
data = fh.read(fmtlen)
file_version, aos_version = struct.unpack(fmt, data)
if FILE_VERSION != file_version:
if FILE_VERSION < file_version:
print("This demo was recorded on a newer version of aos_replay.")
elif FILE_VERSION > file_version:
print("This demo was recorded on an older version of aos_replay.")
print("aos_replay version: %d" % FILE_VERSION)
print("Demo version: %d" % file_version)
sys.exit(1)
class Client(object):
def __init__(self, peer, fh, start_time):
self.peer = peer
self.fh = fh
self.fh.read(struct.calcsize("BB"))
self.start_time = start_time
self.pause_time = 0
self.get_next_packet()
self.spawned = False
self.spam_time = None
self.playerinfo = [[0,0] for _ in range(32)]
self.playerid = None
def get_next_packet(self):
fmt = "fH"
fmtlen = struct.calcsize(fmt)
meta = self.fh.read(fmtlen)
if len(meta) < fmtlen:
raise EOFError("replay file finished")
self.timedelta, size = struct.unpack(fmt, meta)
self.data = self.fh.read(size)
if ord(self.data[0]) == 15: # state data
self.playerid = ord(self.data[1])
import enet
from time import time
host = enet.Host(enet.Address('localhost', args.port), 128, 1)
host.compress_with_range_coder()
clients = {}
client_id = 0
while True:
for cl in clients.values():
if cl.pause_time > 0:
continue
if cl.spam_time is not None and cl.spam_time <= time():
pkt = struct.pack("bbb", 17, 35, 2) + str(cl.timedelta).encode('cp437', 'replace') #chat message
cl.peer.send(0, enet.Packet(pkt, enet.PACKET_FLAG_RELIABLE))
cl.spam_time = time() + 1
while cl.start_time + cl.timedelta <= time():
if ord(cl.data[0]) == 3: #input data
player, data = struct.unpack("xbb", cl.data)
cl.playerinfo[player][0] = data
elif ord(cl.data[0]) == 4: #weapon data
player, data = struct.unpack("xbb", cl.data)
cl.playerinfo[player][1] = data
cl.peer.send(0, enet.Packet(cl.data, enet.PACKET_FLAG_RELIABLE))
try:
cl.get_next_packet()
except EOFError:
print(cl.peer.data, "finished playback")
cl.peer.disconnect(0) #ERROR_UNDEFINED
cl.fh.close()
del clients[cl.peer.data]
break
try:
event = host.service(0)
except IOError:
continue
if event is None:
continue
elif event.type == enet.EVENT_TYPE_CONNECT:
if event.peer.eventData == aos_version:
event.peer.data = str(client_id)
client_id += 1
clients[event.peer.data] = Client(event.peer, open(args.file, "rb"), time())
print("received client connection", event.peer.data)
else:
print("WRONG CLIENT VERSION: replay is version %s and client was version %s" % (aos_version, event.peer.eventData))
event.peer.disconnect_now(3) #ERROR_WRONG_VERSION
elif event.type == enet.EVENT_TYPE_DISCONNECT:
if event.peer.data in clients:
clients[event.peer.data].fh.close()
del clients[event.peer.data]
print("lost client connection", event.peer.data)
elif event.type == enet.EVENT_TYPE_RECEIVE:
cl = clients[event.peer.data]
if not cl.spawned:
if cl.playerid is None:
print("error: could not figure out player id, guessing! use the command 'id X' to fix")
cl.playerid = 0
cl.spawned = True
pkt = struct.pack("bbbbfff16s", 12, cl.playerid, 1, -1, 255., 255., 1., "")
event.peer.send(0, enet.Packet(pkt, enet.PACKET_FLAG_RELIABLE))
elif ord(event.packet.data[0]) == 17:
chat = event.packet.data[3:-1].decode('cp437', 'replace')
if chat == "spawn":
if cl.playerid is None:
print("error: could not figure out player id, guessing! use the command 'id X' to fix")
cl.playerid = 0
cl.spawned = True
pkt = struct.pack("bbbbfff16s", 12, cl.playerid, 1, -1, 255., 255., 1., "asd") #create player
event.peer.send(0, enet.Packet(pkt, enet.PACKET_FLAG_RELIABLE))
elif chat[:3] == "id ":
try:
playerid = int(chat[3:])
except:
pass
else:
cl.playerid = playerid
elif chat == "pause" and cl.pause_time == 0:
cl.pause_time = time()
for i in range(32):
pkt = struct.pack("bbb", 3, i, 0) #input data
event.peer.send(0, enet.Packet(pkt, enet.PACKET_FLAG_RELIABLE))
pkt = struct.pack("bbb", 4, i, 0) #weapon data
event.peer.send(0, enet.Packet(pkt, enet.PACKET_FLAG_RELIABLE))
elif chat == "unpause" and cl.pause_time > 0:
cl.start_time += time() - cl.pause_time
cl.pause_time = 0
for i in range(32):
pkt = struct.pack("bbb", 3, i, cl.playerinfo[i][0]) #input data
event.peer.send(0, enet.Packet(pkt, enet.PACKET_FLAG_RELIABLE))
pkt = struct.pack("bbb", 4, i, cl.playerinfo[i][1]) #weapon data
event.peer.send(0, enet.Packet(pkt, enet.PACKET_FLAG_RELIABLE))
elif chat[:3] == "ff ":
try:
skip = int(chat[3:])
except:
pass
else:
cl.start_time = cl.start_time - skip
elif chat == "time":
if cl.spam_time is None:
cl.spam_time = 0
else:
cl.spam_time = None