引入PETimer之后,就可以整合进服务器和客户端,为它们添加计时服务:
PlaneZhong/PETimer: A C# Timer Tool. (github.com)
服务器TimerSvc
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
| using System; using System.Collections.Generic;
public class TimerSvc:SingletonPattern<TimerSvc> { class TaskPack { public int tid; public Action<int> callback; public TaskPack(int tid, Action<int> callback) { this.tid = tid; this.callback = callback; } } PETimer pt = null; Queue<TaskPack> tpQue = new Queue<TaskPack>(); static readonly string tpQueLock = "tpQueLock"; public void Init() { pt = new PETimer(100); tpQue.Clear(); pt.SetLog(info => { PECommon.Log(info); }); pt.SetHandle((callback,tid) => { if(callback != null) { lock(tpQueLock) { tpQue.Enqueue(new TaskPack(tid, callback)); } } }); PECommon.Log("TimerSvc Init Done"); } public void Update() { while(tpQue.Count > 0) { TaskPack tp = null; lock (tpQueLock) { tp = tpQue.Dequeue(); } tp?.callback(tp.tid); } } public int AddTimeTask(Action<int> callback, double delay, PETimeUnit timeUnit = PETimeUnit.Millisecond, int count = 1) { return pt.AddTimeTask(callback, delay, timeUnit, count); } }
|
定制体力增长的GameMsg
1 2 3 4 5
| [System.Serializable] public class PshPower { public int power; }
|
服务器PowerSys
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
| using PENet; using PEProtocol; using System.Collections.Generic;
public class PowerSys:SingletonPattern<PowerSys> { CacheSvc _cacheSvc; public void Init() { _cacheSvc = CacheSvc.Instance;
TimerSvc.Instance.AddTimeTask(CalcPowerAdd, PECommon.PowerAddInterval, PETimeUnit.Minute, 0); PECommon.Log("PowerSys Inited"); } private void CalcPowerAdd(int tid) { GameMsg msg = new GameMsg() { cmd = (int)CMD.PshPower }; msg.pshPower = new PshPower(); Dictionary<ServerSession,PlayerData> onlineDic = _cacheSvc.GetOnlineCache(); foreach (var item in onlineDic) { PlayerData pd = item.Value; ServerSession session = item.Key;
int powerMax = PECommon.GetPowerLimit(pd.lv); if(pd.power>=powerMax) { continue; } else { pd.power += PECommon.PowerAddNum; if(pd.power >= powerMax) { pd.power = powerMax; } }
if(_cacheSvc.UpdatePlayerData(pd.id, pd)) { msg.err = (int)ErrorCode.UpdateDBError; } else { msg.pshPower.power = pd.power; session.SendMsg(msg); } } } }
|
服务器一开始启动,就执行PoweSys,每5分钟向全服在线玩家发送体力增长消息
离线玩家体力计算
离线玩家离线时记下时间戳,当玩家再次上线时通过与服务器时间对比计算出体力的增加值
GameMsg定义时间戳
修改GameMsg
的PalyerData
部分
1 2 3 4 5 6 7
| public class PlayerData { public long time;
}
|
数据库添加time
在DBMgr
——QueryPlayerData
中:
1
| time = mySqlDataReader.GetInt64("time")
|
在创建新的玩家账号时:
1
| time = TimeSvc.Instance.GetNowTime();
|
TimeSvc.Instance.GetNowTime();
这个API调用的是PETimer的GetMillisecondsTime()
1 2 3 4
| public long GetNowTime() { return (long)pt.GetMillisecondsTime(); }
|
GetMillisecondsTime()
返回的是从当前UTC时间到计算机元年(1970.1.1)的双精度浮点数
1 2 3 4 5
| private double GetUTCMilliseconds() { TimeSpan ts = DateTime.UtcNow - startDateTime; return ts.TotalMilliseconds; }
|
PETimer
是使用这个时间来作为时间计时的比较的
数据库设计表:
名 |
类型 |
长度 |
小数点 |
不是null |
time |
bigint |
11 |
0 |
√ |
修改服务器LoginSys
每次登录服务器,服务器需要根据时间戳计算玩家的体力增量并刷新玩家数据库,然后再发送给玩家登录成功的消息
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
| int power = _playerData.power; long nowtime = _timerSvc.GetNowTime(); long playerOfflineTime = _playerData.time; long playerOfflineDuration = nowtime - playerOfflineTime; int addPower = (int)(playerOfflineDuration / (PECommon.PowerAddInterval * 60 * 1000))*PECommon.PowerAddNum; if (addPower > 0) { int powerMax = PECommon.GetPowerLimit(_playerData.lv); if (_playerData.power < powerMax) { _playerData.power += addPower; if (_playerData.power > powerMax) { _playerData.power = powerMax; } } } if (power != _playerData.power) { _cacheSvc.UpdatePlayerData(_playerData.id, _playerData); }
msg.rspLogin = new RspLogin { playerData = _playerData };
_cacheSvc.AcctOnline(data.acct, msgPack.session, _playerData);
|
玩家下线时更新时间戳
修改服务器LoginSys
的ClearOfflieData
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public void ClearOfflieData(ServerSession session) { PlayerData pd = _cacheSvc.GetPalyerDataBySession(session); if (pd != null) { pd.time = _timerSvc.GetNowTime(); if(!_cacheSvc.UpdatePlayerData(pd.id, pd)) { PECommon.Log("Update Offline time error",LogType.Error); } _cacheSvc.AcctOffLine(session); } }
|
在线玩家更新时间戳
为了防止玩家意外下线,每次在线玩家体力增长时更新玩家的时间数据,修改PowerSys
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
| private void CalcPowerAdd(int tid) { Dictionary<ServerSession,PlayerData> onlineDic = _cacheSvc.GetOnlineCache(); foreach (var item in onlineDic) { PlayerData pd = item.Value; ServerSession session = item.Key;
int powerMax = PECommon.GetPowerLimit(pd.lv); if(pd.power>=powerMax) { continue; } else { pd.power += PECommon.PowerAddNum; pd.time = _timerSvc.GetNowTime(); if(pd.power >= powerMax) { pd.power = powerMax; } }
if(!_cacheSvc.UpdatePlayerData(pd.id, pd)) { msg.err = (int)ErrorCode.UpdateDBError; } else { msg.pshPower.power = pd.power; session.SendMsg(msg); } } }
|