Skip to content

Commit 67151d0

Browse files
committed
feat:存dat文件
1 parent 5ba54f9 commit 67151d0

3 files changed

Lines changed: 235 additions & 65 deletions

File tree

src/mineSweeperGUI.py

Lines changed: 32 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@
33
from PyQt5.QtCore import QTimer, QCoreApplication, Qt, QRect, QUrl
44
from PyQt5.QtGui import QPixmap, QDesktopServices
55
import msgspec
6+
from textdistance import length
67
# from PyQt5.QtWidgets import QLineEdit, QInputDialog, QShortcut
78
# from PyQt5.QtWidgets import QApplication, QFileDialog, QWidget
89
import gameDefinedParameter
910
from plugin_sdk.server_bridge import GameServerBridge
10-
from shared_types.events import GameEndEvent, BoardUpdateEvent, GameStatusChangeEvent
11+
from shared_types.events import GameFinishedEvent, BoardUpdateEvent, GameStatusChangeEvent
1112
import superGUI
1213
import gameAbout
1314
import gameSettings
@@ -29,7 +30,7 @@
2930
import hashlib
3031
import uuid
3132
from Crypto.Cipher import AES
32-
from Crypto.Util.Padding import pad, unpad
33+
from Crypto.Random import get_random_bytes
3334
# from PyQt5.QtWidgets import QApplication
3435
from country_name import country_name
3536
import metaminesweeper_checksum
@@ -222,11 +223,13 @@ def game_state(self):
222223
@game_state.setter
223224
def game_state(self, game_state: str):
224225
# print(self._game_state, " -> " ,game_state)
226+
if game_state == self._game_state:
227+
return
225228
last_state = self._game_state
226229

227-
match self._game_state:
230+
match last_state:
228231
case "playing":
229-
self.onGameEnd(game_state)
232+
self.onGameFinished(game_state)
230233
if game_state not in ("playing", "show", "joking"):
231234
self.timer_10ms.stop()
232235
self.unlimit_cursor()
@@ -274,12 +277,11 @@ def game_state(self, game_state: str):
274277
"display": 7,
275278
"showdisplay": 8,
276279
}
277-
if last_state != game_state:
278-
event = GameStatusChangeEvent(
279-
last_status=state_map.get(last_state, 0),
280-
current_status=state_map.get(game_state, 0),
281-
)
282-
GameServerBridge.instance().send_event(event)
280+
event = GameStatusChangeEvent(
281+
last_status=state_map.get(last_state, 0),
282+
current_status=state_map.get(game_state, 0),
283+
)
284+
GameServerBridge.instance().send_event(event)
283285
self._send_board_update_event()
284286

285287

@@ -319,12 +321,14 @@ def minenum(self, minenum):
319321

