241 lines
7.9 KiB
Python
241 lines
7.9 KiB
Python
import ini, packets
|
|
import os, time
|
|
from PyQt4 import QtCore, QtGui
|
|
from bisect import bisect_left
|
|
|
|
class DemoPlayer(QtCore.QObject):
|
|
MS_Chat = QtCore.pyqtSignal(list)
|
|
newChar = QtCore.pyqtSignal(str)
|
|
newBackground = QtCore.pyqtSignal(str, bool)
|
|
IC_Log = QtCore.pyqtSignal(str)
|
|
OOC_Log = QtCore.pyqtSignal(str)
|
|
charSlots = QtCore.pyqtSignal()
|
|
allEvidence = QtCore.pyqtSignal(list)
|
|
rainbowColor = QtCore.pyqtSignal(str)
|
|
updatePlayerList = QtCore.pyqtSignal(str, int, int, str)
|
|
timerUpdate = QtCore.pyqtSignal(int, int, int)
|
|
|
|
def __init__(self, parent):
|
|
super(DemoPlayer, self).__init__(parent)
|
|
self.parent = parent
|
|
self.paused = False
|
|
self.demo = []
|
|
self.demo_length = len(self.demo)
|
|
self.time = 0
|
|
self.demo_length_ms = 0
|
|
self.wait_timer = QtCore.QTimer(self)
|
|
self.wait_timer.setSingleShot(True)
|
|
self.wait_timer.timeout.connect(self.timer_done)
|
|
|
|
self.mc = [] # Music changes
|
|
self.bn = [] # Background changes
|
|
self.last_music = ""
|
|
self.last_bg = ""
|
|
|
|
def start(self, file):
|
|
self.paused = True
|
|
self.wait_timer.stop()
|
|
|
|
self.time = 0
|
|
self.demo_length_ms = 0
|
|
self.demo = []
|
|
self.mc = []
|
|
self.bn = []
|
|
self.last_music = ""
|
|
self.last_bg = ""
|
|
self.load_demo(file)
|
|
print "[client] Started demo playback (%s commands)" % self.demo_length
|
|
|
|
self.parent.demoslider.setMaximum(self.demo_length - 1)
|
|
self.OOC_Log.emit("<b>Demo playback started.</b>")
|
|
|
|
secs = self.demo_length_ms / 1000
|
|
mins = secs / 60
|
|
hours = mins / 60
|
|
self.OOC_Log.emit("Approximate duration: %02d:%02d:%02d." % (hours, mins % 60, secs % 60))
|
|
|
|
self.OOC_Log.emit("")
|
|
self.step()
|
|
|
|
def playpause(self):
|
|
self.paused = not self.paused
|
|
if not self.paused and self.time < self.demo_length:
|
|
self.step()
|
|
|
|
def step(self, skip_wait=False):
|
|
if self.time >= self.demo_length:
|
|
self.time = 0
|
|
return
|
|
|
|
packet = self.demo[self.time]
|
|
self.parent.demoslider.blockSignals(True)
|
|
self.parent.demoslider.setValue(self.time)
|
|
self.parent.demoslider.blockSignals(False)
|
|
self.time += 1
|
|
self.paused = False
|
|
|
|
if packet[0] == "wait":
|
|
if skip_wait:
|
|
self.time += 1
|
|
else:
|
|
self.wait_timer.start(int(packet[1]))
|
|
return
|
|
|
|
packets.handle_packets(self, [packet], False)
|
|
if self.time < self.demo_length:
|
|
self.wait_timer.start(1)
|
|
else:
|
|
self.OOC_Log.emit("<b>Demo playback finished.</b>")
|
|
|
|
def seek(self, time):
|
|
self.parent.inbox_timer.stop()
|
|
self.parent.inboxqueue = []
|
|
self.wait_timer.stop()
|
|
self.time = time
|
|
|
|
mc_times = [t[0] for t in self.mc]
|
|
t = bisect_left(mc_times, self.time) - 1
|
|
if t >= 0:
|
|
music = self.mc[t][1][1]
|
|
if music != self.last_music:
|
|
packets.handle_packets(self, [self.mc[t][1]], False)
|
|
self.last_music = music
|
|
|
|
bn_times = [t[0] for t in self.bn]
|
|
t = bisect_left(bn_times, self.time) - 1
|
|
if t >= 0:
|
|
bg = self.bn[t][1][1]
|
|
if bg != self.last_bg:
|
|
packets.handle_packets(self, [self.bn[t][1]], False)
|
|
self.last_bg = bg
|
|
|
|
self.step()
|
|
|
|
def load_demo(self, file):
|
|
last_line = ""
|
|
time = 0
|
|
with open(file) as f:
|
|
for line in f:
|
|
last_line = last_line + line
|
|
if last_line.strip()[-1] == "%":
|
|
packet = last_line.split("#")[:-1]
|
|
self.demo.append(packet)
|
|
if packet[0] == "MC":
|
|
self.mc.append((time, packet))
|
|
elif packet[0] == "BN":
|
|
self.bn.append((time, packet))
|
|
elif packet[0] == "wait":
|
|
self.demo_length_ms += int(packet[1])
|
|
last_line = ""
|
|
time += 1
|
|
self.demo_length = len(self.demo)
|
|
|
|
def timer_done(self):
|
|
if self.paused:
|
|
return
|
|
self.step()
|
|
|
|
def stop(self):
|
|
self.paused = True
|
|
self.wait_timer.stop()
|
|
|
|
class DemoRecorder():
|
|
def __init__(self):
|
|
self.demofile = None
|
|
self.lasttime = 0
|
|
|
|
def start(self):
|
|
if not os.path.exists("logs"):
|
|
os.mkdir("logs")
|
|
|
|
currtime = time.localtime()
|
|
self.lasttime = time.time() * 1000
|
|
self.demofile = "logs/%d-%02d-%02d %02d.%02d.%02d.demo" % (currtime[0], currtime[1], currtime[2], currtime[3], currtime[4], currtime[5])
|
|
|
|
def record(self, packet, encode=False):
|
|
if packet[0][0] in ["FM", "ARUP", "CharsCheck"]:
|
|
return
|
|
|
|
#print packet[0][0]
|
|
with open(self.demofile, "a") as demofile:
|
|
currtime = time.time() * 1000
|
|
diff = currtime - self.lasttime
|
|
self.lasttime = currtime
|
|
demofile.write(("wait#%d#%%" % diff) + "\n")
|
|
|
|
line = "#".join(packet[0]) + "#%\n"
|
|
if encode:
|
|
line = line.encode('utf-8')
|
|
demofile.write(line)
|
|
|
|
class DemoPicker(QtGui.QDialog):
|
|
def __init__(self, parent):
|
|
super(DemoPicker, self).__init__()
|
|
self.setModal(True)
|
|
self.gamewindow = parent
|
|
self.parent = parent
|
|
|
|
self.setWindowTitle("Select a demo file...")
|
|
self.setFixedSize(480, 512)
|
|
self.setWindowIcon(QtGui.QIcon("AO2XP.ico"))
|
|
self.setWindowFlags(QtCore.Qt.WindowCloseButtonHint)
|
|
self.hide()
|
|
|
|
self.treeview = get_demo_treeview()
|
|
self.treeview.doubleClicked.connect(self.on_demo_click)
|
|
|
|
self.cancelbtn = QtGui.QPushButton()
|
|
self.cancelbtn.setText("Cancel")
|
|
self.cancelbtn.clicked.connect(self.hide)
|
|
|
|
main_layout = QtGui.QVBoxLayout(self)
|
|
btns_layout = QtGui.QHBoxLayout()
|
|
|
|
btns_layout.addWidget(self.cancelbtn, 0, QtCore.Qt.AlignRight)
|
|
|
|
main_layout.addWidget(self.treeview)
|
|
main_layout.addLayout(btns_layout)
|
|
|
|
self.cancelbtn.setFocus()
|
|
|
|
def on_demo_click(self, item):
|
|
fname = get_demo_fname(self.treeview, item)
|
|
|
|
if not fname:
|
|
return
|
|
|
|
self.gamewindow.gamewidget.start_demo(fname)
|
|
self.gamewindow.stackwidget.setCurrentWidget(self.gamewindow.gamewidget)
|
|
self.hide()
|
|
|
|
def get_demo_treeview():
|
|
demo_model = QtGui.QFileSystemModel();
|
|
demo_model.setRootPath("logs");
|
|
demo_model.setFilter(QtCore.QDir.Files | QtCore.QDir.AllDirs | QtCore.QDir.NoDotAndDotDot)
|
|
demo_model.setNameFilters(QtCore.QStringList("*.demo"))
|
|
demo_model.setNameFilterDisables(False)
|
|
demo_treeview = QtGui.QTreeView()
|
|
demo_treeview.setHeaderHidden(True)
|
|
demo_treeview.setModel(demo_model);
|
|
demo_treeview.setRootIndex(demo_model.index("logs"));
|
|
for i in range(1, demo_model.columnCount()):
|
|
demo_treeview.hideColumn(i)
|
|
|
|
return demo_treeview
|
|
|
|
def get_demo_fname(treeview, item):
|
|
model = treeview.model()
|
|
if model.isDir(item):
|
|
return None
|
|
|
|
path = QtCore.QStringList()
|
|
|
|
while item.isValid():
|
|
fname = model.fileName(item)
|
|
if fname == "logs":
|
|
path.insert(0, "logs")
|
|
break
|
|
path.insert(0, fname)
|
|
item = item.parent()
|
|
|
|
return path.join("/") |