using CommonAI;
using CommonAI.Zone.Instance;
using CommonAI.ZoneServer.JSGModule;
using CommonLang;
using CommonLang.Concurrent;
using CommonLang.Log;
using Pomelo;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.Dynamic;
using System.Threading;
using System.Web.Helpers;
using XmdsCommon.Plugin;
using XmdsCommonServer.Plugin;
using XmdsServerNode.Node;
using XmdsServerNode.Node.R2bNotify;
using static CommonAI.ZoneServer.JSGModule.JSGServerProfile;
namespace XmdsServerEdgeJS.Zone
{
public abstract class ZoneService : IZone
{
//战斗服版本号
public static int s_bsVersion = 1;
public static ZoneService Instance { get; private set; }
protected ZoneService()
{
Instance = this;
updatePrivateMemory(null);
}
//----------------------------------------------------------------------------------------------
protected Logger log = LoggerFactory.GetLogger(typeof(ZoneService).Name);
protected Logger monitorLog = LoggerFactory.GetLogger("monitor");
private ZoneNodeManager zoneNodeManager;
private BattleCodec codec;
private AtomicLong privateMemoryMB = new AtomicLong(0);
private Timer systemUpdateTimer;
private Timer logUpdateTimer;
protected XmdsServerProxy b2r_proxy = new XmdsServerProxy();
///
/// 副本列表
///
private HashMap nodes = new HashMap();
///
/// 玩家列表
///
private HashMap players = new HashMap();
//----------------------------------------------------------------------------------------------
public int PlayerCount
{
get
{
lock (players)
{
return players.Count;
}
}
}
public int ZoneNodeCount
{
get
{
lock (nodes)
{
return nodes.Count;
}
}
}
public long ProcessPrivateMemoryMB
{
get { return privateMemoryMB.Value; }
}
//----------------------------------------------------------------------------------------------
#region Internal
public XmdsPlayer getPlayer(string playerID)
{
lock (players)
{
return players.Get(playerID);
}
}
protected XmdsZoneNode getZoneNode(string instanceID)
{
lock (nodes)
{
return nodes.Get(instanceID);//[instanceID];
}
}
//internal void sendToGameServer(string name, Object param)
//{
// try
// {
// //转化为json
// string json = Json.Encode(param);
// IceManager.instance().eventNotify(name, json);
// }
// catch (Exception err)
// {
// log.Error(err.Message, err);
// }
//}
protected void notifyBattleServer(string instanceId, R2BNotifyMessage param)
{
var node = getZoneNode(instanceId);
if (node != null)
{
//b2r_proxy.SendToBattleServer(node.Node.Zone, param);
param.OnHandle(node.Node.Zone);
}
}
private void updatePrivateMemory(object state)
{
long private_memory_mb = Process.GetCurrentProcess().PrivateMemorySize64 / 1024 / 1024;
privateMemoryMB.Value = private_memory_mb;
}
private void updateLog(object state)
{
dynamic eventStat = new ExpandoObject();
eventStat.Type = "monitor";
eventStat.Object = InstanceZoneObject.ActiveObjectCount + "/" + InstanceZoneObject.AllocObjectCount;
eventStat.Zone = InstanceZone.ActiveZoneCount + "/" + InstanceZone.AllocZoneCount;
eventStat.Node = ZoneNodeCount;
eventStat.Player = PlayerCount;
eventStat.Memory_MB = ProcessPrivateMemoryMB;
eventStat.Pool = ObjectPoolStatus.TotalActive + "/" + ObjectPoolStatus.TotalCount;
monitorLog.Info(eventStat);
// 输出统计日志
if (JSGServerProfile.CheckPrintAllData())
{
this.PrintAllSceneInfo();
}
}
private void PrintAllSceneInfo()
{
lock (nodes)
{
foreach (var p in new List(nodes.Values))
{
try
{
log.Info("PrintAllSceneInfo-ID:" + p.InstanceID + ", " + p.Node.GetBindGameSrvId() + ", 场景ID: " + p.Node.SceneID + ", units=" + p.Node.Zone.AllUnitsCount
+ ", spells=" + p.Node.Zone.AllSpellsCount + ", items=" + p.Node.Zone.AllItemsCount + ", players: " + p.Node.Zone.AllPlayersCount);
}
catch (Exception e)
{
log.Error("PrintAllSceneInfo: " + p.InstanceID + ", e: " + e);
}
}
}
}
#endregion
//----------------------------------------------------------------------------------------------
public void Start(ZoneConfig zoneConfig)
{
lock (this)
{
try
{
log.Info("startPath:" + zoneConfig.startPath);
log.Info("assetPath:" + zoneConfig.assetPath);
JSGServerProfile.init();
systemUpdateTimer = new Timer(updatePrivateMemory, this, 0, 10000);
zoneNodeManager = new ZoneNodeManager();
zoneNodeManager.Init(zoneConfig.startPath, b2r_proxy, zoneConfig.assetPath);
codec = new BattleCodec(ZoneNodeManager.Templates.Templates);
//日志定时器
logUpdateTimer = new Timer(updateLog, this, 30000, 30000);
}
catch (Exception err)
{
//log.Error("初始化失败");
//log.Error(err.Message, err);
//Environment.Exit(0);
throw err;
}
}
}
public void Stop()
{
this.ClearAllPlayers((e, c) => { });
this.DestoryAllZones((e, c) => { });
lock (this)
{
if (zoneNodeManager != null)
{
b2r_proxy.Dispose();
zoneNodeManager.Shutdown();
systemUpdateTimer.Dispose();
logUpdateTimer.Dispose();
zoneNodeManager = null;
codec = null;
}
}
}
public void SetCallBack(string gameSrvId)
{
JSGMountainKingModule.Init(gameSrvId);
}
public void CreateZone(string playerId, string gameServerId, int mapTemplateId, string instanceId, bool forceCreate,
string data, Action cb, Action err)
{
long lstart = TimeUtil.GetTimestampMS();
int resCode = 0;
if (!forceCreate && playerId != null && playerId.Length > 0)
{
var player = getPlayer(playerId);
if (player != null && player.BindingActor.IsActive && player.BindingActor.Virtual.IsInPVP())
{
resCode = 1;
XmdsVirtual playerVirtual = player.BindingActor.Virtual as XmdsVirtual;
log.Warn("PVP状态下传送2:" + playerVirtual.mUnit.PlayerUUID + ", 场景ID: " + playerVirtual.mUnit.Parent.GetSceneID() + ", "
+ playerVirtual.GetHateSystem().GetHatePlayerInfo() + ", 触发PVP玩家:" + playerVirtual.mPvpTriggerPlayerId);
}
}
if (resCode == 0)
{
long private_memory_mb = ProcessPrivateMemoryMB;
if (private_memory_mb > ZoneNodeManager.NodeConfig.SYSTEM_MAX_HEAP_SIZE_MB)
{
string msg = string.Format("CreateZone failed : Private memory {0}MB out of range {1}MB", private_memory_mb, ZoneNodeManager.NodeConfig.SYSTEM_MAX_HEAP_SIZE_MB);
log.Error(msg);
throw new OutOfMemoryException(msg);
}
XmdsZoneNode node = new XmdsZoneNode(this, instanceId, gameServerId);
node.Node.Callback = IceManager.instance().getCallback(gameServerId);
lock (nodes)
{
if (nodes.ContainsKey(instanceId))
{
throw new Exception(string.Format("node instance id ({0}) already exist!", instanceId));
}
nodes.Add(node.InstanceID, node);
}
{
node.Start(mapTemplateId, data, (z) =>
{
//监控日志
dynamic logEvent = new ExpandoObject();
logEvent.type = "createZone";
logEvent.mapTemplateId = mapTemplateId;
logEvent.instanceId = instanceId;
monitorLog.Debug(logEvent);
});
}
JSGServerProfile.RecordZoneCreate(mapTemplateId, (int)(TimeUtil.GetTimestampMS() - lstart));
}
else
{
log.Warn("玩家pvp状态创建场景:" + playerId + ", " + mapTemplateId + ", " + data);
}
cb(resCode);
}
public void DestroyZone(string instanceId, Action cb)
{
XmdsZoneNode node;
lock (nodes)
{
node = this.nodes.RemoveByKey(instanceId);
}
if (node != null)
{
//删除场景实例的所有玩家
lock (players)
{
node.Node.ForEachPlayers((client) =>
{
var player = players.Get(client.PlayerUUID);
if (player != null)
{
if (client.Node == player.Node)
{
players.RemoveByKey(client.PlayerUUID);
}
//else
//{
// log.Warn(client.Node + " destory zone player " + client.PlayerUUID + " in " + player.Node);
//}
}
});
}
node.Stop((z) =>
{
//监控日志
dynamic logEvent = new ExpandoObject();
logEvent.type = "destroyZone";
logEvent.mapTemplateId = z.Node.SceneID;
logEvent.instanceId = instanceId;
monitorLog.Debug(logEvent);
});
}
cb(null, "done");
}
public void DestoryAllZones(Action cb)
{
lock (nodes)
{
foreach (var p in new List(nodes.Values))
{
try
{
this.DestroyZone(p.InstanceID, (e, c) => { });
}
catch (Exception e)
{
log.Error(e);
}
}
}
cb(null, "done");
}
public void PlayerEnter(string playerId, string instanceId, string input, Action cb)
{
var node = getZoneNode(instanceId);
if (node == null)
{
throw new InstanceNotExistException(instanceId);
}
long private_memory_mb = ProcessPrivateMemoryMB;
if (private_memory_mb > ZoneNodeManager.NodeConfig.SYSTEM_MAX_HEAP_SIZE_MB)
{
string msg = string.Format("PlayerEnter failed : Private memory {0}MB out of range {1}MB", private_memory_mb, ZoneNodeManager.NodeConfig.SYSTEM_MAX_HEAP_SIZE_MB);
log.Error(msg);
throw new OutOfMemoryException(msg);
}
dynamic data = Json.Decode(input);
string connectServerId = (string)data.connectServerId;
var session = FastStream.instance().GetSessionByID(connectServerId);
if (session == null)
{
throw new Exception("ConnectServerId not exist : " + connectServerId);
}
string uid = (string)data.uid;
bool robot = data.robot != null ? (bool)data.robot : false;
XmdsPlayerEnter enter = null;
if (data["tempData"] != null)
{
int posX = 0;
int posY = 0;
float direction = 0;
string flagName = null;
flagName = data.tempData.flag;
if (data.tempData["x"] != null)
{
posX = (int)data.tempData.x;
}
if (data.tempData["y"] != null)
{
posY = (int)data.tempData.y;
}
if (data.tempData["direction"] != null)
{
direction = (float)data.tempData.direction;
}
int unitTemplateID = (int)data.unitTemplateID;
XmdsUnitProperties unitprop = new XmdsUnitProperties();
XmdsUnitData unitData = XmdsPlayerUtil.instance().createXmdsUnitData(data, playerId);
unitprop.ServerData = unitData;
enter = new XmdsPlayerEnter();
enter.Pos = new CommonLang.Vector.Vector2(posX, posY);
enter.direction = direction;
enter.FlagName = flagName;
enter.UnitData = new CommonAI.ZoneServer.CreateUnitInfoR2B();
enter.UnitData.Force = unitData.BaseInfo.force;
enter.UnitData.alliesForce = unitData.BaseInfo.alliesForce;
enter.UnitData.StartFlag = null;
enter.UnitData.UnitTemplateID = unitTemplateID;
enter.UnitData.UnitPropData = unitprop;
foreach (dynamic obj in data.tasks)
{
int taskId = obj.QuestID;
int state = obj.State;
XmdsQuestData qData = new XmdsQuestData();
qData.TaskID = taskId.ToString();
qData.TaskState = state.ToString();
foreach (dynamic attr in obj.Attributes)
{
qData.AddAttribute(attr.key, attr.value);
}
unitData.Tasks.Add(qData);
}
foreach (dynamic obj in data.flags)
{
XmdsQuestFlag flag = new XmdsQuestFlag();
flag.FlagName = obj[0];
flag.FlagValue = obj[1];
unitData.QuestFlags.Add(flag);
}
unitData.PlayerEntered = data.playerEntered;
}
XmdsPlayer player = new XmdsPlayer(this, playerId, uid, session, node);
lock (players)
{
if (players.ContainsKey(playerId))
{
this.players[playerId] = player;
//string oldInstanceId = players.Get(playerId).InstanceId;
//PlayerLeave(playerId, oldInstanceId, false, (err, ret) =>
//{
// if (err != null)
// {
// log.Error(err);
// }
//});
}
else
{
this.players.Add(playerId, player);
}
node.Node.OnPlayerEnter(player, enter,
(c) =>
{
player.BindingActor.IsRobot = robot;
//监控日志
dynamic logEvent = new ExpandoObject();
logEvent.type = "playerEnter";
logEvent.mapTemplateId = node.Node.SceneID;
logEvent.instanceId = instanceId;
logEvent.playerId = playerId;
monitorLog.Debug(logEvent);
//cb(null, "done");
},
(e) =>
{
log.Error(e.Message, e);
lock (this.players) { this.players.RemoveByKey(playerId); }
//cb(e, null);
});
}
cb(null, "done");
}
public void PlayerLeave(string playerId, string instanceId, bool keepObject, Action cb)
{
XmdsPlayer player = null;
try
{
lock (players)
{
player = players.Get(playerId);
if (player != null)
{
if (instanceId.Equals(player.InstanceId))
{
this.players.RemoveByKey(playerId);
}
else
{
log.Warn(instanceId + " leave player " + player.InstanceId + player.Node);
}
}
}
var node = getZoneNode(instanceId);
if (node == null)
{
//throw new InstanceNotExistException(instanceId);
cb(null, "done");
return;
}
//玩家已经离开场景
//if (player == null)
//{
// throw new PlayerNotExistException(playerId);
//}
node.Node.OnPlayerLeave(player != null ? player.BindingActor : node.Node.GetPlayer(playerId),
(c) =>
{
//监控日志
dynamic logEvent = new ExpandoObject();
logEvent.type = "playerLeave";
logEvent.mapTemplateId = node.Node.SceneID;
logEvent.playerId = playerId;
monitorLog.Debug(logEvent);
//cb(null, "done");
},
(e) =>
{
//cb(e, null);
log.Error(e.Message, e);
},
keepObject);
cb(null, "done");
}
catch (Exception e)
{
log.Error(e.Message, e);
cb(e, null);
}
finally
{
if (player != null) player.Dispose();
}
}
public void PlayerNetStateChanged(string playerId, string state)
{
var player = getPlayer(playerId);
if (player == null)
{
log.Error("player not exist :" + playerId + " PlayerNetStateChanged");
return;
}
var node = player.Node;
if (node == null)
{
log.Error("zone node not exist :" + player.InstanceId + " PlayerNetStateChanged");
return;
}
log.Debug("player:" + playerId + " PlayerNetStateChanged " + state);
node.OnPlayerNetStateChanged(player, state);
}
public void PlayerReceive(string playerId, byte[] msg)
{
var player = getPlayer(playerId);
if (player == null)
{
log.Debug("fast stream receive not exist player : " + playerId);
return;
}
var node = player.Node;
if (node == null)
{
log.Error("zone node not exist : " + player.InstanceId + " fast stream receive");
return;
}
//log.Debug("player:" + playerId + " socket.receive");
node.OnPlayerReceivedMessage(player, msg);
}
public void GetAllPlayerCount(Action cb)
{
int count = PlayerCount;
cb(null, count);
}
public void ClearAllPlayers(Action cb)
{
try
{
lock (players)
{
foreach (var p in new List(players.Values))
{
this.PlayerLeave(p.PlayerUUID, p.InstanceId, false, (e, c) => { });
}
}
cb(null, "done");
}
catch (Exception e)
{
cb(e, null);
}
}
public void GetAllPlayers(Action cb)
{
try
{
var ret = new List();
lock (players)
{
foreach (var p in new List(players.Values))
{
ret.Add(p.PlayerUUID);
}
}
cb(null, ret.ToArray());
}
catch (Exception e)
{
cb(e, null);
}
}
public void GetServerState(string serverID, Action cb)
{
try
{
int zc = ZoneNodeCount;
int pc = PlayerCount;
int ActiveObjectCount = InstanceZoneObject.ActiveObjectCount;
int AllocObjectCount = InstanceZoneObject.AllocObjectCount;
int ActiveZoneCount = InstanceZone.ActiveZoneCount;
int AllocZoneCount = InstanceZone.AllocZoneCount;
float w = zc * 1000 + pc;
int flag = IceManager.instance().getCallback(serverID) == null ? 0 : 1;
dynamic ret = new
{
weight = w,
memory = ProcessPrivateMemoryMB,
zone_count = zc,
player_count = pc,
ActiveObjectCount = ActiveObjectCount,
AllocObjectCount = AllocObjectCount,
ActiveZoneCount = ActiveZoneCount,
AllocZoneCount = AllocZoneCount,
flag = flag,
};
cb(null, ret);
}
catch (Exception e)
{
log.Error("GetServerState failed, error: " + e.Message, e);
cb(e, e.Message);
}
}
public void RegisterGameServer(int serverId, int crossId, Action cb)
{
try
{
var str = ConfigurationManager.AppSettings["game.server.id"];
if (!string.IsNullOrEmpty(str) && int.Parse(str) != serverId && int.Parse(str) != crossId)
{
cb(null, -1);
return;
}
}
catch (Exception e)
{
cb(e, -2);
return;
}
cb(null, s_bsVersion);
}
//获取单位血量
public void GetUnitHP(string instanceId, int objectId, Action cb)
{
try
{
var node = getZoneNode(instanceId);
if (node == null)
{
cb(null, -1);
return;
}
InstanceUnit unit = node.Node.Zone.getUnit((uint)objectId);
if (unit == null)
{
cb(null, -2);
return;
}
cb(null, unit.CurrentHP);
}
catch (Exception e)
{
cb(e, -10);
return;
}
}
//----------------------------------------------------------------------------------------------
}
}