using CommonAI.Zone; using CommonAI.ZoneClient; using CommonLang; using ET.Client; using ET.EventType; using ET.Server; using Sirenix.Utilities; using System; using System.IO; using System.Linq; using UnityEngine; using XmdsCommon.Message; using XmdsCommon.Plugin; namespace ET { [FriendOf(typeof(UnitMgr))] public partial class BattleMgr : Singleton, ISingletonAwake, ISingletonUpdate, ILayerClient { public ZoneLayer Layer; private readonly MemoryStream writeBuffer = new MemoryStream(2048); private EventDispatcher eventHandler; private static CommonLang.Geometry.Vector3 vecTemp = new(); private HashMap UnitTemplateIdHash = new(); public void Awake() { eventHandler = new(); registerEventHandler(); Layer = TemplateManager.Factory.CreateClientZoneLayer(BattleResourceMgr.Instance.GameEditorTemplates, this); Layer.ActorSyncMode = SyncMode.ForceByServer; Layer.LayerInit += LayerEvent_Init; Layer.ObjectEnter += LayerEvent_ObjectEnter; Layer.ObjectLeave += LayerEvent_ObjectLeave; Layer.MessageReceived += (ZoneLayer _, CommonLang.Protocol.IMessage msg) => { /*if (msg is SyncPosEvent || msg is UnitForceSyncPosEvent || msg is LaunchSkill || msg is AddSpellEvent || msg is RemoveObjectEvent || msg is AddUnitEvent || msg is PlayerFocuseTargetEvent || msg is UnitFieldChangedEvent || msg is UnitEffectEvent || msg is UnitLaunchSkillEvent || msg is PlayerSkillStopEvent || msg is UnitHitEvent || msg is UnitLaunchBuffEvent) { } else { Log.Debug($"<< { Log.Error("not implements: DecorationChanged"); };*/ } public void Update(int timeMS) { //TODO: Send ping Layer.BeginUpdate(timeMS); Layer.Update(); this.doUpdate(); KeyboardCheckUpdate(); } private void KeyboardCheckUpdate() { for(var i = KeyCode.F1; i < KeyCode.F13; i++) { if(Input.GetKeyDown((KeyCode)i)) { EventSystem.Instance.Publish(BattleFunc.Static.Clone((int)i)); } } } //ILayerClient接口实现,供layer层调用 //layer层在收到LockActorEvent消息后调用 void ILayerClient.BattleReady(bool bok) { Log.Debug($"battle ready......{bok}"); //TODO: 等GameObjectPool.cache完场景资源后,再play bgm var scnData = Layer.Data; if(!scnData.BGM.IsNullOrWhitespace() ) { EventSystem.Instance.Publish(PlayBgm.Static.Clone(true, scnData.BGM)); } } //ILayerClient接口实现,供layer层调用 //layer层中需要发送消息到战斗服 public void SendAction(CommonAI.Zone.Action action) { if(PlayerComponent.Instance == null) { Log.Error("playerComponent is null"); return; } Log.Debug($">>>Send BattleMsg: {action.GetType()}"); writeBuffer.Position = 0; if (BattleResourceMgr.Instance.BattleMsgDecoder.doEncode(writeBuffer, action)) { PlayerComponent.Instance.ClientScene().GetComponent().Session.Send(new BattleEventPushToServer() { data = writeBuffer.ToArray() }); } } //客户端自己模拟创建消息,发送到zonelayer层处理 public void PostMsg2Layer(CommonLang.Protocol.IMessage msg) { Layer.ProcessMessage(msg); } //layer层在处理好战斗服推送的ClientEnterScene消息后回调 protected void LayerEvent_Init(CommonAI.ZoneClient.ZoneLayer layer) { Log.Debug($"OnLayerInit- scene template ID:{layer.Data.ID}"); } //单位进入战斗 protected void LayerEvent_ObjectEnter(ZoneLayer layer, ZoneObject obj) { var unit = BattleUnitFactory.Instance.Create(obj); if(unit != null ) { UnitMgr.Instance.PutUnit(obj.ObjectID, unit); if (unit is BattleActor) { UnitMgr.Instance.Actor = unit as BattleActor; } unit.OnAwake(obj); if (unit is BattleUnit bu) { var tid = (obj as ZoneUnit).TemplateID; if (ConstGame.TowerTemplateIDs.Contains(tid)) { if (UnitTemplateIdHash.ContainsKey((tid))) { Log.Error($"Already exist unit({tid}) @{obj.ObjectID}"); return; } UnitTemplateIdHash.Add(tid, bu); } //Log.Debug($"OnObjectEnter: {bu.ZUnit.TemplateID}@{obj.ObjectID}"); if(bu.ZUnit.Info.Properties is XmdsUnitProperties prop && prop.GameStatusType == XmdsUnitProperties.StatusType.SpecialBoss) { EventSystem.Instance.Publish(BattleMsgEvent.Static.Clone($"发现怪兽:'{prop.ServerData.BaseInfo.name}',你过来啊!")); } } } } //单位离开战斗 protected void LayerEvent_ObjectLeave(ZoneLayer layer, ZoneObject obj) { //Log.Debug($"OnObjectLeave: {obj.ObjectID}"); var unit = UnitMgr.Instance.GetUnit(obj.ObjectID); if(unit == null) { Log.Error($"LayerEvent_ObjectLeave not exist:{obj.Name}:{obj.ObjectID}"); return; } unit.OnSleep(); UnitMgr.Instance.RemoveUnit(obj.ObjectID); if (unit is BattleUnit bu) { UnitTemplateIdHash.Remove(bu.ZUnit.TemplateID); } } public BattleUnit GetUnitByTemplateID(int tid) { return UnitTemplateIdHash.ContainsKey(tid) ? UnitTemplateIdHash[tid] : null; } private void registerEventHandler() { //actor=================== eventHandler.AddListener((ev) => { var isAutoFight = (ev as SetAutoBattleB2C).isAutoBattle != 0; Log.Debug($"AutoFight: {isAutoFight}"); (UnitMgr.Instance.Actor.ZUnit as ZoneActor).IsGuard = isAutoFight; }); eventHandler.AddListener((ev) => { }); eventHandler.AddListener((ev) => { var e = ev as UnitHitBreak; var unit = UnitMgr.Instance.GetUnit(e.ObjectID); if (unit != null && unit is BattleUnit bunit) { var launcheffect = bunit.ZUnit.Info.HitBreakEffect; if (launcheffect != null) { EventSystem.Instance.Publish(PlayEffectEvent.Static.Clone(launcheffect, unit.Id, CommonLang.Geometry.Vector3.Zero)); } if (bunit.ZUnit.Info.Properties is XmdsUnitProperties prop) { EventSystem.Instance.Publish(BattleMsgEvent.Static.Clone($"'{prop.ServerData.BaseInfo.name}'受到了怪物的猛烈攻击")); } } }); eventHandler.AddListener((ev) => { }); eventHandler.AddListener((ev) => { var e = ev as UnitDeadEvent; //Log.Debug($"Unit({e.object_id}) dead"); var unit = UnitMgr.Instance.GetUnit(e.ObjectID); if(unit != null && unit is BattleUnit bunit) { EventSystem.Instance.Publish(PlayAnimatorEvent.Clone( e.ObjectID, AnimatorEventType.Dead)); var launcheffect = bunit.ZUnit.Info.DeadEffect; if (launcheffect != null) { if (launcheffect.BindBody) { vecTemp.Set(0, 0, 0); } else { vecTemp.Set(unit.ZoneObject.X, unit.ZoneObject.Y, unit.ZoneObject.Z); } EventSystem.Instance.Publish(PlayEffectEvent.Static.Clone(launcheffect, unit.Id, vecTemp)); } //TODO: 在死亡动作播放完毕之后播放此特效 launcheffect = bunit.ZUnit.Info.DeadAnimationEndEffect; if (launcheffect != null) { vecTemp.Set(unit.ZoneObject.X, unit.ZoneObject.Y, unit.ZoneObject.Z); EventSystem.Instance.Publish(PlayEffectEvent.Static.Clone(launcheffect, unit.Id, vecTemp)); } if (bunit.ZUnit.Info.Properties is XmdsUnitProperties prop) { if (prop.GameStatusType == XmdsUnitProperties.StatusType.SpecialElite) { EventSystem.Instance.Publish(BattleMsgEvent.Static.Clone($"'{prop.ServerData.BaseInfo.name}'失去了所有能量")); } else if(prop.GameStatusType == XmdsUnitProperties.StatusType.SpecialBoss) { EventSystem.Instance.Publish(BattleMsgEvent.Static.Clone($"'{prop.ServerData.BaseInfo.name}',被打的倒地不起")); } } } }); eventHandler.AddListener((ev) => { }); eventHandler.AddListener((ev) => { var e = ev as UnitHitEvent; var unit = UnitMgr.Instance.GetUnit(e.ObjectID); if(unit == null) { Log.Warning($"Ignore unit({e.ObjectID}) on hit, not exist?"); return; } if (e.dmgSrc == CommonAI.Data.DamageSource.RemedyPoison) { //伤害来源于叠毒BUFF e.client_state = (byte)UnitHitEventState.PoisonBuff; } //TODO: 显示伤害飘字 LaunchEffect hitEffect = e.effect; if (hitEffect != null) { float roation = 0f; if (hitEffect.IsSyncSenderRotation) { //设置特效的rotation为施法者与受击连线方向的rotation var sender = UnitMgr.Instance.GetUnit(e.senderId); if (sender != null) { UnityEngine.Vector3 difpos = new UnityEngine.Vector3(unit.ZoneObject.X, unit.ZoneObject.Y, 0) - new UnityEngine.Vector3(sender.ZoneObject.X, sender.ZoneObject.Y, 0); roation = (float)-Math.Atan2(-difpos.y, difpos.x); } } if (hitEffect.BindBody) { vecTemp.Set(0, 0, 0); } else { vecTemp.Set(unit.ZoneObject.X, unit.ZoneObject.Y, unit.ZoneObject.Z); } EventSystem.Instance.Publish(PlayEffectEvent.Static.Clone(hitEffect, e.ObjectID, vecTemp, roation)); } }); eventHandler.AddListener((ev) => { //TODO:替代virtual层 var e = ev as PlayerPKModeChangeEventB2C; Log.Debug($"PKMode: {e.CurMode}"); }); eventHandler.AddListener((ev) => { }); eventHandler.AddListener((ev) => { }); eventHandler.AddListener((ev) => { }); eventHandler.AddListener((ev) => { var e = ev as UnitEffectEvent; vecTemp.Set(0,0,0); var unit = UnitMgr.Instance.GetUnit(e.object_id); if (unit != null && !e.effect.BindBody) { vecTemp.Set(unit.ZoneObject.X, unit.ZoneObject.Y, unit.ZoneObject.Z); } EventSystem.Instance.Publish(PlayEffectEvent.Static.Clone(e.effect, e.ObjectID, vecTemp)); if(e.effect.Name == "chuanyunjian01") { if (unit is BattleUnit bu && bu.ZUnit.Info.Properties is XmdsUnitProperties prop) { EventSystem.Instance.Publish(BattleMsgEvent.Static.Clone($"'{prop.ServerData.BaseInfo.name}'快要支撑不住了,宝宝们快来注入能量")); } } }); eventHandler.AddListener((ev) => { }); //NPCCureEventB2C //MonsterSufferDamageInfoB2C //BattleHintNumberB2C //BattleFloatTipsEventB2C //BubbleTipsEventB2C //怪物归属权 //MonsterHeirInfoChangeEventB2C eventHandler.AddListener((ev) => { var e = ev as GameOverEvent; EventSystem.Instance.Publish(GameoverEvent.Static.Clone(e.WinForce)); }); eventHandler.AddListener((ev) => { var e = ev as CameraMoveToEvent; EventSystem.Instance.Publish(CameraEvent.Static.Clone(e.x, e.height, e.y, e.TimeMS, e.MoveSpeedSec)); }); eventHandler.AddListener((ev) => { var e = ev as AddEffectEvent; if(e.hostId == 0 || UnitMgr.Instance.HasUnit(e.hostId)) { vecTemp.Set(e.x, e.y, 0); EventSystem.Instance.Publish(PlayEffectEvent.Static.Clone(e.effect, e.hostId, vecTemp)); } }); eventHandler.AddListener((ev) => { var e = ev as ClientMsgEvent; Log.Debug($">>>Battle client event: {e.Message}"); /*if(e.Message == BattleNotify.CameraOk.ToString() ) { }*/ }); /*BubbleTalkEvent AddEffectEvent SyncEnvironmentVarEvent ScriptCommandEvent ScriptAddUnitEventsB2C ScriptRemoveUnitEventsB2C PlaySoundEventB2CForAll SyncFlagsEvent ChangeBGMEvent PlayDestoryEffect*/ /*var e = msg as CommonAI.Zone.CommonAI.Zone.Event; if (e is ChatEvent) { var evt = (e as ChatEvent); var message = evt.Message; var evt_param = message.Split('|'); if (evt_param.Length >= 2 && evt_param[0] == "Notice.Msg") { var dic = GameUtil.GetDBData("NoticeMsg", int.Parse(evt_param[1])); if (dic != null) { string result = ""; if (evt_param.Length >= 3 && evt_param[2] != null) { //根据参数个数 依次填值 string[] par = evt_param[2].Split('.'); if (par != null && par.Length > 0) { switch (par.Length) { case 1: { result = Average(dic["MsgContent"] as string, par[0]); break; } case 2: { result = Average(dic["MsgContent"] as string, par[0], par[1]); break; } case 3: { result = Average(dic["MsgContent"] as string, par[0], par[1], par[2]); break; } case 4: { result = Average(dic["MsgContent"] as string, par[0], par[1], par[2], par[3]); break; } case 5: { result = Average(dic["MsgContent"] as string, par[0], par[1], par[2], par[3], par[4]); break; } } } } else { //没有参数 result = (dic["MsgContent"] as string); } // EventManager.Fire("CommonAI.Zone.Event.OnEventHandler.star", new Dictionary() { {"content", result}, {"keepTime", "" + (evt.KeepTimeMS/1000)}, {"content_is_text", "true"} }); } else { YXJDebug.logError("config not exist >" + msg); } } else if (evt_param.Length == 2) { string funcName = "GlobalHooks." + evt_param[0]; object[] param = evt_param[1].Split(','); //Client.GetMainState().GetFunction(funcName).LazyCall(param); if (param.Length == 0) Client.GetMainState().Call(funcName, Client.LogMiss); else if (param.Length == 1) Client.GetMainState().Call(funcName, param[0], Client.LogMiss); else if (param.Length == 2) Client.GetMainState().Call(funcName, param[0], param[1], Client.LogMiss); else if (param.Length == 3) Client.GetMainState().Call(funcName, param[0], param[1], param[2], Client.LogMiss); else if (param.Length == 4) Client.GetMainState().Call(funcName, param[0], param[1], param[2], param[3], Client.LogMiss); else if (param.Length == 5) Client.GetMainState().Call(funcName, param[0], param[1], param[2], param[3], param[4], Client.LogMiss); else { YXJDebug.logError("BattleClientBase.OnEventHandler Error!funcName is {0}", funcName); } } else { //位面进入退出效果 if (msg == "EnterAOI") { var wwe = Camera.main.GetComponent(); if (wwe != null) { wwe.SetParam(40, -30, 3, 2); wwe.play(); } //GameAlertManager.Instance.setAutoAnimiVisible(false); InAOI = true; } else if (msg == "LeaveAOI") { var wwe = Camera.main.GetComponent(); if (wwe != null) { wwe.SetParam(40, -30, 3, 2); wwe.play(); } InAOI = false; } else { //普通chatevent EventManager.Fire("CommonAI.Zone.Event.OnEventHandler.star", new Dictionary() { {"content", msg}, {"isImportant", "1"}, {"keepTime", "" + (evt.KeepTimeMS/1000)} }); } } } else if (e is CommonAI.Zone.ZoneEvent) { if (e is BubbleTalkEvent) { BubbleTalkEvent evt = e as BubbleTalkEvent; if (evt.TalkInfos != null) { foreach (var info in evt.TalkInfos) { System.Action callback = delegate () { if (info.TalkUnit == 0) { YXJDebug.logError("旁白气泡还没有实现>{0}", info.TalkContent); return; } ComAIUnit unit = GetUnitById(info.TalkUnit) as ComAIUnit; if (unit == null) { if (info.TalkContent != "bubblechat") { YXJDebug.logDebug(">BubbleTalkEvent unit not exist: {0}>>{1}", info.TalkUnit, info.TalkContent); } return; } if (info.TalkContent == "bubblechat") { UIBridgeManager.Instance.QuestUIBridge.BubbleTalkEventSend(unit); } else { var txt = ConfigMgr.Instance.TxtCfg.GetTextByKey("GameEditor_" + info.TalkContent); unit.AddBubbleChat(txt, info.TalkKeepTimeMS / 1000); } if (!string.IsNullOrEmpty(info.TalkActionType)) { unit.PlayAnimationWhileIdle(info.TalkActionType); } }; if (info.TalkDelayTimeMS > 0) { GameGlobal.Instance.StartCoroutine(WaitForSeconds(info.TalkDelayTimeMS / 1000, callback)); } else { callback.Invoke(); } } } } else if (e is AddEffectEvent && battleManager != null) { AddEffectEvent evt = e as AddEffectEvent; if (evt.hostId == 0 || GetUnitById(evt.hostId) != null) { Vector3 pos = battleManager.GetU3DPosByUnitCell(evt.x, evt.y); pos = ComAICell.AdjustHeight(pos); Quaternion rotation = Quaternion.Euler(0, evt.direction * Mathf.Rad2Deg + 90, 0); EffectPlayer.SetRotationOnetime(rotation); //--->这个功能加个参数不就好了 →_→ EffectPlayer.Play(evt.effect, pos, false); } } else if (e is AddEffectEvent2 && battleManager != null) { AddEffectEvent2 evt = e as AddEffectEvent2; if (evt.hostId == 0 || GetUnitById(evt.hostId) != null) { Vector3 pos = battleManager.GetU3DPosByUnitCell(evt.x, evt.y); pos = ComAICell.AdjustHeight(pos); Vector3 targetPos = battleManager.GetU3DPosByUnitCell(evt.TargetX, evt.TargetY); EffectPlayer.PlayLocal(evt.effect, pos, false, 0, 0, 0, 0, evt.ET, targetPos, evt.FollowActor); } } else if (e is SyncEnvironmentVarEvent) { SyncEnvironmentVarEvent evt = e as SyncEnvironmentVarEvent; UIBridgeManager.Instance.BattleUIBridge.EnvironmentVarChange(evt.Key, evt.Value); } else if (e is ScriptCommandEvent) { ScriptCommandEvent evt = e as ScriptCommandEvent; string[] evt_param = evt.message.Split('|'); if (evt_param.Length == 2) { object[] param = evt_param[1].Split(','); string funcName = "GlobalHooks." + evt_param[0]; if (param.Length == 0) Client.GetMainState().Call(funcName, Client.LogMiss); else if (param.Length == 1) Client.GetMainState().Call(funcName, param[0], Client.LogMiss); else if (param.Length == 2) Client.GetMainState().Call(funcName, param[0], param[1], Client.LogMiss); else if (param.Length == 3) Client.GetMainState().Call(funcName, param[0], param[1], param[2], Client.LogMiss); else if (param.Length == 4) Client.GetMainState().Call(funcName, param[0], param[1], param[2], param[3], Client.LogMiss); else if (param.Length == 5) Client.GetMainState().Call(funcName, param[0], param[1], param[2], param[3], param[4], Client.LogMiss); else { YXJDebug.logError("BattleClientBase.OnEventHandler Error!funcName is {0}", funcName); } } } else if (e is LockActorEvent) { LockActorEvent evt = e as LockActorEvent; OnLockActorEvent(evt); } else if (e is ScriptAddUnitEventsB2C) { ScriptAddUnitEventsB2C evt = e as ScriptAddUnitEventsB2C; OnScriptAddUnitEvent(evt); } else if (e is ScriptRemoveUnitEventsB2C) { ScriptRemoveUnitEventsB2C evt = e as ScriptRemoveUnitEventsB2C; OnScriptRemoveUnitEvents(evt); } else if (e is PlaySoundEventB2CForAll) { PlaySoundEventB2CForAll evt = e as PlaySoundEventB2CForAll; XmdsSoundManager.GetXmdsInstance().PlaySound(evt.SoundName); } else if (e is SyncFlagsEvent && mDecoMgr != null) { mDecoMgr.LoadDecos(); } else if (e is ChangeBGMEvent) { XmdsSoundManager.GetXmdsInstance().ChangeBGM((e as ChangeBGMEvent).FileName); } else if (e is PlayDestoryEffect) { if (EffectPlayer == null) return; PlayDestoryEffect destoryEffect = e as PlayDestoryEffect; Vector3 vec = new Vector3(destoryEffect.X, destoryEffect.Y, destoryEffect.Z); Quaternion rotation = Quaternion.Euler(0, destoryEffect.Direction * Mathf.Rad2Deg + 90, 0); LaunchEffect effect = new LaunchEffect(); effect.Name = destoryEffect.EffectName; EffectPlayer.SetRotationOnetime(rotation); EffectPlayer.Play(effect, vec, true); } else { //YXJDebug.logInfo("OnEventHandler not implemented! {0}", e.ToString()); } }*/ } } }