MergeServerLogic.lua 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
  1. --合服逻辑
  2. --[=[
  3. 1.备份数据库, 方法见 MergeServerDefine
  4. 2.先执行一次start.sh, 因为重启游戏服时会根据条件删除一些数据, 这样合服时要处理的数据就少了一些
  5. 3.将/script 目录下 Main文件改名为其他名字, MainMerger改为Main,合服完毕后再改回来。
  6. 4.检查MergeServerDefine中的MERGE_DB_TB数据库名是否正确, 如果正确则和正常启动游戏一样启动游戏服, 开始进行合服
  7. 5.查看日志oss_merge, 看看是否有报错
  8. 6.修改mysql区服列表的 port 和 dbName, 被合服的 port 和 dbname 要改为目标服一样
  9. 7.修改linux上代表游戏服的bin*文件名, 防止 start.sh 启动时会把被合服也启动起来
  10. 8.需要测试下邮件和cdk
  11. ]=]
  12. local LuaMongo = _G.lua_mongo
  13. local Config = require("Config")
  14. local Log = require("common.Log")
  15. local MergeServerDefine = require("merge.MergeServerDefine")
  16. local MoZhuExcel = require("excel.mozhu")
  17. local MailExcel = require("excel.mail")
  18. local Util = require("common.Util")
  19. local ItemDefine = require("bag.ItemDefine")
  20. local primaryKeyTable = {}
  21. --重复_id缓存表
  22. local repeatIdTb = {}
  23. --目标服和被合服所有玩家的名字缓存表
  24. local allNameTb = {}
  25. --同名数据
  26. local repeatName2Data = {}
  27. local num = 0
  28. --次元魔珠数据缓存表
  29. local mozhuDbCache = { roleList = {}, unionList = {}}
  30. --创建一个mongo连接实例
  31. local function clientMongoDb(addr)
  32. addr = addr or Config.DB_IP
  33. LuaMongo.client(addr)
  34. end
  35. --切换数据库
  36. local function chooseMongoDb(dbName)
  37. if not dbName or dbName == "" then
  38. print(string.format("数据库名错误, dbName = %s\n", dbName))
  39. return
  40. end
  41. LuaMongo.auth(dbName, Config.DB_USER, Config.DB_PASS)
  42. end
  43. --生成新的 _id
  44. local function generateNewId()
  45. local newId = LuaMongo.id()
  46. return newId
  47. end
  48. --清理部分缓存数据
  49. local function cleanCache()
  50. primaryKeyTable = {}
  51. repeatIdTb = {}
  52. allNameTb = {}
  53. repeatName2Data = {}
  54. mozhuDbCache = { roleList = {}, unionList = {}}
  55. end
  56. --写日志
  57. local function writeLog(tag, targetDb, sourceDb, sourceColl, info1, info2, docId, errInfo)
  58. local logInfo = string.format("tag: %s, targetDb: %s, sourceDb: %s, sourceColl: %s, info1: %s, info2: %s, docId: %s, errInfo: %s",
  59. tag, targetDb, sourceDb, sourceColl, info1, info2, docId, errInfo)
  60. Log.write(Log.LOGID_OSS_MERGE, logInfo)
  61. end
  62. -------------------------------------------------------------需要单独处理的部分数据---------------------------------------------------------------------
  63. ----------------恶魔之塔-------------------
  64. local queryTowerByLv = { lv = nil }
  65. local function getSourceServerTowerData(sourceDb, collectionName, level)
  66. local targetCollection = sourceDb .. collectionName
  67. queryTowerByLv.lv = level
  68. LuaMongo.find(targetCollection, queryTowerByLv, {})
  69. local data = {}
  70. if not LuaMongo.next(data) then
  71. return nil
  72. end
  73. return data
  74. end
  75. ---------------------------------次元魔蛛/梼杌------------------------------------
  76. local MozhuQueryFiles = { [MergeServerDefine.KEY_CIYUAN_MOZHU] = 1}
  77. --读取
  78. local function loadMoZhuDB(sourceDb, collectionName)
  79. local targetCollection = sourceDb .. collectionName
  80. LuaMongo.find(targetCollection, nil, MozhuQueryFiles)
  81. local data = {}
  82. if not LuaMongo.next(data) then
  83. return nil
  84. end
  85. local targetMoZhuData = data.ciyuanMoZhu
  86. for uuid, roleData in pairs(targetMoZhuData.role or {}) do
  87. mozhuDbCache.roleList[uuid] = roleData
  88. end
  89. for uuid, unionData in pairs(targetMoZhuData.union or {}) do
  90. mozhuDbCache.unionList[uuid] = unionData
  91. num = num + 1
  92. end
  93. end
  94. --随机词条
  95. local function randomCiTiao(data)
  96. local weekTime = Util.getWeekStartTime(os.time())
  97. -- if data.citiaoTime and data.citiaoTime == weekTime then
  98. -- return
  99. -- end
  100. data.citiao = {}
  101. local citiao_rare_max
  102. if not citiao_rare_max then
  103. -- 防止策划删减 词条
  104. citiao_rare_max = 0
  105. for k, v in pairs(MoZhuExcel.citiao) do
  106. if v then
  107. citiao_rare_max = citiao_rare_max + v.quanzhong
  108. end
  109. end
  110. end
  111. local getRare = 0
  112. for i=1, 1 do
  113. local random = math.random(1, citiao_rare_max - getRare)
  114. for k, v in pairs(MoZhuExcel.citiao) do
  115. if not data.citiao[k] and random <= v.quanzhong then
  116. data.citiao[k] = i
  117. getRare = getRare + v.quanzhong
  118. break
  119. elseif not data.citiao[k] then
  120. -- 防止循环最后一个是 已经随机过的 导致 随机不出来
  121. random = random - v.quanzhong
  122. end
  123. end
  124. end
  125. data.citiaoTime = weekTime
  126. end
  127. --初始化魔珠db
  128. local function initMoZhuDB(data)
  129. data.time = os.time()
  130. data.unionRank = {}
  131. data.roleRank = {}
  132. data.role = {}
  133. data.union= {}
  134. --词条
  135. randomCiTiao(data)
  136. end
  137. --插入
  138. local function insertTargetMoZhuDB(targetDb)
  139. local collectionName = MergeServerDefine.COLLECTIONS[3]
  140. local targetCollection = targetDb .. collectionName
  141. LuaMongo.find(targetCollection, nil, MozhuQueryFiles)
  142. local data = {}
  143. if not LuaMongo.next(data) then
  144. return
  145. end
  146. if not data.ciyuanMoZhu then
  147. data.ciyuanMoZhu = {}
  148. initMoZhuDB(data.ciyuanMoZhu)
  149. end
  150. local targetMoZhuData = data.ciyuanMoZhu
  151. local roleRankLen = #targetMoZhuData.roleRank
  152. local unionRankLen = #targetMoZhuData.unionRank
  153. --玩家
  154. for uuid, roleData in pairs(mozhuDbCache.roleList) do
  155. targetMoZhuData.role[uuid] = roleData
  156. roleRankLen = roleRankLen + 1
  157. targetMoZhuData.roleRank[roleRankLen] = uuid
  158. end
  159. --公会
  160. for uuid, unionData in pairs(mozhuDbCache.unionList) do
  161. targetMoZhuData.union[uuid] = unionData
  162. unionRankLen = unionRankLen + 1
  163. targetMoZhuData.unionRank[unionRankLen] = uuid
  164. end
  165. --排序
  166. table.sort(targetMoZhuData.roleRank, function(a, b)
  167. local roleA = targetMoZhuData.role[a]
  168. local roleB = targetMoZhuData.role[b]
  169. return roleA.hurt > roleB.hurt
  170. end)
  171. table.sort(targetMoZhuData.unionRank, function(a, b)
  172. local unionA = targetMoZhuData.union[a]
  173. local unionB = targetMoZhuData.union[b]
  174. if unionA.hurt > unionB.hurt then
  175. return true
  176. elseif unionA.hurt == unionB.hurt then
  177. return unionA.time < unionB.time
  178. end
  179. return false
  180. end)
  181. --更新
  182. LuaMongo.update(targetCollection, {}, {
  183. ["$set"] = {
  184. [MergeServerDefine.KEY_CIYUAN_MOZHU] = targetMoZhuData
  185. },
  186. })
  187. mozhuDbCache = nil
  188. end
  189. -----------------------------------------------------------------------------
  190. ---------------------------------------玩家同名------------------------------
  191. local NameQueryFiles = { ["name"] = 1 }
  192. --加载目标库所有玩家的名字
  193. local function loadTargetCharName(targetDb)
  194. local collectionName = MergeServerDefine.COLLECTIONS[1]
  195. local targetCollection = targetDb .. collectionName
  196. LuaMongo.find(targetCollection, nil, NameQueryFiles)
  197. while true do
  198. local data = {}
  199. if not LuaMongo.next(data) then
  200. break
  201. end
  202. allNameTb[data.name] = '1'
  203. end
  204. end
  205. --得到一个邮件数据
  206. local mailConfig = MailExcel.mail[MergeServerDefine.MAIL_ID]
  207. local function frontMail(receiverUuid)
  208. local mail = {}
  209. mail.type = 1
  210. mail.receiverUuid = receiverUuid
  211. mail.title = mailConfig.title
  212. mail.content = mailConfig.content
  213. mail.read = nil
  214. mail.senderName = mailConfig.title
  215. mail.head = 0
  216. mail.fbTime = nil
  217. mail.fbContent = nil
  218. mail.time = os.time()
  219. mail.get = nil
  220. mail.flag = 1
  221. mail.items = { { ItemDefine.ITEM_ZUANSHI_ID, MergeServerDefine.MAIL_NUM } }
  222. return mail
  223. end
  224. --给因同名而修改名字的玩家发送补偿邮件
  225. local function sendMail(targetDb)
  226. local coll = MergeServerDefine.COLLECTIONS[2]
  227. local targetCollection = targetDb .. coll
  228. for oldName, v in pairs(repeatName2Data) do
  229. local mail = frontMail(v.uuid)
  230. local _, err = pcall(LuaMongo.insert, targetCollection, mail)
  231. writeLog(MergeServerDefine.CHANGENAME_TAG, targetDb, v.sourceDb, coll, oldName, v.newName, v.uuid, err or "")
  232. end
  233. end
  234. --------------------------------更新合服时间------------------------------------
  235. local function updateMergeTime(targetDb)
  236. local targetCollection = targetDb .. MergeServerDefine.COLLECTIONS[3]
  237. local now = os.time()
  238. LuaMongo.update(targetCollection, {}, {
  239. ["$set"] = {
  240. [MergeServerDefine.KEY_MERGE_TIME] = now
  241. },
  242. })
  243. end
  244. ----------------------------------------------------------------------------------------------------------------------------------
  245. -----------------------------------------------------char集合中_id的重复检测和处理-------------------------------------------------
  246. --用于检测不同数据库的char集合中的_id是否有重复, 一般来说通过mongo生成的_id基本不会重复(暂时不用)
  247. local function primaryKeyRepeatCheck()
  248. print("================================检查char集合_id的重复性开始=======================================\n")
  249. local collectionName = MergeServerDefine.COLLECTIONS[1]
  250. for k, dbName in ipairs(MergeServerDefine.MERGE_DB_TB) do
  251. local targetCollection = dbName .. collectionName
  252. LuaMongo.find(targetCollection, nil, nil, {_id = 1})
  253. while true do
  254. local data = {}
  255. if not LuaMongo.next(data) then
  256. break
  257. end
  258. if k ~= 1 then
  259. if primaryKeyTable[data._id] then
  260. repeatIdTb[data._id] = generateNewId()
  261. Log.write(Log.LOGID_OSS_MERGE, string.format("result: %s, targetColl: %s, repeatId: %s, newId: %s",
  262. "Repeat", targetCollection, data._id, repeatIdTb[data._id]))
  263. else
  264. primaryKeyTable[data._id] = '1'
  265. end
  266. else
  267. primaryKeyTable[data._id] = '1'
  268. end
  269. end
  270. end
  271. print("================================检查char集合_id的重复性结束=======================================\n")
  272. end
  273. --好友集合
  274. local function handleFriend(data)
  275. if repeatIdTb[data.uuid1] then
  276. data.uuid1 = repeatIdTb[data.uuid1]
  277. end
  278. if repeatIdTb[data.uuid2] then
  279. data.uuid2 = repeatIdTb[data.uuid2]
  280. end
  281. end
  282. --邮件集合
  283. local function handleMail(data)
  284. if repeatIdTb[data.receiverUuid] then
  285. data.receiverUuid = repeatIdTb[data.receiverUuid]
  286. end
  287. end
  288. --公会集合
  289. local function handleUnion(data)
  290. local tb = {}
  291. for id, v in pairs(data.member) do
  292. if repeatIdTb[id] then
  293. tb[id] = v
  294. end
  295. end
  296. for id, v in pairs(tb) do
  297. data.member[id] = nil
  298. data.member[repeatIdTb[id]] = v
  299. end
  300. tb = {}
  301. for id, v in pairs(data.apply) do
  302. if repeatIdTb[id] then
  303. tb[id] = v
  304. end
  305. end
  306. for id, v in pairs(tb) do
  307. data.apply[id] = nil
  308. data.apply[repeatIdTb[id]] = v
  309. end
  310. if data.presidentUuid and repeatIdTb[data.presidentUuid] then
  311. data.presidentUuid = repeatIdTb[data.presidentUuid]
  312. end
  313. end
  314. --星空争霸集合
  315. local function handleStar(data)
  316. if repeatIdTb[data.uuid] then
  317. data.uuid = repeatIdTb[data.uuid]
  318. end
  319. end
  320. --单人竞技场集合
  321. local function handleJJC(data)
  322. if not data.monsterOutID and repeatIdTb[data._id] then
  323. data._id = repeatIdTb[data._id]
  324. end
  325. end
  326. --战斗视频集合
  327. local function handleVideo(data)
  328. local uuid = data.combatInfo.attacker.uuid
  329. if repeatIdTb[uuid] then
  330. data.combatInfo.attacker.uuid = repeatIdTb[uuid]
  331. end
  332. end
  333. ----------------------------------------------------合并数据----------------------------------------------------------
  334. local writeQueue = {}
  335. local function flushWriteQueue()
  336. for _, task in ipairs(writeQueue) do
  337. local ok, err = pcall(LuaMongo.insert, task.collection, task.data)
  338. if not ok then
  339. Log.write(Log.LOGID_OSS_MERGE, task.collection, err)
  340. end
  341. end
  342. writeQueue = {}
  343. end
  344. -- 每积累100条数据批量写入
  345. local function bufferedInsert(collection, data)
  346. table.insert(writeQueue, {collection=collection, data=data})
  347. if #writeQueue >= 100 then
  348. flushWriteQueue()
  349. end
  350. end
  351. local function processCollection(sourceDb, targetDb, coll)
  352. local sourceCollection = sourceDb .. coll
  353. local targetCollection = targetDb .. coll
  354. local errNum = 0
  355. local allNum = 0
  356. LuaMongo.find(sourceCollection, nil, {})
  357. while true do
  358. local data = {}
  359. if not LuaMongo.next(data) then
  360. break
  361. end
  362. --直接插入目标库
  363. local ok, err = pcall(LuaMongo.insert, targetCollection, data)
  364. if not ok then
  365. errNum = errNum + 1
  366. writeLog(MergeServerDefine.ERR_TAG, targetDb, sourceDb, coll, 1, 1, data._id, err)
  367. end
  368. allNum = allNum + 1
  369. end
  370. writeLog(MergeServerDefine.SUCC_TAG, targetDb, sourceDb, coll, allNum, errNum, "", "")
  371. end
  372. --合并char集合
  373. local function processCharColl(sourceDb, targetDb, coll)
  374. local sourceCollection = sourceDb .. coll
  375. local targetCollection = targetDb .. coll
  376. local errNum = 0
  377. local allNum = 0
  378. LuaMongo.find(sourceCollection, nil, {})
  379. while true do
  380. local data = {}
  381. if not LuaMongo.next(data) then
  382. break
  383. end
  384. --同名检测
  385. if allNameTb[data.name] then
  386. num = num + 1
  387. local newName = MergeServerDefine.NEW_NAME .. num
  388. --统计数据
  389. repeatName2Data[data.name] = {
  390. uuid = data._id,
  391. newName = newName,
  392. sourceDb = sourceDb,
  393. }
  394. --改名
  395. data.name = newName
  396. end
  397. allNameTb[data.name] = '1'
  398. --插入目标库
  399. local ok, err = pcall(LuaMongo.insert, targetCollection, data)
  400. if not ok then
  401. errNum = errNum + 1
  402. writeLog(MergeServerDefine.ERR_TAG, targetDb, sourceDb, coll, 1, 1, data._id, err)
  403. end
  404. allNum = allNum + 1
  405. end
  406. writeLog(MergeServerDefine.SUCC_TAG, targetDb, sourceDb, coll, allNum, errNum, "", "")
  407. end
  408. local function startMergeServer(dbList)
  409. assert(dbList and next(dbList), "====数据错误====")
  410. cleanCache()
  411. --目标集合数据库名
  412. local targetDb = dbList[1]
  413. loadTargetCharName(targetDb)
  414. for i = 2, #dbList do
  415. local sourceDb = dbList[i]
  416. LuaMongo.auth(sourceDb, Config.DB_USER, Config.DB_PASS)
  417. for _, coll in ipairs(MergeServerDefine.COLLECTIONS) do
  418. if not MergeServerDefine.NO_INSERT_COLLECTIONS[coll] then
  419. print(string.format("========================开始处理集合: %s, %s\n", sourceDb, coll))
  420. if coll == MergeServerDefine.COLLECTIONS[1] then
  421. processCharColl(sourceDb, targetDb, coll)
  422. elseif coll == MergeServerDefine.COLLECTIONS[3] then
  423. loadMoZhuDB(sourceDb, coll)
  424. else
  425. processCollection(sourceDb, targetDb, coll)
  426. end
  427. end
  428. end
  429. end
  430. --处理那些需要单独处理的数据
  431. insertTargetMoZhuDB(targetDb)
  432. sendMail(targetDb)
  433. updateMergeTime(targetDb)
  434. end
  435. --合服开始函数
  436. function Start()
  437. --创建mongo连接实例
  438. clientMongoDb()
  439. --检查char集合_id的重复性
  440. --primaryKeyRepeatCheck()
  441. print("========================合服开始=====================")
  442. for i, dbList in ipairs(MergeServerDefine.MERGE_DB_TB) do
  443. startMergeServer(dbList)
  444. end
  445. print("========================合服结束=====================")
  446. end