forked from moeheart/jx3bla
-
Notifications
You must be signed in to change notification settings - Fork 0
/
LiveBase.py
1142 lines (965 loc) · 41.4 KB
/
LiveBase.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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# Created by moeheart at 10/10/2020
# 实时模式的基础方法库。
import threading
import os
import time
import traceback
import hashlib
import urllib.request
import requests
import json
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
from tools.Functions import *
import pyperclip
from data.DataController import DataController
from replayer.ActorReplayPro import ActorProReplayer
from replayer.boss.General import GeneralWindow
from replayer.boss.HuTangLuoFen import HuTangLuoFenWindow
from replayer.boss.ZhaoBasao import ZhaoBasaoWindow
from replayer.boss.HaiTu import HaiTuWindow
from replayer.boss.JiangJiku import JiangJikuWindow
from replayer.boss.YuwenMie import YuwenMieWindow
from replayer.boss.GongWei import GongWeiWindow
from replayer.boss.GongAo import GongAoWindow
from replayer.boss.JuxingJianwenfeng import JuxingJianwenfengWindow
from replayer.boss.SangQiao import SangQiaoWindow
from replayer.boss.XidaLuomo import XidaLuomoWindow
from replayer.boss.YoujiaLuomo import YoujiaLuomoWindow
from replayer.boss.YuequanHuai import YuequanHuaiWindow
from replayer.boss.WuMenggui import WuMengguiWindow
class ToolTip(object):
'''
浮动标签类,用于实现简单的浮动标签。
'''
def build(self, widget):
self.widget = widget
self.tipwindow = None
self.id = None
self.x = self.y = 0
def showtip(self, text):
"Display text in tooltip window"
self.text = text
if self.tipwindow or not self.text:
return
x, y, _cx, cy = self.widget.bbox("insert")
x = x + self.widget.winfo_rootx() + 27
y = y + cy + self.widget.winfo_rooty() +27
self.tipwindow = tw = tk.Toplevel(self.widget)
tw.wm_overrideredirect(1)
tw.wm_geometry("+%d+%d" % (x, y))
tf = tk.Frame(tw, relief=tk.SOLID, borderwidth=1, bg="#ffffe0")
tf.pack(ipadx=1)
textList = text.split('\n')
for line in textList:
if line == "":
fg = "#000000"
if line[0] == "-":
fg = "#ff0000"
elif line[0] == "+":
fg = "#007700"
else:
fg = "#000000"
label = tk.Label(tf, text=line, fg=fg, justify=tk.LEFT,
background="#ffffe0", anchor='nw',
font=("Aaril", "10", "normal"))
label.pack(anchor=tk.NW)
def hidetip(self):
tw = self.tipwindow
self.tipwindow = None
if tw:
tw.destroy()
def createToolTip(self, widget, text):
toolTip = self.build(widget)
def enter(event):
self.showtip(text)
def leave(event):
self.hidetip()
self.widget = widget
widget.bind('<Enter>', enter)
widget.bind('<Leave>', leave)
def remove(self):
self.widget.unbind('<Enter>')
self.widget.unbind('<Leave>')
def __init__(self, widget, text):
self.createToolTip(widget, text)
class CommentWindow():
'''
评论窗口类。用于维护评论窗口的逻辑。
'''
def final(self):
'''
关闭窗口。
'''
self.windowAlive = False
self.window.destroy()
def submit(self):
'''
尝试提交评论。
'''
result = {}
result["type"] = int(self.var1.get())
result["power"] = int(self.var2.get())
result["content"] = self.commentEntry.get()
result["pot"] = self.potDescription
result["server"] = self.server
result["userid"] = self.userid
result["mapdetail"] = self.mapDetail
result["time"] = self.beginTime
result["player"] = self.targetID
hashStr = result["server"] + result["player"] + result["userid"] + result["mapdetail"] + str(result["time"])
hashres = hashlib.md5(hashStr.encode(encoding="utf-8")).hexdigest()
result["hash"] = hashres
if result["type"] == 0 or result["power"] == 0:
messagebox.showinfo(title='错误', message='提交失败,请检查类型与能量是否正确。')
return
Jdata = json.dumps(result)
jpost = {'jdata': Jdata}
jparse = urllib.parse.urlencode(jpost).encode('utf-8')
resp = urllib.request.urlopen('http://139.199.102.41:8009/uploadComment', data=jparse)
res = json.load(resp)
if res['result'] == 'success':
messagebox.showinfo(title='成功', message='评价成功!')
self.final()
elif res['result'] == 'lack':
messagebox.showinfo(title='失败', message='评价失败,你的积分与能量卡不足以进行此次评价,请尝试使用更低的能量等级。')
elif res['result'] == 'duplicate':
messagebox.showinfo(title='失败', message='评价失败,你对该玩家提交过相同的评价。')
elif res['result'] == 'denied':
messagebox.showinfo(title='失败', message='评价失败,你的等级无法以使用此功能。')
def start(self):
self.windowAlive = True
self.windowThread = threading.Thread(target=self.loadWindow)
self.windowThread.start()
def loadWindow(self):
'''
使用tkinter绘制复盘窗口。
'''
window = tk.Toplevel()
window.title('评价')
window.geometry('500x400')
targetID = self.targetID
targetColor = getColor(self.targetOcc)
IDlabel = tk.Label(window, text=targetID, height=1, fg=targetColor)
IDlabel.grid(row=0, column=0)
self.var1 = tk.IntVar()
label1 = tk.Label(window, text="评价类别", height=1)
label1.grid(row=1, column=0)
ToolTip(label1, "选取评价类别。点赞会增加目标的信誉分,而吐槽会扣除目标的信誉分。\n在同一场战斗数据中,只能对同一名玩家评价一次。")
frame1 = tk.Frame(window)
radio11 = tk.Radiobutton(frame1,text='点赞',variable=self.var1,value=1)
radio11.grid(row=0, column=0)
radio12 = tk.Radiobutton(frame1,text='吐槽',variable=self.var1,value=2)
radio12.grid(row=0, column=1)
frame1.grid(row=1, column=1)
self.var2 = tk.IntVar()
label2 = tk.Label(window, text="评价能量", height=1)
label2.grid(row=2, column=0)
frame2 = tk.Frame(window)
radio21 = tk.Radiobutton(frame2,text='低',variable=self.var2,value=1)
radio21.grid(row=0, column=1)
radio22 = tk.Radiobutton(frame2,text='中',variable=self.var2,value=2)
radio22.grid(row=0, column=2)
radio23 = tk.Radiobutton(frame2,text='高',variable=self.var2,value=3)
radio23.grid(row=0, column=3)
frame2.grid(row=2, column=1)
ToolTip(label2, "选取评价能量,会影响分数变化的多少。")
ToolTip(radio21, "使用低能量,分数变化为2,无消耗。")
ToolTip(radio22, "使用中能量,分数变化为8,消耗中级能量卡或8点积分。")
ToolTip(radio23, "使用高能量,分数变化为20,消耗高级能量卡或20点积分。")
potDesLabel = tk.Label(window, text="犯错记录")
potDesLabel.grid(row=3, column=0)
potLabel = tk.Label(window, text=self.potDescription)
potLabel.grid(row=3, column=1, ipadx=75)
commentDesLabel = tk.Label(window, text="评论内容")
commentDesLabel.grid(row=4, column=0)
self.commentEntry = tk.Entry(window, show=None, width=50)
self.commentEntry.grid(row=4, column=1, ipady=25)
submitButton = tk.Button(window, text='提交', command=self.submit)
submitButton.grid(row=5, column=1)
self.window = window
window.protocol('WM_DELETE_WINDOW', self.final)
def alive(self):
return self.windowAlive
def __init__(self, id, occ, pots, server, userid, mapDetail, beginTime):
self.windowAlive = False
self.targetID = id
self.targetOcc = occ
self.potDescription = pots
self.server = server
self.userid = userid
self.mapDetail = mapDetail
self.beginTime = beginTime
class PotExtendWindow():
'''
锅的扩展窗口类。用于维护添加锅的窗体。
'''
def final(self):
'''
收集分锅结果并关闭窗口。
'''
self.windowAlive = False
self.singleBossWindow.potExtendRunning = False
self.window.destroy()
def Act(self):
'''
实施加锅。
'''
playerID = self.playerValue.get()
potLevel = self.lvlValue.get()
potDescription = "[手动]" + self.descEntry.get()
try:
score = int(self.scoreEntry.get())
except:
score = 0
potLevelNum = 1
if potLevel == "轻微":
potLevelNum = 0
elif potLevel == "严重":
potLevelNum = 1
elif potLevel == "补贴":
potLevelNum = 3
if playerID in self.playerIDDict:
playerOcc = self.playerIDDict[playerID]
self.pot = [playerID, playerOcc, potLevelNum, self.bossName, potDescription, []]
self.singleBossWindow.AddPot(self.pot, score)
self.final()
def loadWindow(self):
'''
使用tkinter绘制复盘窗口。
'''
window = tk.Toplevel()
window.title('加锅')
window.geometry('300x120')
tk.Label(window, text="玩家ID", height=1).grid(row=0, column=0)
self.playerValue = tk.StringVar()
playerCombobox = ttk.Combobox(window, textvariable=self.playerValue)
playerCombobox["values"] = self.playerIDList
playerCombobox.current(0)
playerCombobox.grid(row=0, column=1)
tk.Label(window, text="分锅描述", height=1).grid(row=1, column=0)
self.descEntry = tk.Entry(window, show=None)
self.descEntry.grid(row=1, column=1)
tk.Label(window, text="分锅等级", height=1).grid(row=2, column=0)
self.lvlValue = tk.StringVar()
lvlCombobox = ttk.Combobox(window, textvariable=self.lvlValue)
lvlCombobox["values"] = ("严重", "轻微", "补贴")
lvlCombobox.current(0)
lvlCombobox.grid(row=2, column=1)
tk.Label(window, text="评分", height=1).grid(row=3, column=0)
self.scoreEntry = tk.Entry(window, show=None)
self.scoreEntry.grid(row=3, column=1)
tk.Button(window, text='加锅', width=10, height=1, command=self.Act).grid(row=4, column=0)
self.window = window
window.protocol('WM_DELETE_WINDOW', self.final)
def start(self):
self.windowAlive = True
self.windowThread = threading.Thread(target=self.loadWindow)
self.windowThread.start()
def alive(self):
return self.windowAlive
def __init__(self, singleBossWindow):
self.windowAlive = False
self.singleBossWindow = singleBossWindow
self.playerList = singleBossWindow.analyser.getPlayer()
self.playerIDDict = {}
self.playerIDList = []
for line in self.playerList:
self.playerIDDict[line[0]] = line[1]
self.playerIDList.append(line[0])
self.bossName = singleBossWindow.detail["boss"]
class SingleBossWindow():
'''
单个BOSS复盘结果类。维护复盘结果的窗体,与简单的信息收集逻辑。
'''
def getPotColor(self, level):
if level == 0:
return "#777777"
elif level == 1:
return "#000000"
else:
return "#0000ff"
def AddPot(self, pot, score):
'''
新增一条锅。暂时的处理方式为添加的锅不会在记录中显示,而是添加到记录中,刷新后才显示。
params
- pot 锅
'''
self.potList.append(pot)
self.scoreList.append(score)
def StartPotExtend(self):
'''
开启加锅界面。
'''
if self.potExtendRunning == False:
self.potExtendWindow = PotExtendWindow(self)
self.potExtendWindow.start()
self.potExtendRunning = True
def getPot(self, tmp, num):
'''
分锅结果变化的处理函数。
params
- tmp 记录编号
- num 锅数
'''
self.scoreList[tmp] += num
scoreStr = ""
scoreColor = "#000000"
if self.scoreList[tmp] > 0:
scoreStr = "+%d"%self.scoreList[tmp]
scoreColor = "#007700"
elif self.scoreList[tmp] < 0:
scoreStr = "%d"%self.scoreList[tmp]
scoreColor = "#ff0000"
self.scoreLabels[tmp].config(text=scoreStr, fg=scoreColor)
#self.analyser.potListScore[-self.numPot + tmp][-1] = self.scoreList[tmp]
self.analyser.setSinglePotScore(self.bossNum, tmp, self.scoreList[tmp])
self.analyser.getPlayerPotList()
text = self.analyser.getPlayerText(self.nameList[tmp])
self.toolTips[tmp].remove()
toopTip = ToolTip(self.toolTips[tmp].widget, text)
self.toolTips[tmp] = toopTip
def copyPot(self, tmp):
'''
点击复制按钮的处理函数。
params
- tmp 记录编号
'''
text = self.potList[tmp][4]
player = self.potList[tmp][0].strip('"')
copyText = "[%s]:%s"%(player, text)
pyperclip.copy(copyText)
messagebox.showinfo(title='提示', message='复制成功!')
def final(self):
'''
收集分锅结果并关闭窗口。
'''
# print("[Test]SingleBoss")
# print(self.potWindowActivated)
# print(self.potList)
# print(self.scoreList)
if self.potExtendRunning:
self.potExtendWindow.final()
if self.potWindowActivated:
for i in range(len(self.potList)):
self.potList[i][6] = self.scoreList[i]
self.analyser.changeResult(self.potList, self.bossNum)
# print("[Test]After modified")
# print(self.potWindowActivated)
# print(self.potList)
# print(self.scoreList)
if self.windowAlive:
self.window.destroy()
self.windowAlive = False
def constructReplayByNum(self, num):
'''
根据序号来打开对应的BOSS复盘窗口,要求序号必须合法
params
- num 对应的序号,如果序号为-1,表示选择最后一个BOSS
'''
if num == -1:
num = self.analyser.getLastBossNum()
if num == "None":
return
self.bossNum = int(num)
self.addPotList(self.analyser.potContainer.getBoss(num))
a, b, c, d = self.analyser.potContainer.getDetail(num)
self.setDetail(a, b, c, d)
# self.start()
self.specificBossWindow.start()
def finalPrev(self):
'''
收集分锅结果并关闭窗口,尝试打开前一个BOSS的窗口。
'''
prevNum = self.bossNum - 1
if self.analyser.checkBossExists(prevNum):
self.final()
self.specificBossWindow.final()
self.potWindowActivated = False
self.constructReplayByNum(prevNum)
else:
messagebox.showinfo(title='嘶', message='前序BOSS未找到。')
def finalNext(self):
'''
收集分锅结果并关闭窗口,尝试打开后一个BOSS的窗口。
'''
nextNum = self.bossNum + 1
if self.analyser.checkBossExists(nextNum):
self.final()
self.specificBossWindow.final()
self.potWindowActivated = False
self.constructReplayByNum(nextNum)
else:
messagebox.showinfo(title='嘶', message='后继BOSS未找到。')
def setDetail(self, potList, effectiveDPSList, detail, occResult):
'''
初始化详细复盘的数据。
- params
potList 分锅记录。
effectiveDPSList DPS详细统计,包括每名玩家在特定算法下的DPS。
detail 详细复盘记录。
occResult 心法复盘记录。
'''
self.effectiveDPSList = effectiveDPSList
self.detail = detail
self.occResult = occResult
self.hasDetail = 1
if "boss" in detail:
if detail["boss"] == "胡汤&罗芬":
self.specificBossWindow = HuTangLuoFenWindow(self.mainWindow.config, effectiveDPSList, detail, occResult)
elif detail["boss"] == "赵八嫂":
self.specificBossWindow = ZhaoBasaoWindow(self.mainWindow.config, effectiveDPSList, detail, occResult)
elif detail["boss"] == "海荼":
self.specificBossWindow = HaiTuWindow(self.mainWindow.config, effectiveDPSList, detail, occResult)
elif detail["boss"] == "姜集苦":
self.specificBossWindow = JiangJikuWindow(self.mainWindow.config, effectiveDPSList, detail, occResult)
elif detail["boss"] == "宇文灭":
self.specificBossWindow = YuwenMieWindow(self.mainWindow.config, effectiveDPSList, detail, occResult)
elif detail["boss"] == "宫威":
self.specificBossWindow = GongWeiWindow(self.mainWindow.config, effectiveDPSList, detail, occResult)
elif detail["boss"] == "宫傲":
self.specificBossWindow = GongAoWindow(self.mainWindow.config, effectiveDPSList, detail, occResult)
elif detail["boss"] == "巨型尖吻凤":
self.specificBossWindow = JuxingJianwenfengWindow(self.mainWindow.config, effectiveDPSList, detail, occResult)
elif detail["boss"] == "桑乔":
self.specificBossWindow = SangQiaoWindow(self.mainWindow.config, effectiveDPSList, detail, occResult)
elif detail["boss"] == "悉达罗摩":
self.specificBossWindow = XidaLuomoWindow(self.mainWindow.config, effectiveDPSList, detail, occResult)
elif detail["boss"] == "尤珈罗摩":
self.specificBossWindow = YoujiaLuomoWindow(self.mainWindow.config, effectiveDPSList, detail, occResult)
elif detail["boss"] == "月泉淮":
self.specificBossWindow = YuequanHuaiWindow(self.mainWindow.config, effectiveDPSList, detail, occResult)
elif detail["boss"] == "乌蒙贵":
self.specificBossWindow = WuMengguiWindow(self.mainWindow.config, effectiveDPSList, detail, occResult)
else:
self.specificBossWindow = GeneralWindow(self.mainWindow.config, effectiveDPSList, detail, occResult)
self.specificBossWindow.setPotWindow(self)
# def showDetail(self):
# '''
# 显示战斗统计详情。
# '''
# if self.hasDetail:
# self.specificBossWindow.start()
# else:
# messagebox.showinfo(title='嘶', message='制作中,敬请期待!')
def loadWindow(self):
'''
使用tkinter绘制复盘窗口。
'''
window = tk.Toplevel()
#window = tk.Tk()
window.title('战斗复盘')
window.geometry('650x700')
numPot = len(self.potList)
self.numPot = numPot
self.potWindowActivated = True
canvas=tk.Canvas(window,width=600,height=500,scrollregion=(0,0,580,numPot*30)) #创建canvas
canvas.place(x=25, y=25) #放置canvas的位置
frame=tk.Frame(canvas) #把frame放在canvas里
frame.place(width=580, height=500) #frame的长宽,和canvas差不多的
vbar=tk.Scrollbar(canvas,orient=tk.VERTICAL) #竖直滚动条
vbar.place(x = 580,width=20,height=500)
vbar.configure(command=canvas.yview)
canvas.config(yscrollcommand=vbar.set) #设置
canvas.create_window((265,numPot*15), window=frame) #create_window
self.scoreLabels = []
self.scoreList = []
self.toolTips = []
self.nameList = []
for i in range(len(self.potList)):
assert len(self.potList[i]) == 7
self.scoreList.append(self.potList[i][6])
if not self.analyser.checkBossExists(self.bossNum):
self.analyser.addResult(self.potList, self.bossNum, self.effectiveDPSList, self.detail, self.occResult)
self.analyser.getPlayerPotList()
for i in range(numPot):
line = self.potList[i]
name = line[0].strip('"')
occ = line[1]
color = getColor(occ)
nameLabel = tk.Label(frame, text=name, width = 13, height=1, fg=color)
nameLabel.grid(row=i, column=0)
pot = line[4]
color = self.getPotColor(line[2])
potLabel = tk.Label(frame, text=pot, height=1, fg=color)
potLabel.grid(row=i, column=1)
if len(line) > 5:
potDetail = '\n'.join(line[5])
if potDetail != "":
ToolTip(potLabel, potDetail)
scoreLabel = tk.Label(frame, text="", width=5, height=1, font=("Arial", 12, "bold"))
scoreLabel.grid(row=i, column=2)
self.scoreLabels.append(scoreLabel)
tmp = i
button1 = tk.Button(frame, text='接锅', width=6, height=1, command=lambda tmp=tmp: self.getPot(tmp, -1), bg='#ffcccc')
button1.grid(row=i, column=3)
button2 = tk.Button(frame, text='领赏', width=6, height=1, command=lambda tmp=tmp: self.getPot(tmp, 1), bg='#ccffcc')
button2.grid(row=i, column=4)
button3 = tk.Button(frame, text='复制', width=6, height=1, command=lambda tmp=tmp: self.copyPot(tmp), bg='#ccccff')
button3.grid(row=i, column=5)
text = self.analyser.getPlayerText(name)
toolTip = ToolTip(nameLabel, text)
self.toolTips.append(toolTip)
self.nameList.append(name)
for i in range(len(self.potList)):
self.getPot(i, 0)
buttonFinal = tk.Button(window, text='分锅完成', width=10, height=1, command=self.final)
buttonFinal.place(x=250, y=540)
# buttonPrev = tk.Button(window, text='<<', width=2, height=1, command=self.finalPrev)
# buttonPrev.place(x = 220, y = 540)
#
# buttonNext = tk.Button(window, text='>>', width=2, height=1, command=self.finalNext)
# buttonNext.place(x = 340, y = 540)
buttonDetail = tk.Button(window, text='手动设置', width=10, height=1, command=self.StartPotExtend)
buttonDetail.place(x=200, y=580)
# buttonDetail = tk.Button(window, text='数据统计', width=10, height=1, command=self.showDetail)
# buttonDetail.place(x = 300, y = 570)
self.window = window
window.protocol('WM_DELETE_WINDOW', self.final)
#window.mainloop()
def openDetailWindow(self):
'''
开启详细复盘界面。这是由于在7.0版本更新后,先显示复盘界面,再显示分锅界面。
'''
self.potWindowActivated = False
self.specificBossWindow.start()
def start(self):
self.windowAlive = True
self.windowThread = threading.Thread(target=self.loadWindow)
self.windowThread.start()
def addPotList(self, potList):
self.potList = potList
def alive(self):
return self.windowAlive
def __init__(self, analyser, bossNum, mainWindow):
self.analyser = analyser
self.bossNum = bossNum
self.mainWindow = mainWindow
self.effectiveDPSList = []
self.detail = {}
self.windowAlive = False
self.potExtendRunning = False
self.potWindowActivated = False
class PotContainer():
'''
锅的记录类。
'''
def getAll(self):
'''
返回所有的锅。
return
- 分锅与打分的列表,list格式
'''
result = []
for line in self.pot:
result.extend(self.pot[line])
return result
def getPlayerOcc(self):
'''
获取记录中的角色与门派。用effectiveDpsList作为信息来源。
return
- list格式的角色与门派组合。
'''
playerOcc = {}
playerOccNum = {}
for key in self.effectiveDPSList:
dpsList = self.effectiveDPSList[key]
for line in dpsList:
if line[0] not in playerOcc:
playerOcc[line[0]] = line[1]
occ = line[1]
if occ[-1] in ['d', 't', 'h', 'p', 'm']:
occ = occ[:-1]
playerOccNum[line[0]] = int(occ)
playerList = []
for line in playerOccNum:
playerList.append([line.strip('"'), playerOccNum[line], playerOcc[line]])
playerList.sort(key = lambda x:x[1])
playerListSort = []
for line in playerList:
playerListSort.append([line[0], line[2]])
return playerListSort
def getDetail(self, bossid):
'''
返回对应boss的详细记录。
return
- 分锅与打分的列表,list格式
- 战斗复盘中的DPS列表
- 战斗复盘中的特定BOSS细节
'''
bossidStr = str(bossid)
return self.pot[bossidStr], self.effectiveDPSList[bossidStr], self.detail[bossidStr], self.occResult[bossidStr]
def getBoss(self, bossid):
'''
返回对应boss的锅。
return
- 分锅与打分的列表,list格式
'''
bossidStr = str(bossid)
return self.pot[bossidStr]
def getBossName(self, bossid):
'''
查找对应boss的名称。
return
- 字符串格式的BOSS名。
'''
bossidStr = str(bossid)
return self.detail[bossidStr]["boss"]
def addBoss(self, bossid, potListScore, effectiveDPSList=[], detail={}, occResult={}, change=1):
'''
当一个BOSS结束时,把分锅记录加入总记录中。
或是当修改锅时,按对应的bossid取代原有的分锅记录。
params
- bossid 按时间顺序的BOSS编号。
- potListScore 分锅与打分的列表,list格式
- effectiveDPSList 战斗复盘中的DPS列表
- detail 战斗复盘中的特定BOSS细节
'''
bossidStr = str(bossid)
self.pot[bossidStr] = potListScore
if change:
self.effectiveDPSList[bossidStr] = effectiveDPSList
self.detail[bossidStr] = detail
self.occResult[bossidStr] = occResult
def __init__(self):
self.pot = {}
self.effectiveDPSList = {}
self.detail = {}
self.occResult = {}
class LiveActorAnalysis():
'''
实时演员信息类。维护当前结果信息的存储与获取。
'''
def getBossName(self):
'''
从结果记录中提取所有BOSS的名称,记录为字典形式。
return
- bossDict key为数字,value为boss名称。
'''
bossDict = {}
lastNum = int(list(self.potContainer.pot.keys())[-1])
for i in range(1, lastNum + 1):
bossDict[str(i)] = self.potContainer.getBossName(i)
return bossDict
def getPlayer(self):
'''
从结果记录中提取所有ID与门派,按门派顺序排序
return
- playerListSort 排好序的ID与门派列表
'''
return self.potContainer.getPlayerOcc()
def getPlayerPotList(self):
playerPot = {}
self.potListScore = self.potContainer.getAll()
for line in self.potListScore:
name = line[0].strip('"')
if name not in playerPot:
playerPot[name] = {"occ": line[1], "numPositive": 0, "numNegative": 0, "pot": []}
playerPot[name]["pot"].append(line[1:])
if line[-1] > 0:
playerPot[name]["numPositive"] += line[-1]
elif line[-1] < 0:
playerPot[name]["numNegative"] += line[-1]
self.playerPotList = playerPot
return playerPot
def getPlayerText(self, player):
first = 1
s = ""
if player in self.playerPotList:
for line in self.playerPotList[player]["pot"]:
if first:
first = 0
else:
s += '\n'
s += "%s %s %s"%(line[2], line[3], str(line[-1]))
return s
def setSinglePotScore(self, bossNum, pos, pot):
'''
设定单个分锅记录的锅数。
params
- bossNum BOSS编号
- tmp 记录的位置
- pot 修改后的锅数
'''
bossidStr = str(bossNum)
self.potContainer.pot[bossidStr][pos][-1] = pot
def setServer(self, server):
self.server = server
def getServer(self):
return self.server
def setMapDetail(self, mapDetail):
self.mapDetail = mapDetail
def getMapDetail(self):
return self.mapDetail
def setBeginTime(self, beginTime):
self.beginTime = beginTime
def getBeginTime(self):
return self.beginTime
def changeResult(self, potListScore, bossNum):
self.potContainer.addBoss(bossNum, potListScore, change=0)
def addResult(self, potListScore, bossNum, effectiveDPSList, detail, occResult):
#self.potListScore.extend(potListScore)
self.potContainer.addBoss(bossNum, potListScore, effectiveDPSList, detail, occResult)
def checkBossExists(self, bossNum):
bossNumStr = str(bossNum)
return bossNumStr in self.potContainer.pot
def getLastBossNum(self):
return list(self.potContainer.pot.keys())[-1]
def checkEmpty(self):
return list(self.potContainer.pot.keys()) == []
def __init__(self):
#self.potListScore = []
self.potContainer = PotContainer()
self.server = "未知"
class LiveListener():
'''
复盘监听类,在实时模式中控制开始复盘的时机。
'''
def getOneBattleLog(self, basepath, fileName):
'''
在对一条战斗记录进行复盘。
params
- basepath 监控的路径
- lastFile 复盘数据对应的文件名
- raw raw文件。如果是实时模式则为空,现场读取;否则从之前的记录中继承。
return
- liveGenerator 实时复盘对象,用于后续处理流程。
'''
controller = DataController(self.config)
if self.mainWindow.bldDict != {}:
controller.setRawData(self.mainWindow.bldDict)
controller.getSingleData(self.mainWindow, fileName) # 此处将MainWindow类本身传入
try:
fileNameInfo = [fileName, 0, 1]
# print(self.mainWindow.bldDict)
# print(fileNameInfo)
# print(basepath)
actorRep = ActorProReplayer(self.config, fileNameInfo, basepath, self.mainWindow.bldDict, self.mainWindow)
analysisExitCode = actorRep.FirstStageAnalysis()
if analysisExitCode == 1:
messagebox.showinfo(title='提示', message='数据格式错误,请再次检查设置。如不能解决问题,尝试重启程序。\n在此状态下,大部分功能将不能正常使用。')
raise Exception("数据格式错误,请再次检查设置。如不能解决问题,尝试重启程序。")
actorRep.SecondStageAnalysis()
if not actorRep.available:
# 分片,记录
self.mainWindow.lastBld = actorRep.bld
return actorRep
actorRep.ThirdStageAnalysis()
self.analyser.setServer(actorRep.bld.info.server)
self.analyser.setMapDetail(actorRep.bld.info.map)
self.analyser.setBeginTime(actorRep.bld.info.battleTime)
if actorRep.upload:
actorRep.prepareUpload()
# if liveGenerator.win: # TODO 移除失败的复盘
# self.mainwindow.addRawData(fileName, liveGenerator.getRawData())
# else:
# DestroyRaw(liveGenerator.getRawData())
except Exception as e:
traceback.print_exc()
self.mainWindow.setNotice({"t1": "[%s]分析失败!"%actorRep.bld.info.boss, "c1": "#000000", "t2": "请保留数据,并反馈给作者~", "c2": "#ff0000"})
return actorRep
self.bossNum += 1
self.mainWindow.setTianwangInfo(actorRep.ids, actorRep.server)
return actorRep
def getAllBattleLog(self, basepath, fileList):
'''
复盘模式中对所有战斗记录进行复盘。
params
- basepath 监控的路径
- fileList 需要复盘的文件名列表.
'''
for file in fileList:
actorRep = self.getOneBattleLog(basepath, file)
if not actorRep.available:
continue
#print("[Detail]", actorRep.detail)
potListScore = []
for i in range(len(actorRep.potList)):
if len(actorRep.potList[i]) <= 6:
potListScore.append(actorRep.potList[i] + [0])
else:
potListScore.append(actorRep.potList[i])
self.analyser.addResult(potListScore, self.bossNum, actorRep.effectiveDPSList, actorRep.detail, actorRep.occResult)
def getNewBattleLog(self, basepath, lastFile):
'''
实时模式中复盘战斗记录,并控制窗口弹出、数据记录。
params
- basepath: 监控的路径
- lastFile: 新增的文件,通常是刚刚完成的战斗复盘
'''
actorRep = self.getOneBattleLog(basepath, lastFile)
if not actorRep.available:
self.mainWindow.setNotice({"t1": "[%s]分析中断,等待完整记录..." % actorRep.bossname, "c1": "#000000"})
return
if self.window is not None and self.window.alive():
self.window.final()
if self.mainWindow is not None:
self.mainWindow.setNotice({"t1": "[%s]分析完成!"%actorRep.bossname, "c1": "#000000"})
window = SingleBossWindow(self.analyser, self.bossNum, self.mainWindow)
self.window = window
window.addPotList(actorRep.potList)
window.setDetail(actorRep.potList, actorRep.effectiveDPSList, actorRep.detail, actorRep.occResult)
window.openDetailWindow()
self.mainWindow.notifier.show("分锅结果已生成", "[%s]的战斗复盘已经解析完毕,请打开结果界面分锅。"%actorRep.bossname)
def listenPath(self, basepath):
'''
开始监控对应的路径。
params
- basepath: 监控的路径
'''
filelist = os.listdir(basepath)
if self.config.datatype == "jx3dat":
dataList = [x for x in filelist if x[-12:] == '.fstt.jx3dat']
else:
dataList = [x for x in filelist if x[-4:] == '.jcl']
if dataList != []:
newestFile = dataList[-1]
else:
newestFile = ""
while(self.listenFlag):
time.sleep(3)
filelist = os.listdir(basepath)
if self.config.datatype == "jx3dat":
dataList = [x for x in filelist if x[-12:] == '.fstt.jx3dat']
else:
dataList = [x for x in filelist if x[-4:] == '.jcl']
if dataList != []:
lastFile = dataList[-1]
else:
lastFile = ""
if lastFile != newestFile:
newestFile = lastFile
print("检测到新的复盘记录: %s"%lastFile)
time.sleep(0.5)
self.getNewBattleLog(basepath, lastFile)
def stopListen(self):
'''
中止监听。
'''
self.listenFlag = False
def startListen(self):
'''
产生监听线程,开始监控对应的路径。
'''
self.listenFlag = True
self.listenThread = threading.Thread(target = self.listenPath, args = (self.basepath,))
self.listenThread.setDaemon(True);
self.listenThread.start()
def __init__(self, basepath, config, analyser, mainWindow):
'''