using CommonAI.Zone;
using CommonAI.Zone.Instance;
using CommonAI.ZoneServer;
using CommonLang;
using CommonLang.ByteOrder;
using CommonLang.Concurrent;
using CommonLang.IO;
using CommonLang.IO.Attribute;
using CommonLang.Property;
using CommonLang.Protocol;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using XmdsCommon.Message;
using XmdsCommon.Plugin;
using XmdsCommonServer.Message;
using XmdsCommonServer.Plugin;
using XmdsServerNode.Node.Interface;
using CommonAIServer.Node;
using CommonAI.ZoneClient;
using XmdsCommonServer.Plugin.Units;
using XmdsCommonServer.Plugin.Scene;
using CommonAI.Zone.ZoneEditor;
using System.Dynamic;
using XmdsServerNode.CheatingDeath;
using Pomelo;
using System.Web.Helpers;
using static CommonAI.XmdsConstConfig;
using CommonAI.Zone.Helper;
using CommonAI.Data;
namespace XmdsServerNode.Node
{
public class ServerZoneNode : CommonAIServer.Node.ZoneNode
{
private GameOverEvent mGameOver = null;
public bool PauseOnNoPlayer { get; set; }
public string UUID { get { return Zone.UUID; } }
public bool IsGameOver { get { return mGameOver != null; } }
public ICEZoneSession Callback;
private readonly string BindGameServerId;
public ServerZoneNode(string gameServerId) : base(ZoneNodeManager.Templates, ZoneNodeManager.NodeConfig)
{
this.BindGameServerId = gameServerId;
PauseOnNoPlayer = false;
}
public string GetBindGameSrvId()
{
return this.BindGameServerId;
}
///
/// 房间初始化
///
public void Start(string instanceID, int scene_id, string monsterHard, byte allowAutoGuard, bool calPKValue,
int average_level, double monsterAddPropPercentWithFloor, double monsterAddPropRatioWithLv, int killInterval,
int killMax, int killMaxCoolTime, bool usespaceDiv, CommonAI.Data.SceneType scenetype, GSCreateAreaData areaData,
CommonAI.XmdsConstConfig.AreaType areaType, bool isteam = false, bool canRiding = true)
{
try
{
var sd = base.DataRoot.LoadScene_Server(scene_id, true, false);
sd.DefaultUnitLevel = average_level;
sd.MonsterAddPropPercentWithFloor = monsterAddPropPercentWithFloor;
sd.MonsterAddPropRatioWithLv = monsterAddPropRatioWithLv;
sd.canRiding = canRiding;
sd.killInterval = killInterval;
sd.killMax = killMax;
sd.killMaxCoolTime = killMaxCoolTime;
sd.isTeam = isteam;
sd.sceneType = scenetype;
XmdsSceneProperties zsp = sd.Properties as XmdsSceneProperties;
XmdsServerSceneData sceneData = new XmdsServerSceneData();
sceneData.AllowAutoGuard = allowAutoGuard;
sceneData.CalPKValue = calPKValue;
sceneData.SceneHard = monsterHard;
sceneData.UsespaceDiv = usespaceDiv;
sceneData.CurAreaType = areaType;
zsp.ServerSceneData = sceneData;
base.Start(sd, areaData, this.BindGameServerId);
base.Zone.UUID = instanceID;
}
catch (System.Exception e)
{
throw new Exception(string.Format("scene {0} start error : {1}", scene_id, e.ToString()), e);
}
}
public void QueueTaskAsync(System.Action action)
{
base.QueueTask(() =>
{
action(base.Zone);
});
}
public void QueueTaskAsync(System.Action action)
{
base.QueueTask(() =>
{
action();
});
}
public void SendToGameServer(string name, Object param)
{
if (Callback == null)
{
this.Callback = IceManager.instance().getCallback(this.BindGameServerId);
log.Warn("SendToGameServer callback - 1 - null : " + this.BindGameServerId + ", name:" + name + ", data:" + param);
}
string json = null;
if (Callback != null && Callback.callback != null)
{
try
{
json = Json.Encode(param);
Callback.callback.eventNotify(name, json);
}
catch (Exception err)
{
if(json == null)
{
log.Error("SendToGameServer序列化就异常了,放弃记录:" + name + ", err:" + err.Message, err);
}
else
{
Callback.notifyFailData.Enqueue(new ICENotifyData(name, json));
log.Error("SendToGameServer: " + name + ", err:" + err.Message, err);
EventNotifyFail();
}
}
}
else
{
log.Warn("SendToGameServer callback - 2- null : " + this.BindGameServerId + ", name:" + name + ", data:" + param);
}
}
private void EventNotifyFail()
{
try
{
if (Callback.callback.ice_getCachedConnection() == null)
{
Callback.failTimes++;
if (Callback.fastSession != null/* && Callback.failTimes >= 3*/)
{
Callback.fastSession.doClose();
Callback.failTimes = 0;
log.Warn("EventNotifyFail 重置连接: " + Callback.fastSession.GetDescribe());
}
else
{
log.Error("EventNotifyFail fastSession null:" + Callback.callback.ToString());
}
}
}
catch (System.Exception e)
{
log.Error("EventNotifyFail catch:" + e);
}
}
//------------------------------------------------------------------------------------------------------------
#region _主线程内回调_线程安全_
public override bool ZoneUpdate(int intervalMS)
{
if (PauseOnNoPlayer && base.PlayerCount == 0) { intervalMS = 0; }
return base.ZoneUpdate(intervalMS);
}
//过滤游戏场景推送出的消息//
protected override bool OnMessageHandlerFromInstanceZone(Event e)
{
//战斗服To游戏服.
if (e is MessagePlayerEventB2R)
{
e.sender = null;
var msg = e as MessagePlayerEventB2R;
msg.eventName = e.GetType().Name;
SendToGameServer("playerEvent", e);
return true;
}
else if (e is MessageZoneEventB2R)
{
e.sender = null;
var msg = e as MessageZoneEventB2R;
msg.eventName = e.GetType().Name;
SendToGameServer("zoneEvent", e);
return true;
}
else if(e is MessageMapEventB2R)
{
var msg = e as MessageMapEventB2R;
msg.eventName = e.GetType().Name;
SendToGameServer("mapNotify", e);
return true;
}
else if (e is GameOverEvent)
{
if (mGameOver == null)
{
mGameOver = e as GameOverEvent;
var eventParam = new
{
eventName = "gameOver",
instanceId = this.UUID,
winForce = mGameOver.WinForce
};
SendToGameServer("areaEvent", eventParam);
}
}
return false;
}
protected override void OnEndUpdate()
{
base.ForEachPlayers((c) =>
{
var zone_client = c.Client as ZoneNodePlayer;
zone_client.Flush();
});
}
protected override void OnPlayerEntered(PlayerClient client)
{
base.OnPlayerEntered(client);
CheatingDeath.CheatingDeathManager.OnPlayerEnter(client.Actor);
//进去默认自动战斗的情况下
if(this.SceneData.Properties.GetAutoFightFlag() == 3 && !client.Actor.IsGuard)
{
client.Actor.doEnterAutoFight();
}
client.Actor.Virtual.doEvent(JSGCustomOpType.UpdateAutoBattleFlag);
}
protected override void OnPlayerLeft(PlayerClient client)
{
base.OnPlayerLeft(client);
this.KillPlayerAOIObjects(client);
}
//干掉所有和玩家同一位面单位//
protected void KillPlayerAOIObjects(PlayerClient client)
{
var player = client.Actor;
if (player != null && player.AoiStatus != null)
{
var src_aoi = player.AoiStatus as XmdsPlayerAOI;
if (src_aoi.Owner == player)
{
src_aoi.Cleanup();
}
}
}
#endregion
//------------------------------------------------------------------------------------------------------------
#region _游戏服控制玩家_
///
/// 单位进入场景
///
///
///
public void OnPlayerEnter(IPlayer player, PlayerEnterRoomS2R enter, Action callback, Action callerror)
{
if (enter == null)
{
// 建立绑定关系 //
var zone_player = new ZoneNodePlayer(this, player);
base.PlayerEnter(zone_player, null, 0, 0, 0, null,0, callback, callerror);
}
else
{
// 有出生点则放入出生点 //
CommonLang.Vector.Vector2 enterPos = enter.Pos;
if (enterPos.X == 0 && enterPos.Y == 0)
{
enterPos = null;
}
if (!string.IsNullOrEmpty(enter.FlagName))
{
InstanceFlag p = Zone.getFlag(enter.FlagName);
if(p != null)
{
if (p is ZoneRegion)
{
// Region随机取一个坐标
var pos = (p as ZoneRegion).getRandomPos(Zone.RandomN);
enterPos.SetX(pos.X);
enterPos.SetY(pos.Y);
}
else
{
enterPos = p.Pos;
}
}
}
UnitInfo temp = ZoneNodeManager.Templates.Templates.getUnit(enter.UnitData.UnitTemplateID);
if (temp != null)
{
temp = temp.Clone() as UnitInfo;
temp.UType = UnitInfo.UnitType.TYPE_PLAYER;
XmdsUnitProperties tprop = (temp.Properties as XmdsUnitProperties);
//临时代码.
//默认无限等待.
temp.RebirthTimeMS = int.MaxValue;
// 插入玩家能力属性 //
tprop.ServerData = ((enter.UnitData.UnitPropData) as XmdsUnitProperties).ServerData;
// 建立绑定关系 //
var zone_player = new ZoneNodePlayer(this, player);
base.PlayerEnter(zone_player, temp, enter.UnitData.Force, enter.UnitData.alliesForce,
tprop.ServerData.BaseInfo.UnitLv, enterPos,enter.direction, callback, callerror);
}
else
{
throw new Exception("Unit template not exist : " + enter);
}
}
}
///
/// 单位离开场景
///
///
public void OnPlayerLeave(InstancePlayer player, Action callback, Action callerror, bool keep_object = false)
{
if (player != null)
{
base.PlayerLeave(player, callback, callerror, keep_object);
}
}
///
/// 玩家网络状况改变
///
///
///
public void OnPlayerNetStateChanged(IPlayer player, string state)
{
QueueTask(() =>
{
var zc = player.BindingObject;
if (zc != null)
{
zc.NetStateChanged(state);
}
});
}
///
/// 单位收到来自客户端的消息
///
///
///
public void OnPlayerReceivedMessage(IPlayer player, byte[] msg)
{
QueueTask(() =>
{
//if (doDecodePing(player, msg))
//{
// return;
//}
//else
{
var zone_player = player.BindingObject;
if (zone_player != null)
{
zone_player.Recv(msg);
}
}
});
}
public void ReceiveMsgR2B(IPlayer client, object status)
{
QueueTask(() =>
{
var zc = client.BindingObject;
if (zc != null && zc.BindingActor != null)
{
XmdsVirtual zv = (XmdsVirtual)zc.BindingActor.Virtual;
zv.ReceiveMsgR2B(status);
}
});
}
///
/// 玩家复活,分原地复活和复活点复活
///
///
///
public void OnHelpPlayerRebirth(IPlayer player, IPlayer revivePlayer, int time)
{
QueueTask(() =>
{
var p = player.BindingObject;
var r = revivePlayer.BindingObject;
if (p != null && r != null && p.BindingActor != null && r.BindingActor != null)
{
PlayerSaveEventR2B r2b = new PlayerSaveEventR2B();
XmdsVirtual Decedent = (XmdsVirtual)(r.BindingActor).Virtual;
XmdsVirtual Saver = (XmdsVirtual)(p.BindingActor).Virtual;
r2b.Decedent = Decedent.mUnit;
r2b.Saver = Saver.mUnit;
r2b.SaveTime = time;
Saver.ReceiveMsgR2B(r2b);
}
});
}
public void OnPlayerReadyR2B(IPlayer client)
{
QueueTask(() =>
{
InstancePlayer out_player;
PlayerClient out_client;
if (GetPlayerAndClient(client.PlayerUUID, out out_player, out out_client))
{
if (out_player != null && out_client != null)
{
(out_player as XmdsInstancePlayer).PlayerReady();
}
}
});
}
public void OnPlayerReviveTeamInfoEventR2B(IPlayer client, TeamInfoEventR2B team)
{
QueueTask(() =>
{
InstancePlayer out_player;
PlayerClient out_client;
if (GetPlayerAndClient(client.PlayerUUID, out out_player, out out_client))
{
if (out_player != null && out_client != null)
{
(out_client as BindingPlayerClient).OnPlayerReviveTeamInfoEventR2B(team);
var zv = (XmdsVirtual)out_player.Virtual;
zv.ReceiveMsgR2B(team);
}
}
});
}
public void OnPlayerAddHPByItem(List notifyPlayers, IPlayer client, int addHP)
{
QueueTask(() =>
{
var nodePlayer = client.BindingObject as ZoneNodePlayer;
if (nodePlayer != null)
{
XmdsVirtual zv = (nodePlayer.BindingActor.Virtual) as XmdsVirtual;
int finalHp = zv.AddHPByItem(addHP);
ZoneNodePlayer temp = null;
foreach (IPlayer p in notifyPlayers)
{
temp = p.BindingObject as ZoneNodePlayer;
XmdsVirtual notifyPlayer = null;
if (temp != null)
{
notifyPlayer = (temp.BindingActor.Virtual) as XmdsVirtual;
notifyPlayer.SendHPChangeMessage(zv.mUnit.ID, finalHp);
}
}
}
});
}
public float GetDropRange(int items)
{
if(items >= 10)
{
return 5.0f;
}
if (items >= 7)
{
return 4.0f;
}
else if(items > 4)
{
return 3.6f;
}
return 2.8f;
}
public float GetDropOffect(float dropRange)
{
int index = (this.Zone.RandomN.Next() % 2 == 0) ? 1 : -1;
return dropRange * this.Zone.RandomN.Next(0, 100) / 100f * index;
}
public void AddDropItem(float x, float y, dynamic items)
{
QueueTask(() =>
{
//阿基米德螺线<-装B用,实际不需要这样
//20170621wuyonghui修改为随机掉落位置算法
float dropRange = GetDropRange(((DynamicJsonArray)items).Length);// 掉落半径范围为5
bool addSuc = false;
foreach (dynamic obj in items)
{
XmdsCommon.Message.DropItem di = new XmdsCommon.Message.DropItem();
di.FileName = (string)obj.showId;
di.FreezeTime = (int)obj.freezeTime;
di.Name = (string)obj.name;
di.ObjID = (string)obj.id;
di.ProtectTime = (int)obj.protectTime;
di.Qty = (int)obj.groupCount;
di.Quality = (int)obj.qColor;
di.TemplateID = (int)obj.itemTypeId;
di.TTL = (int)obj.lifeTime;
di.PlayerUUID = new List();
di.Mode = (byte)obj.distributeType;
di.OriginX = x;
di.OriginY = y;
bool showLifeTimes = (bool)obj.showLifeTime;
di.code = (String)obj.code;
di.bindPlayerId = obj.bindPlayerId;
di.createTime = (int)(CommonLang.CUtils.S_LOCAL_TIMESTAMPMS/1000);
if (obj.PlayerUUID != null)
{
foreach (dynamic playeruuid in obj.PlayerUUID)
{
di.PlayerUUID.Add(playeruuid);
}
}
di.IconName = (string)obj.IconName;
ItemTemplate templateTemp = Zone.Templates.getItem(di.TemplateID);
if(templateTemp == null)
{
log.Warn("AddDropItem没有对应单位信息:" + di.TemplateID + ", " + di.code);
return;
}
ItemTemplate template = templateTemp.Clone() as ItemTemplate;
//每个物品类型可能有多个显示模型,所以按游戏服传过来的策划配置模型名称
template.FileName = di.FileName;
//修改模板的部分数据,由于模板是共享的,所以必须每次都把以下数据完整覆盖
template.LifeTimeMS = di.TTL;
template.GotCoolDownTimeMS = di.FreezeTime;
template.DropForAll = true;
template.GotOnUse = true;
template.showLifeTime = showLifeTimes;
//template.Pickable = false;//这里注释掉,直接用模板里的值,不要改变
XmdsItemProperties props = template.Properties as XmdsItemProperties;
props.ItemType = XmdsItemProperties.XmdsItemType.Equip;
float x1 = this.GetDropOffect(dropRange);//获得X偏移量
float y1 = this.GetDropOffect(dropRange);//获得Y偏移量
if(Zone.TryTouchMap(null,x+x1,y+y1))
{
x1 = 0;
y1 = 0;
}
//System.Console.WriteLine("掉落物:" + di.Name + ", 偏移:" + x1 + ", " + y1 + "----" + (x + x1) + ", " + (y + y1));
AddItemEvent aie;
XmdsDropableInstanceItem drop_item = Zone.AddItem(template, obj.name, x + x1, y + y1, 0, 0, obj.name, out aie, null,1);
if(drop_item == null || aie == null)
{
log.Warn("添加bs掉落物失败:" + template.ID + ", " + template.Name + ", " + this.SceneID);
return;
}
aie.Sync.ExtData = di;
if(drop_item != null)
{
addSuc = true;
}
}
if (addSuc)
{
base.RecordDropItem();
}
});
}
public void FinishPickItem(IPlayer player, string itemIcon, int quality, int num)
{
QueueTask(() =>
{
var p = player.BindingObject;
if (p != null && p.BindingActor != null)
{
PlayerGotItemB2C b2c = new PlayerGotItemB2C();
XmdsVirtual zv = (XmdsVirtual)(p.BindingActor).Virtual;
b2c.IconName = itemIcon;
b2c.Qty = num;
b2c.Quality = quality;
zv.mUnit.queueEvent(b2c);
}
});
}
#endregion
//------------------------------------------------------------------------------------------------------------
#region _PingPong_
//private static readonly int MSG_TYPE_ID_PING = PropertyUtil.GetAttribute(typeof(Ping)).MessageTypeID;
//private static readonly int MSG_TYPE_ID_PONG = PropertyUtil.GetAttribute(typeof(Pong)).MessageTypeID;
//private ArraySegment pong_data = new ArraySegment(new byte[8], 0, 8);
//public bool doDecodePing(IPlayer player, byte[] data)
//{
// int pos = 0;
// int msg_id = LittleEdian.GetS32(data, ref pos);
// if (msg_id == MSG_TYPE_ID_PING)
// {
// uint time = LittleEdian.GetU32(data, ref pos);
// pos = 0;
// LittleEdian.PutS32(pong_data.Array, ref pos, MSG_TYPE_ID_PONG);
// LittleEdian.PutU32(pong_data.Array, ref pos, time);
// player.SendToClient(pong_data);
// return true;
// }
// return false;
//}
#endregion
//------------------------------------------------------------------------------------------------------------
protected override PlayerClient CreatePlayerClient(CommonAIServer.Node.Interface.IPlayer client, InstancePlayer actor)
{
var syncIn = base.Config.CLIENT_SYNC_OBJECT_IN_RANGE;
var syncOut = base.Config.CLIENT_SYNC_OBJECT_OUT_RANGE;
var zpp = base.SceneData.Properties as XmdsSceneProperties;
if (zpp.AOIMinRange > 0 && zpp.AOIMaxRange > 0)
{
syncIn = zpp.AOIMinRange;
syncOut = zpp.AOIMaxRange;
}
return new BindingPlayerClient(client, actor, this, syncIn, syncOut);
}
//------------------------------------------------------------------------------------------------------------
public class ZoneNodePlayer : CommonAIServer.Node.Interface.IPlayer
{
private static AtomicInteger s_alloc_object_count = new AtomicInteger(0);
///
/// 分配实例数量
///
public static int AllocCount { get { return s_alloc_object_count.Value; } }
public readonly ZoneNode node;
public readonly IPlayer player;
private ZoneNodeCodec mCodec = new ZoneNodeCodec(ZoneNodeManager.MessageFactory);
private AtomicReference binding_player = new AtomicReference(null);
private Action