From a972cc7ea6c2cd055a2c6a45df80fb79a52d4b00 Mon Sep 17 00:00:00 2001
From: hxp <ale99527@vip.qq.com>
Date: 星期二, 06 十二月 2022 18:31:52 +0800
Subject: [PATCH] 9651 【后端】玩家个人数据保存问题(地图玩家支持按每个玩家独立备档)

---
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ReadChConfig.py        |    7 ++-
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerBackup.py |   86 +++++++++++++++++++++++++++++++++++++++++++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IPY_GameObj.py         |    1 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerState.py  |    4 ++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py            |    1 
 5 files changed, 97 insertions(+), 2 deletions(-)

diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
index 43cafec..03d0af3 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
@@ -3409,6 +3409,7 @@
 
 # 玩家字典key定义规则, key的长度不能超过29个字节, 注意尽量避免命名重复
 # 新增参数TYPE 用于字典分类,默认0
+Def_PDict_BackupTime = "BackupTime" # 最近一次数据备档时间
 Def_QuDao_DoubleBillGold = "qddbGold"   # 渠道返利的仙玉
 Def_QuDao_DoubleBillCount = "qddbCount"   # 渠道返利的仙玉领取次数 日期+次数组合数字
 Def_PDict_GeTuiSet = "GetuiSet"     # 推送提醒的设置
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IPY_GameObj.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IPY_GameObj.py
index 4b47e32..3d4ef0e 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IPY_GameObj.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IPY_GameObj.py
@@ -1668,6 +1668,7 @@
     def SetClientMoveTick(self, *args): return _IPY_GameObj.IPY_Player_SetClientMoveTick(self, *args)
     def Sync_ClientTick(self): return _IPY_GameObj.IPY_Player_Sync_ClientTick(self)
     def PushSaveData(self): return _IPY_GameObj.IPY_Player_PushSaveData(self)