320322
# 生命周期函数,正式的游戏结束时调用。由游戏状态的变更触发,当且仅当由playing变为其他状态
321323
# 处理数据相关。不处理前端显示
322-
def onGameEnd(self, new_game_state):
324+
def onGameFinished(self, new_game_state):
323325
# 不论如何都必然生成数据
326+
if self.label.ms_board.game_board_state == utils.GameBoardState.Playing.value:
327+
self.label.ms_board.step_game_state("replay")
324328
self.dump_evf_file_data()
325329
# 发信号给插件,游戏结束了
326330
board = self.label.ms_board.board
327-
event = GameEndEvent(
331+
event = GameFinishedEvent(
328332
game_state = ['ready', 'study', 'show', 'playing', 'joking', 'fail',
329333
'win', 'jofail', 'jowin', 'display', 'showdisplay'].index(new_game_state),
330334
nf = self.label.ms_board.rce == 0,
@@ -362,22 +366,17 @@ def onGameEnd(self, new_game_state):
362366
board = board if isinstance(board, list) else board.into_vec_vec(),
363367
raw_data = self.label.ms_board.raw_data
364368
)
365-
GameServerBridge.instance().send_event(event)
366369

367370
# 强制保存stats.dat文件
368371
record = utils.StatsRecord(
369372
game_state=event.game_state,
370-
nf=event.nf,
371373
row=event.row,
372374
column=event.column,
373375
mine_num=event.mine_num,
374-
rtime=event.rtime,
376+
rtime_ms=self.label.ms_board.rtime_ms,
375377
left=event.left,
376378
right=event.right,
377379
double=event.double,
378-
level=event.level,
379-
cl=event.cl,
380-
ce=event.ce,
381380
rce=event.rce,
382381
lce=event.lce,
383382
dce=event.dce,
@@ -387,33 +386,30 @@ def onGameEnd(self, new_game_state):
387386
flag=event.flag,
388387
path=event.path,
389388
start_time=event.start_time,
390-
end_time=event.end_time,
391389
mode=event.mode,
392-
software=event.software,
393-
player_identifier=event.player_identifier,
394-
race_identifier=event.race_identifier,
395-
uniqueness_identifier=event.uniqueness_identifier,
396390
is_official=event.is_official,
397391
is_fair=event.is_fair,
398392
op=event.op,
399393
isl=event.isl,
400394
pluck=event.pluck,
401-
board=event.board
395+
board_bytes=utils.board_list_to_bytes(event.board),
396+
short_md5 = hashlib.md5(self.label.ms_board.raw_data).digest()[:8]
402397
)
403-
binary_data = msgspec.msgpack.encode(record)
404-
# 简单的AES加密
398+
GameServerBridge.instance().send_event(event)
399+
binary_data = record.encode()
400+
# 简单的AES-CTR加密(将nonce与密文一起写入以便解密)
405401
key = bytes([2,135,180,102,125,204,245,102,253,59,217,7,114,61,231,62]) # 16字节的密钥
406-
cipher = AES.new(key, AES.MODE_ECB)
407-
padded_data = pad(binary_data, AES.block_size)
408-
encrypted_data = cipher.encrypt(padded_data)
402+
nonce = get_random_bytes(8)
403+
cipher = AES.new(key, AES.MODE_CTR, nonce=nonce)
404+
encrypted_data = cipher.encrypt(binary_data)
409405
dat_file_path = self.setting_path / 'stats.dat'
410-
# 把二进制加密数据 编码成 base64 字符串(bytes)
411-
b64_data = base64.b64encode(encrypted_data)
412-
is_empty = not os.path.exists(dat_file_path) or os.path.getsize(dat_file_path) == 0
406+
# 将 nonce(8字节) + ciphertext 一并写入文件,前两字节为总长度
413407
with open(dat_file_path, 'ab') as f:
414-
if not is_empty:
415-
f.write(b"\n")
416-
f.write(b64_data)
408+
blob = nonce + encrypted_data
409+
encrypted_data_length = len(blob)
410+
len_bytes = encrypted_data_length.to_bytes(2, byteorder="big", signed=False)
411+
f.write(len_bytes)
412+
f.write(blob)
417413

418414

419415
# 根据策略保存录像文件到磁盘
@@ -718,7 +714,7 @@ def gameRestart(self, e=None): # 画界面,但是不埋雷,改数据而不
718714
# self.label.paint_cursor = False
719715
# self.label.setMouseTracking(False) # 鼠标未按下时,组织移动事件回调
720716

721-
# 游戏结束画残局,改状态
717+
# 游戏结束画残局,改状态。前端的游戏结束逻辑
722718
def gameFinished(self):
723719
if self.label.ms_board.game_board_state == 3 and self.end_then_flag:
724720
self.label.ms_board.win_then_flag_all_mine()

src/shared_types/events.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ class ButtonClickEvent(BaseEvent, tag="button_click"):
5858
button = 0
5959

6060

61-
class GameEndEvent(BaseEvent, tag="game_end"):
61+
class GameFinishedEvent(BaseEvent, tag="game_end"):
6262
"""
6363
游戏结束事件。发生在游戏胜利、失败、重开、游戏关闭、游戏设置关闭、切换游戏状态关闭、
6464
游戏状态变为非正式等情况。
@@ -112,5 +112,5 @@ class GameEndEvent(BaseEvent, tag="game_end"):
112112
BoardUpdateEvent,
113113
GameStatusChangeEvent,
114114
ButtonClickEvent,
115-
GameEndEvent,
115+
GameFinishedEvent,
116116
]

0 commit comments

Comments
 (0)