using CommonAI.RTS;
using CommonAI.Zone;
using CommonAI.Zone.Attributes;
using CommonAI.Zone.Helper;
using CommonAI.Zone.ZoneEditor;
using CommonLang;
using CommonLang.Concurrent;
using CommonLang.Log;
using CommonLang.Protocol;
using System;
using System.Collections.Generic;
namespace CommonAI.ZoneClient
{
public interface ILayerClient
{
void SendAction(CommonAI.Zone.Action action);
//为战斗场景添加
void BattleReady(bool bok);
}
///
/// 客户端同步模式
///
public enum SyncMode : byte
{
///
/// 服务端强同步
///
ForceByServer = 0,
///
/// 移动直接在客户端处理,技能在客户端预处理,(伤害数字由服务端同步)
///
MoveByClient_PreSkillByClient = 2,
}
// ---------------------------------------------------------------------------------------------
public partial class ZoneLayer : GameEntity
{
private static AtomicInteger s_alloc_object_count = new AtomicInteger(0);
private static AtomicInteger s_active_object_count = new AtomicInteger(0);
///
/// 未释放实例数量
///
public static int ActiveZoneLayerCount { get { return s_active_object_count.Value; } }
///
/// 分配实例数量
///
public static int AllocZoneLayerCount { get { return s_alloc_object_count.Value; } }
///
/// 超出此同步范围,立即将坐标修正
///
public float AsyncUnitPosModifyMaxRange { get; private set; }
///
/// 是否主角做异步位置同步(即客户端先模拟假象)
///
public SyncMode ActorSyncMode { get; set; }
///
/// 服务器时间,从游戏开始到现在多少毫秒
///
public long ServerTimeMS { get { return mRemotePassTimeMS; } }
///
/// 是否为Short,双字节同步单位,场景必须小于255
///
public bool IsHalfSync { get; private set; }
///
/// 是否实时同步Z坐标,如果不实时同步Z坐标,那么客户端本地计算Z
///
public bool IsSyncZ { get; private set; }
///
/// 当前客户端更新Interval
///
public int CurrentIntervalMS { get; private set; }
///
/// 当前客户端Ping值
///
public int CurrentPing { get; private set; }
///
/// 服务端资源版本号
///
public string ServerResourceVersion { get; private set; }
///
/// 本地资源版本号
///
public string ClientResourceVersion { get { return Templates.ResourceVersion; } }
private Logger log = LoggerFactory.GetLogger("ZoneClient");
private long mRemotePassTimeMS = 0;
private SceneData mData;
private ZoneInfo mTerrainDataSrc;
//private SyncMessageQueue mSyncMessageQueue = new SyncMessageQueue();
private List mSyncMessageQueue = new List();
private HashMap EnvironmentVarMap = new HashMap();
private HashMap mListenRequests = new HashMap();
private TimeInterval mListenRequestTimeout = new TimeInterval(2000);
private ServerStatusB2C mLastServerStatus;
public float MinStep { get; private set; }
public ILayerClient LayerClient { get; private set; }
public TemplateManager Templates { get; private set; }
public EditorTemplates DataRoot { get; private set; }
public bool IsLoaded { get; private set; }
public ServerStatusB2C ServerStatus { get { return mLastServerStatus; } }
public ZoneLayer(EditorTemplates dataroot, ILayerClient client)
{
ZoneLayer.s_alloc_object_count++;
ZoneLayer.s_active_object_count++;
this.IsLoaded = false;
this.DataRoot = dataroot;
this.LayerClient = client;
this.ActorSyncMode = SyncMode.ForceByServer;
this.Templates = dataroot?.Templates;
if (Templates == null)
{
log.Error("dataroot cannot set to null");
}
else
{
this.AsyncUnitPosModifyMaxRange = Templates.CFG.CLIENT_UNIT_MOVE_MODIFY_MAX_RANGE;
this.MinStep = MoveHelper.GetDistance(1000 / Templates.CFG.SYSTEM_FPS, Templates.CFG.OBJECT_MOVE_TO_MIN_STEP_SEC);
}
}
//-------------------------------------------------------------------------------------------
~ZoneLayer()
{
ZoneLayer.s_alloc_object_count--;
}
protected virtual void InitSceneData(ClientEnterScene msg)
{
log.Debug("---------------------------------------InitSceneData---------------------------------");
SceneData sdata;
if (mData == null)
{
sdata = DataRoot.LoadScene(msg.sceneID, false, true);
mData = sdata;
}
else
{
sdata = mData;
}
if (sdata == null)
{
throw new Exception("Can not load scene data : " + msg.sceneID);
}
this.ServerResourceVersion = msg.resVersion;
this.mTerrainDataSrc = sdata.ZoneData;
this.SpaceDivSize = msg.spaceDiv;
if (this.SpaceDivSize > 0)
{
this.mSpaceDiv = new SpaceDivision(
mTerrainDataSrc.TotalWidth,
mTerrainDataSrc.TotalHeight,
SpaceDivSize * mTerrainDataSrc.GridCellW,
SpaceDivSize * mTerrainDataSrc.GridCellH);
}
foreach (var dt in sdata.Units)
{
var zea = new ZoneEditorUnit(dt, this);
mFlags.Add(zea.Name, zea);
}
foreach (var dt in sdata.Items)
{
var zea = new ZoneEditorItem(dt, this);
mFlags.Add(zea.Name, zea);
}
foreach (var dt in sdata.Regions)
{
var zea = new ZoneEditorRegion(dt, this);
mFlags.Add(zea.Name, zea);
}
foreach (var dt in sdata.Points)
{
var zea = new ZoneEditorPoint(dt, this);
mFlags.Add(zea.Name, zea);
}
foreach (var dt in sdata.Decorations)
{
var zed = new ZoneEditorDecoration(dt, this);
mFlags.Add(zed.Name, zed);
}
foreach (var dt in sdata.Areas)
{
var zea = new ZoneEditorArea(dt, this);
mFlags.Add(zea.Name, zea);
}
this.InitTerrain(msg, out this.path_terrain_data, out this.path_finder, out this.path_terrain_area_gen);
foreach (var flag in mFlags.Values)
{
flag.OnInit();
}
foreach (ZoneObject o in mObjectes.Objects) { SwapSpace(o); }
IsLoaded = true;
if (mLayerInit != null)
{
mLayerInit.Invoke(this);
}
}
protected override void Disposing()
{
this.IsLoaded = false;
base.Disposing();
this.clearEvents();
foreach (var o in mObjectes.Objects)
{
o.Dispose();
}
this.mObjectes.Clear();
this.mObjectes = null;
this.mActor = null;
foreach (var f in mFlags.Values)
{
f.Dispose();
}
this.mFlags.Clear();
this.mFlags = null;
this.DataRoot = null;
this.Templates = null;
this.DisposeTerrain();
if (mSpaceDiv != null)
{
this.mSpaceDiv.Dispose();
}
this.mSpaceDiv = null;
this.mData = null;
this.mTerrainDataSrc = null;
if (mTasks != null)
{
this.mTasks.Clear();
}
this.mTasks = null;
if (this.mTimeTasks != null)
{
this.mTimeTasks.Dispose();
}
this.mTimeTasks = null;
if (mSyncMessageQueue != null)
{
mSyncMessageQueue.Clear();
}
EnvironmentVarMap.Clear();
EnvironmentVarMap = null;
mListenRequests.Clear();
mLastServerStatus = null;
ZoneLayer.s_active_object_count--;
}
public SceneData Data
{
get { return mData; }
set
{
mData = value;
}
}
public int SceneID
{
get { return mData.ID; }
}
//当前是否为渡劫场景
public bool IsSceneDujie()
{
return mData != null && mData.ID == 70005;
}
public ZoneInfo Terrain
{
get { return path_terrain_data.Data; }
}
public ZoneInfo TerrainSrc
{
get { return mTerrainDataSrc; }
}
///
/// 获得当前服务端可同步环境变量
///
///
///
public object GetEnvironmentVar(string key)
{
return EnvironmentVarMap.Get(key);
}
///
/// 获得当前服务端可同步环境变量列表
///
///
///
public IEnumerable ListEnvironmentVars()
{
return EnvironmentVarMap.Keys;
}
public void BeginUpdate(int intervalMS)
{
try
{
if (IsDesposed) { return; }
mTasks.ProcessMessages(this);
if (intervalMS > 0)
{
//this.mLocalPassTimeMS += intervalMS;
this.CurrentIntervalMS = intervalMS;
this.MinStep = MoveHelper.GetDistance(intervalMS, Templates.CFG.OBJECT_MOVE_TO_MIN_STEP_SEC);
this.mObjectes.ForEachObjectsDoUpdateAI();
}
}
catch(Exception )
{
}
}
public void Update()
{
if (IsDesposed) { return; }
//mSyncMessageQueue.ProcessMessages(doEvent);
if (mSyncMessageQueue != null)
{
var num = mSyncMessageQueue.Count;
for (int i = 0; i < num; i++)
{
doEvent(mSyncMessageQueue[i]);
}
mSyncMessageQueue.RemoveRange(0, num);
}
if (CurrentIntervalMS > 0)
{
updateObjects();
mTimeTasks.Update(CurrentIntervalMS);
}
if (mListenRequestTimeout.Update(CurrentIntervalMS))
{
check_request_timeout();
}
}
private void updateObjects()
{
this.mObjectes.ForEachObjectsDoUpdate();
//this.mObjectes.ForEachObjects((zo) =>
//{
// zo.Update();
// return false;
//});
//this.mObjectes.ForEachObjects((zo) =>
//{
// zo.UpdatePos();
// return false;
//});
}
//-------------------------------------------------------------------------------------------
#region IO
///
/// 接收新消息
///
///
public void ProcessMessage(IMessage _msg)
{
if (_msg is PackEvent)
{
var pack = _msg as PackEvent;
for (int i = 0; i < pack.events.Count; i++)
{
var msg = pack.events[i];
if (msg is Pong)
{
uint ctime = (uint)CUtils.CurrentTimeMS; ;
Pong pong = msg as Pong;
this.CurrentPing = (int)(ctime - pong.ClientTimeDayOfMS);
}
else
{
mSyncMessageQueue.Add(msg);
}
}
}
else
{
mSyncMessageQueue.Add(_msg);
}
}
///
/// 发送消息
///
///
public void SendAction(CommonAI.Zone.Action action)
{
if (action is Ping)
{
uint ctime = (uint)CUtils.CurrentTimeMS; ;
Ping ping = action as Ping;
ping.DayOfMS = ctime;
}
LayerClient.SendAction(action);
}
///
/// 发送请求
///
///
///
///
///
///
internal Request SendRequest(ActorRequest msg, OnResponseHandler handler, OnRequestTimeoutHandler timeout = null, int timeOutMS = 15000)
{
Request req = new Request(this, timeOutMS, msg, handler, timeout);
lock (mListenRequests)
{
mListenRequests.Add(req.MessageID, req);
}
LayerClient.SendAction(msg);
return req;
}
#endregion
//-------------------------------------------------------------------------------------------
#region EVENTS
///
/// 客户端模拟服务端的包
///
///
public void PreQueueEvent(IMessage msg)
{
doEvent(msg);
}
public void clientSendDoEvent(IMessage msg)
{
doEvent(msg);
}
private void doEvent(IMessage msg)
{
try
{
if (msg is ActorResponse)
{
var rsp = msg as ActorResponse;
on_received_response(rsp);
}
if (msg is ObjectEvent)
{
var oe = msg as ObjectEvent;
ZoneObject obj = (oe.object_id == 0) ? Actor : GetObject(oe.object_id);
if (obj == null)
{
log.Warn(">not found object(" + oe.object_id + ") @event:" + oe);
return;
}
obj.DoEvent(msg as ObjectEvent);
if (mMessageReceived != null)
{
mMessageReceived.Invoke(this, msg);
}
if (mObjectMessageReceived != null)
{
mObjectMessageReceived.Invoke(this, msg, obj);
}
if (obj.mOnDoEvent != null)
{
obj.mOnDoEvent.Invoke(obj, msg as ObjectEvent);
}
return;
}
else if (msg is ServerStatusB2C)
{
mLastServerStatus = msg as ServerStatusB2C;
}
else
{
if (msg is ClientEnterScene)
{
doClientEnterScene(msg as ClientEnterScene);
}
else if (msg is LockActorEvent)
{
doLockActorEvent(msg as LockActorEvent);
}
else if (msg is SyncObjectsEvent)
{
doSyncUnitsEvent(msg as SyncObjectsEvent);
}
else if (msg is SyncFlagsEvent)
{
doSyncFlagsEvent(msg as SyncFlagsEvent);
}
else if (msg is AddUnitEvent)
{
doAddUnitEvent(msg as AddUnitEvent);
}
else if (msg is AddSpellEvent)
{
doAddSpellEvent(msg as AddSpellEvent);
}
else if (msg is AddItemEvent)
{
doAddItemEvent(msg as AddItemEvent);
}
else if (msg is RemoveObjectEvent)
{
doRemoveObjectEvent(msg as RemoveObjectEvent);
}
else if (msg is SyncPosEvent)
{
doSyncPosEvent(msg as SyncPosEvent);
}
else if (msg is DecorationChangedEvent)
{
doDecorationChanged(msg as DecorationChangedEvent);
}
else if (msg is FlagTagChangedEvent)
{
doFlagTagChanged(msg as FlagTagChangedEvent);
}
else if (msg is SyncEnvironmentVarEvent)
{
doSyncEnvironmentVarEvent(msg as SyncEnvironmentVarEvent);
}
else if (msg is ChangeBGMEvent)
{
doChangeBGMEvent(msg as ChangeBGMEvent);
}
else if (msg is DoScriptEvent)
{
doDoScriptEvent(msg as DoScriptEvent);
}
else if (msg is ScriptCommandEvent)
{
doScriptCommandEvent(msg as ScriptCommandEvent);
}
else if (msg is GameOverEvent)
{
//doZoneEvent(ZoneEvent.GAME_OVER, null, msg);
doGameOver(msg as GameOverEvent);
}
//doZoneEvent(ZoneEvent.MESSAGE, null, msg);
if (mMessageReceived != null)
{
mMessageReceived.Invoke(this, msg);
}
}
}
finally
{
if (msg is Event) (msg as Event).sender = null;
}
}
private void doClientEnterScene(ClientEnterScene msg)
{
this.InitSceneData(msg);
}
private void doLockActorEvent(LockActorEvent msg)
{
//客户端可以主动发送战斗服消息
if(LayerClient != null)
{
LayerClient.BattleReady(true);
}
if (msg.CurrentZoneVars != null)
{
foreach (CommonAI.ZoneClient.ClientStruct.ZoneEnvironmentVar var in msg.CurrentZoneVars)
{
EnvironmentVarMap.Put(var.Key, var.Value);
}
}
if (msg.UnitData != null)
{
SyncUnitInfo syn = msg.UnitData;
ZoneUnit ret = GetObject(syn.ObjectID) as ZoneUnit;
if (ret != null)
{
removeObj(syn.ObjectID);
}
UnitInfo unit = Templates.getUnit(syn.TemplateID);
if (unit != null)
{
unit = unit.Clone() as UnitInfo;
unit.Properties = msg.GameServerProp;
ZoneActor act = TemplateManager.Factory.CreateClientActor(this, unit, msg);
act.Direction = syn.direction;
mActor = act;
if (ret == null)
{
addObj(act);
}
else
{
replaceObj(act);
}
}
else
{
log.Error("TemplateID Not Exist! ID = " + syn.TemplateID);
}
}
}
private void doSyncUnitsEvent(SyncObjectsEvent msg)
{
foreach (var syn in msg.Objects)
{
doSyncObjectInfo(syn);
}
}
private void doSyncFlagsEvent(SyncFlagsEvent msg)
{
foreach (var kv in msg.ChangedTags)
{
var flag = mFlags.Get(kv.Key);
if (flag != null)
{
flag.Tag = kv.Value;
if (mFlagTagChanged != null)
{
mFlagTagChanged.Invoke(this, flag);
}
}
}
foreach (var flag in mFlags.Values)
{
if (flag is ZoneEditorDecoration)
{
ZoneEditorDecoration ed = flag as ZoneEditorDecoration;
bool enable = !msg.ClosedDecorations.Contains(ed.Name);
if (ed.Enable != enable)
{
ed.Enable = enable;
ed.DecorationChanged();
//doZoneEvent(ZoneEvent.DECORATION_CHANGED, ed);
if (mDecorationChanged != null)
{
mDecorationChanged.Invoke(this, ed);
}
}
}
}
}
private ZoneObject doSyncObjectInfo(SyncObjectInfo syn)
{
ZoneObject ret = GetObject(syn.ObjectID);
if (ret == null)
{
if (syn is SyncUnitInfo)
{
UnitInfo unit = Templates.getUnit(syn.TemplateID);
if (unit != null)
{
unit = unit.Clone() as UnitInfo;
ret = TemplateManager.Factory.CreateClientUnit(this, unit, syn as SyncUnitInfo, null);
}
}
else if (syn is SyncItemInfo)
{
ItemTemplate item = Templates.getItem(syn.TemplateID);
if (item != null)
{
item = item.Clone() as ItemTemplate;
ret = TemplateManager.Factory.CreateClientItem(this, item, syn as SyncItemInfo, null);
}
}
else if (syn is SyncSpellInfo)
{
SpellTemplate spell = Templates.getSpell(syn.TemplateID);
if (spell != null)
{
spell = spell.Clone() as SpellTemplate;
ret = TemplateManager.Factory.CreateClientSpell(this, spell, syn as SyncSpellInfo, null);
}
}
if (ret != null)
{
addObj(ret);
}
else
{
log.Error(string.Format("SyncObject : Can Not Create Object : {0} as {1}", syn.TemplateID, syn));
return null;
}
}
ret.ForceSyncPos(syn.x, syn.y);
ret.Direction = syn.direction;
return ret;
}
private void doAddUnitEvent(AddUnitEvent e)
{
UnitInfo info = Templates.getUnit(e.Sync.TemplateID);
if (info != null)
{
info = info.Clone() as UnitInfo;
ZoneUnit ret = TemplateManager.Factory.CreateClientUnit(this, info, e.Sync, e);
if (addObj(ret))
{
ret.SyncBuffStatus(e.Sync.CurrentBuffStatus);
}
}
}
private void doAddSpellEvent(AddSpellEvent e)
{
SpellTemplate sp = Templates.getSpell(e.spell_template_id);
if (sp != null)
{
sp = sp.Clone() as SpellTemplate;
var syn = new SyncSpellInfo();
syn.ObjectID = e.spell_id;
syn.x = e.x;
syn.y = e.y;
syn.direction = e.direction;
var ret = TemplateManager.Factory.CreateClientSpell(this, sp, syn, e);
ret.Direction = e.direction;
ret.Sender = GetObject(e.sender_unit_id);
if (ret.Sender != null && ret.Sender is ZoneSpell)
{
ret.LaunchHeight = (ret.Sender as ZoneSpell).Z;
}
else
{
ret.LaunchHeight = e.height;
}
ret.Launcher = GetUnit(e.launcher_unit_id);
ret.Target = GetUnit(e.target_obj_id);
ret.TargetPos = e.target_pos;
addObj(ret);
}
else
{
log.Error($"Not found spell template :{e.spell_template_id}");
}
}
private void doAddItemEvent(AddItemEvent e)
{
ItemTemplate item = Templates.getItem(e.Sync.TemplateID);
if (item != null)
{
item = item.Clone() as ItemTemplate;
ZoneItem ret = TemplateManager.Factory.CreateClientItem(this, item, e.Sync, e);
addObj(ret);
}
}
private void doRemoveObjectEvent(RemoveObjectEvent e)
{
removeObj(e.object_id);
}
private void doSyncPosEvent(SyncPosEvent e)
{
bool isDujie = IsSceneDujie();
this.mRemotePassTimeMS = e.PassTimeMS;
this.IsHalfSync = e.IsHalf;
this.IsSyncZ = e.IsSyncZ;
ZoneObject gu;
if (e.units_st != null)
{
for (int i = 0; i < e.units_st.Length; ++i)
{
gu = GetObject(e.units_st[i].ID);
if (gu != null)
{
//YXJDebug.logWarning(">>{0}:{1}>syncState{4}-->x:{2},y:{3}", gu.ObjectID, gu.Name, e.units_st[i].UnitMainState, e.units_st[i].UnitSubState, ((ZoneUnit)gu).CurrentState);
if (isDujie && e.units_st[i].UnitMainState == UnitActionStatus.Move)
{
//YXJDebug.logWarning(">({0}/{1})ignore move state@Dujie scene", gu.ObjectID, gu.Name);
}
else
{
gu.SyncPos(ref e.units_st[i]);
}
}
}
}
if (e.units_pos != null)
{
for (int i = 0; i < e.units_pos.Length; ++i)
{
gu = GetObject(e.units_pos[i].ID);
if (gu != null)
{
//YXJDebug.logWarning(">>{0}:{1}>syncPos({4}), x:{2},y:{3}", gu.ObjectID, gu.Name, e.units_pos[i].X, e.units_pos[i].Y, ((ZoneUnit)gu).CurrentState);
if (isDujie)
{
//YXJDebug.logWarning(">({0}/{1})ignore syncPos@Dujie scene", gu.ObjectID, gu.Name);
}
else
{
gu.SyncPos(ref e.units_pos[i]);
SwapSpace(gu);
}
}
}
}
}
private void doDecorationChanged(DecorationChangedEvent e)
{
var ed = mFlags.Get(e.Name) as ZoneEditorDecoration;
if (ed != null && ed.Enable != e.Enable)
{
ed.Enable = e.Enable;
ed.DecorationChanged();
if (mDecorationChanged != null)
{
mDecorationChanged.Invoke(this, ed);
}
//doZoneEvent(ZoneEvent.DECORATION_CHANGED, ed, e);
}
}
private void doFlagTagChanged(FlagTagChangedEvent e)
{
var flag = mFlags.Get(e.Name);
if (flag != null && flag.Tag != flag.EditorData.Tag)
{
flag.Tag = e.Tag;
if (mFlagTagChanged != null)
{
mFlagTagChanged.Invoke(this, flag);
}
//doZoneEvent(ZoneEvent.DECORATION_CHANGED, ed, e);
}
}
private void doSyncEnvironmentVarEvent(SyncEnvironmentVarEvent e)
{
EnvironmentVarMap[e.Key] = e.Value;
}
private void doChangeBGMEvent(ChangeBGMEvent e)
{
if (mOnChangeBGM != null)
{
mOnChangeBGM.Invoke(this, e.FileName);
}
}
private void doDoScriptEvent(DoScriptEvent e)
{
if (mOnScriptFile != null)
{
mOnScriptFile.Invoke(this, e.ScriptFileName);
}
}
private void doScriptCommandEvent(ScriptCommandEvent e)
{
if (mOnScriptCommand != null)
{
mOnScriptCommand.Invoke(this, e.message);
}
}
private void doGameOver(GameOverEvent evt)
{
if (mGameOver != null)
{
mGameOver.Invoke(this, evt.WinForce == Actor.Force, evt.message);
}
}
#endregion
//-------------------------------------------------------------------------------------------
// #region EVENT_NOTIFY
//
// private void doZoneEvent(ZoneEvent ze, ZoneLayerObject obj = null, IMessage msg = null)
// {
// switch (ze)
// {
// case ZoneEvent.INIT:
//
// break;
// case ZoneEvent.ADD_OBJ:
//
// break;
// case ZoneEvent.REMOVE_OBJ:
//
// break;
// case ZoneEvent.GAME_OVER:
//
// break;
// case ZoneEvent.MESSAGE:
//
// break;
// case ZoneEvent.OBJECT_EVENT:
//
// break;
// case ZoneEvent.DECORATION_CHANGED:
//
// break;
// }
// }
//
// #endregion
//-------------------------------------------------------------------------------------------
#region OBJECTS
private bool addObj(ZoneObject obj)
{
ZoneObject ret = mObjectes.GetObject(obj.ObjectID);
if (ret != null)
{
ret.ForceSyncPos(obj.X, obj.Y);
ret.Direction = obj.Direction;
obj.Dispose();
return false;
}
else
{
mObjectes.Add(obj);
SwapSpace(obj);
obj.OnAdded();
if (mObjectEnter != null)
{
mObjectEnter.Invoke(this, obj);
}
if (obj == mActor)
{
if (mActorAdded != null)
{
mActorAdded.Invoke(this, mActor);
}
mActor.SendReady();
}
return true;
}
}
private void replaceObj(ZoneObject obj)
{
ZoneObject old = mObjectes.RemoveObjectByKey(obj.ObjectID);
if (old != null)
{
old.Dispose();
if (mSpaceDiv != null) mSpaceDiv.ClearSpace(old.mCurrentCellNode);
}
mObjectes.Add(obj);
SwapSpace(obj);
obj.OnAdded();
//doZoneEvent(ZoneEvent.ADD_OBJ, obj, null);
if (mObjectEnter != null)
{
mObjectEnter.Invoke(this, obj as ZoneObject);
}
if (obj == mActor)
{
if (mActorAdded != null)
{
mActorAdded.Invoke(this, mActor);
}
mActor.SendReady();
}
}
private void removeObj(uint objID)
{
ZoneObject ret = mObjectes.RemoveObjectByKey(objID);
if (ret != null)
{
if (mPlayerLeave != null)
{
mPlayerLeave.Invoke(this, ret);
}
ret.Dispose();
if (mSpaceDiv != null) { mSpaceDiv.ClearSpace(ret.mCurrentCellNode); }
//doZoneEvent(ZoneEvent.REMOVE_OBJ, ret, null);
if (mObjectLeave != null)
{
mObjectLeave.Invoke(this, ret);
}
}
}
#endregion
//-------------------------------------------------------------------------------------------
#region REQUEST_RESPONSE
private void check_request_timeout()
{
long curTime = CUtils.CurrentTimeMS;
lock (mListenRequests)
{
if (mListenRequests.Count > 0)
{
using (var removing = ListObjectPool.AllocAutoRelease())
{
foreach (Request req in mListenRequests.Values)
{
if (req.EndTime < curTime)
{
removing.Add(req);
}
}
if (removing.Count > 0)
{
foreach (Request remove in removing)
{
mListenRequests.RemoveByKey(remove.MessageID);
remove.onTimeout();
}
}
}
}
}
}
private bool on_received_response(ActorResponse rsp)
{
Request request = null;
lock (mListenRequests)
{
request = mListenRequests.RemoveByKey(rsp.MessageID) as Request;
}
if (request != null)
{
request.onRecivedMessage(rsp);
return true;
}
return false;
}
private AtomicInteger MessageIDGen = new AtomicInteger(1);
public class Request
{
internal static Logger log = LoggerFactory.GetLogger("ZoneLayer.Request");
private OnResponseHandler mHandler;
private OnRequestTimeoutHandler mTimeout;
public ZoneLayer Layer { get; private set; }
public int TimeOutMS { get; private set; }
public long EndTime { get; private set; }
public long SendTime { get; private set; }
public int MessageID { get; private set; }
public ActorRequest RequestMessage { get; protected set; }
public ActorResponse ResponseMessage { get; protected set; }
public Request(ZoneLayer client, int timeOutMS, ActorRequest request, OnResponseHandler handler = null, OnRequestTimeoutHandler timeout = null)
{
this.Layer = client;
this.MessageID = request.MessageID = client.MessageIDGen.GetAndIncrement();
this.RequestMessage = request;
this.TimeOutMS = timeOutMS;
this.SendTime = CUtils.CurrentTimeMS;
this.EndTime = SendTime + timeOutMS;
this.mHandler = handler;
this.mTimeout = timeout;
}
virtual internal void onRecivedMessage(ActorResponse msg)
{
ResponseMessage = msg;
if (mHandler != null)
{
try
{
mHandler.Invoke(this);
}
catch (Exception err)
{
log.Error(err.Message, err);
}
}
mHandler = null;
mTimeout = null;
}
virtual internal void onTimeout()
{
if (mTimeout != null)
{
try
{
mTimeout.Invoke(this);
}
catch (Exception err)
{
log.Error(err.Message, err);
}
}
mHandler = null;
mTimeout = null;
}
}
public delegate void OnResponseHandler(Request req);
public delegate void OnRequestTimeoutHandler(Request req);
#endregion
//------------------------------------------------------------------------------------
#region TIMING_AND_TASK
private SyncMessageQueueAction mTasks = new SyncMessageQueueAction();
private TimeTaskQueue mTimeTasks = new TimeTaskQueue();
private void doTask(Action task)
{
task(this);
}
///
/// 【线程安全】向主线程排一个任务
///
///
public void QueueTask(Action task)
{
mTasks.Enqueue(task);
}
///
/// 【线程安全】增加时间任务
///
///
///
///
///
public TimeTaskMS AddTimeTask(int intervalMS, int delayMS, int repeat, TickHandler handler)
{
return mTimeTasks.AddTimeTask(intervalMS, delayMS, repeat, handler);
}
///
/// 【线程安全】增加延时回调方法
///
///
///
public TimeTaskMS AddTimeDelayMS(int delayMS, TickHandler handler)
{
return mTimeTasks.AddTimeDelayMS(delayMS, handler);
}
///
/// 【线程安全】增加定时回调方法
///
///
///
public TimeTaskMS AddTimePeriodicMS(int intervalMS, TickHandler handler)
{
return mTimeTasks.AddTimePeriodicMS(intervalMS, handler);
}
#endregion
//-------------------------------------------------------------------------------------------
#region EVENTS
public delegate void OnInitHandler(ZoneLayer layer);
public delegate void OnActorAddedHandler(ZoneLayer layer, ZoneActor actor);
public delegate void OnObjectEnterHandler(ZoneLayer layer, ZoneObject obj);
public delegate void OnObjectLeaveHandler(ZoneLayer layer, ZoneObject obj);
public delegate void OnPlayerLevelHandler(ZoneLayer layer, ZoneObject obj);
public delegate void OnDecorationChangedHandler(ZoneLayer layer, ZoneEditorDecoration ed);
public delegate void OnFlagTagChangedHandler(ZoneLayer layer, ZoneFlag flag);
public delegate void OnMessageReceivedHandler(ZoneLayer layer, IMessage msg);
public delegate void OnObjectMessageReceivedHandler(ZoneLayer layer, IMessage msg, ZoneObject obj);
public delegate void OnGameOverHandler(ZoneLayer layer, bool isWin, string msg);
public delegate void OnScriptCommandHandler(ZoneLayer layer, string msg);
public delegate void OnScriptFileHandler(ZoneLayer layer, string filename);
public delegate void OnChangeBGMHandler(ZoneLayer layer, string filename);
/* 只要不加 event 就不会报错 */
private OnInitHandler mLayerInit;
private OnActorAddedHandler mActorAdded;
private OnObjectEnterHandler mObjectEnter;
private OnObjectLeaveHandler mObjectLeave;
private OnDecorationChangedHandler mDecorationChanged;
private OnFlagTagChangedHandler mFlagTagChanged;
private OnMessageReceivedHandler mMessageReceived;
private OnObjectMessageReceivedHandler mObjectMessageReceived;
//本地外部临时数据(用于跨服战),由于先断数据层,再清渲染层会导致外部临时数据清理的时候出错
private OnPlayerLevelHandler mPlayerLeave;
private OnGameOverHandler mGameOver;
private OnScriptCommandHandler mOnScriptCommand;
private OnScriptFileHandler mOnScriptFile;
private OnChangeBGMHandler mOnChangeBGM;
[EventTriggerDescAttribute("客户端场景初始化时触发")]
public event OnInitHandler LayerInit { add { mLayerInit += value; } remove { mLayerInit -= value; } }
[EventTriggerDescAttribute("主角被添加时触发")]
public event OnActorAddedHandler ActorAdded { add { mActorAdded += value; } remove { mActorAdded -= value; } }
[EventTriggerDescAttribute("单位进入场景")]
public event OnObjectEnterHandler ObjectEnter { add { mObjectEnter += value; } remove { mObjectEnter -= value; } }
[EventTriggerDescAttribute("玩家离开场景")]
public event OnPlayerLevelHandler PlayerLeave { add { mPlayerLeave += value; } remove { mPlayerLeave -= value; } }
[EventTriggerDescAttribute("单位离开场景")]
public event OnObjectLeaveHandler ObjectLeave { add { mObjectLeave += value; } remove { mObjectLeave -= value; } }
[EventTriggerDescAttribute("空气墙变化时触发")]
public event OnDecorationChangedHandler DecorationChanged { add { mDecorationChanged += value; } remove { mDecorationChanged -= value; } }
[EventTriggerDescAttribute("Flag Tag 变化时触发")]
public event OnFlagTagChangedHandler FlagTagChanged { add { mFlagTagChanged += value; } remove { mFlagTagChanged -= value; } }
[EventTriggerDescAttribute("接收网络消息")]
public event OnMessageReceivedHandler MessageReceived { add { mMessageReceived += value; } remove { mMessageReceived -= value; } }
[EventTriggerDescAttribute("接收Object网络消息")]
public event OnObjectMessageReceivedHandler ObjectMessageReceived { add { mObjectMessageReceived += value; } remove { mObjectMessageReceived -= value; } }
[EventTriggerDescAttribute("BGM发生变化时触发")]
public event OnChangeBGMHandler OnChangeBGM { add { mOnChangeBGM += value; } remove { mOnChangeBGM -= value; } }
[EventTriggerDescAttribute("游戏结束")]
public event OnGameOverHandler GameOver { add { mGameOver += value; } remove { mGameOver -= value; } }
[EventTriggerDescAttribute("服务端通知客户端执行指定脚本代码")]
public event OnScriptCommandHandler OnScriptCommand { add { mOnScriptCommand += value; } remove { mOnScriptCommand -= value; } }
[EventTriggerDescAttribute("服务端通知客户端执行指定脚本文件")]
public event OnScriptFileHandler OnScriptFile { add { mOnScriptFile += value; } remove { mOnScriptFile -= value; } }
private void clearEvents()
{
this.mLayerInit = null;
this.mActorAdded = null;
this.mObjectEnter = null;
this.mObjectLeave = null;
this.mDecorationChanged = null;
this.mFlagTagChanged = null;
this.mMessageReceived = null;
this.mObjectMessageReceived = null;
this.mGameOver = null;
this.mOnScriptCommand = null;
this.mOnScriptFile = null;
this.mOnChangeBGM = null;
this.mPlayerLeave = null;
}
#endregion
}
}