using System; using System.Collections.Generic; using System.Linq; using System.Threading; using Sog; namespace Game { //玩家server patch 机制, //使用场景:老玩家的一些数据随着版本迭代已经不符合当下的需求,或者一些业务存在bug,导致玩家数据不正确,需要修复 //对应的数据,但是不想把修复代码参合再现有的逻辑中、补丁方式修复,所以建议采用patch 机制,玩家只需要执行一次修复, //后续将不用再维护相关的修复逻辑。 public static class PatchSvc { private class PatchModel { public int Id; public Func Patch; } private static readonly ReaderWriterLockSlim Locker = new(); private static int _maxPatch; private static readonly Dictionary AllPatchMethods = new(); public static void RegisterAll() { try { Locker.EnterUpgradeableReadLock(); try { //写锁线程只有一个 Locker.EnterWriteLock(); AllPatchMethods.Clear(); Register(PatchCode.PATCH_CODE_FIX_TEST, FixTest); } catch (Exception e) { TraceLog.Error("Patch.Register register method failed,e={0}", e.Message); } finally { Locker.ExitWriteLock(); } } catch (Exception e) { TraceLog.Error("Patch.Register register method failed,e={0}", e.Message); } finally { Locker.ExitUpgradeableReadLock(); } } private static void Register(int id, Func method) { if (method == null) { return; } TraceLog.Trace("PatchSvc.Register register method,id={0},name={1}", id, method.Method.Name); AllPatchMethods[id] = new PatchModel() { Id = id, Patch = method }; _maxPatch = Math.Max(_maxPatch, id); } public static void PatchAll(PlayerOnGame player) { _Patch(player); player.MakeDirty(); } private static void _Patch(PlayerOnGame player) { try { Locker.EnterReadLock(); int position = player.RoleData.ExtData.Patch; if (position == _maxPatch) { return; } if (AllPatchMethods.Count == 0) { return; } foreach (var patch in AllPatchMethods.Where(patch => patch.Key > position)) { try { patch.Value.Patch(player); } catch (Exception e) { TraceLog.Trace("PatchSvc.PatchAll patch failed. id={0},name={1},error info={2}", patch.Key, patch.Value.Patch.Method.Name, e.Message); break; } position = Math.Max(patch.Key, position); } player.RoleData.ExtData.Patch = position; } catch (Exception e) { TraceLog.Trace("PatchSvc.PatchAll patch failed,e={0}", e.Message); } finally { Locker.ExitReadLock(); } } public static void OnPlayerBorn(PlayerOnGame player) { int position = 0; try { Locker.EnterReadLock(); position = _maxPatch; } catch (Exception e) { TraceLog.Error("PatchSvc.OnPlayerBorn error: {0}", e.Message); } finally { Locker.ExitReadLock(); } player.RoleData.ExtData.Patch = position; } //---------------------------------------------------------------- 需要修复的逻辑 public static int FixTest(PlayerOnGame player) { TraceLog.Trace("test fix data player uid={0}", player.UserID); return 0; } } }