+    def RealTimeBackupSinglePlayerLogic(self, *args): return _IPY_GameObj.IPY_Player_RealTimeBackupSinglePlayerLogic(self, *args)
     def Sync_FbSystemMessage(self, *args): return _IPY_GameObj.IPY_Player_Sync_FbSystemMessage(self, *args)
     def Sync_ShowFbBillboard(self): return _IPY_GameObj.IPY_Player_Sync_ShowFbBillboard(self)
     def Interface_SaveCard(self, *args): return _IPY_GameObj.IPY_Player_Interface_SaveCard(self, *args)
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerBackup.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerBackup.py
new file mode 100644
index 0000000..f127920
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerBackup.py
@@ -0,0 +1,86 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package Player.PlayerBackup
+#
+# @todo:玩家备档
+# @author hxp
+# @date 2022-12-06
+# @version 1.0
+#
+# 详细描述: 玩家备档
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2022-12-06 18:30"""
+#-------------------------------------------------------------------------------
+
+import ChConfig
+import PlayerControl
+import ReadChConfig
+import GameWorld
+
+import shutil
+import time
+import os
+
+def CheckPlayerBackup(curPlayer):
+    PlayerBakRoot = ReadChConfig.GetPyMongoConfig("Backup", "PlayerBakRoot", isLog=False)
+    if not PlayerBakRoot:
+        #GameWorld.DebugLog("未启用备档")
+        return
+    curTime = int(time.time())
+    backupTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_BackupTime)
+    if not backupTime:
+        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_BackupTime, curTime)
+        return
+    
+    playerID = curPlayer.GetPlayerID()
+    BackupCDTimes = GameWorld.ToIntDef(ReadChConfig.GetPyMongoConfig("Backup", "BackupMinutes"))
+    if not BackupCDTimes or curTime - backupTime < BackupCDTimes * 60:
+        #GameWorld.DebugLog("备档cd中, BackupCDTimes=%s,pass=%s" % (BackupCDTimes, curTime - backupTime), playerID)
+        return
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_BackupTime, curTime)
+    
+    PlayerBakDir = os.path.join(PlayerBakRoot, str(playerID))
+    BakCopyDir = os.path.join(PlayerBakDir, "Backup")
+    if not os.path.exists(PlayerBakDir):
+        os.makedirs(PlayerBakDir)
+        os.makedirs(BakCopyDir)
+        
+    fileType = ReadChConfig.GetPyMongoConfig("Backup", "PlayerBakFileType", defaultValue=".pdbak")
+    moveList, copyList = [], []
+    for parent, _, filenames in os.walk(PlayerBakDir):
+        for filename in filenames:
+            if not filename.endswith(fileType):
+                continue
+            fullPath = os.path.join(parent, filename)
+            if parent == BakCopyDir:
+                bakTime = GameWorld.ToIntDef(filename[:filename.index(".")].split("_")[1])
+                copyList.append([bakTime, fullPath])
+            else:
+                if not os.path.exists(os.path.join(BakCopyDir, filename)):
+                    moveList.append(fullPath)
+                else:
+                    os.remove(fullPath)
+                    
+    for filePath in moveList:
+        shutil.move(filePath, BakCopyDir)
+        
+    copyList.sort()
+    BackupCopyMax = GameWorld.ToIntDef(ReadChConfig.GetPyMongoConfig("Backup", "BackupCopy")) # 保留旧备档份数
+    delCopyCount = len(copyList) + len(moveList) - BackupCopyMax
+    for _, copyFilePath in copyList:
+        if delCopyCount > 0:
+            delCopyCount -= 1
+            os.remove(copyFilePath)
+        else:
+            break
+        
+    # 玩家备档文件格式:  玩家ID_备档时间戳.pb
+    pdBakPath = os.path.join(PlayerBakDir, "%s_%s%s" % (playerID, curTime, fileType))
+    curPlayer.RealTimeBackupSinglePlayerLogic(pdBakPath)
+    GameWorld.DebugLog("DoPlayerBackup: %s" % pdBakPath, playerID)
+    return
+
+
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerState.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerState.py
index 1816ccc..2a05c49 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerState.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerState.py
@@ -58,6 +58,7 @@
 import ChEquip
 import PlayerYinji
 import PlayerActivity
+import PlayerBackup
 
 #---------------------------------------------------------------------
 #---------------------------------------------------------------------
@@ -1161,6 +1162,9 @@
         #GameWorld.Log("玩家还未初始化成功, 不处理")
         return
     
+    #定时备档
+    PlayerBackup.CheckPlayerBackup(curPlayer)
+    
     #被GM封状态响应
     ProcessGMOperLogic(curPlayer, tick)
     
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ReadChConfig.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ReadChConfig.py
index ec2fdd2..0acb2a0 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ReadChConfig.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ReadChConfig.py
@@ -216,7 +216,7 @@
 #  @param option: 配置项名
 #  @return
 #  @remarks \db\PyMongoDataServer\PyMongoDataServer.ini配置读取
-def GetPyMongoConfig(section, option, raw=False):
+def GetPyMongoConfig(section, option, raw=False, defaultValue=None, isLog=True):
     global PyMongoDataServerConfig
     
     if not PyMongoDataServerConfig:
@@ -231,7 +231,10 @@
         GameWorld.DebugLog("Reload dbAPPath=%s" % str(dbAPPath))
     
     if not PyMongoDataServerConfig.has_option(section, option):
-        GameWorld.ErrLog("PyMongoDataServer.ini找不到配置: section=%s,option=%s" % (section, option))
+        if defaultValue != None:
+            return defaultValue
+        if isLog:
+            GameWorld.ErrLog("PyMongoDataServer.ini找不到配置: section=%s,option=%s" % (section, option))
         return ""
     
     strParam = PyMongoDataServerConfig.get(section, option, raw)

--
Gitblit v1.8.0