using CommonAI.Data;
using CommonAI.RTS;
using CommonAI.Zone.EventTrigger;
using CommonAI.Zone.Formula;
using CommonAI.Zone.Helper;
using CommonAI.ZoneClient;
using CommonAI.ZoneEditor;
using CommonAI.ZoneServer.JSGModule;
using CommonLang;
using CommonLang.Concurrent;
using CommonLang.IO;
using CommonLang.Log;
using CommonLang.Property;
using CommonLang.Vector;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using static CommonAI.Zone.SpellTemplate;
using static CommonAI.Zone.UnitInfo;
namespace CommonAI.Zone.Instance
{
///
/// 服务端场景
///
public partial class InstanceZone : GameEntity
{
private static AtomicInteger s_alloc_zone_count = new AtomicInteger(0);
private static AtomicInteger s_active_zone_count = new AtomicInteger(0);
///
/// 分配实例数量
///
public static int AllocZoneCount { get { return s_alloc_zone_count.Value; } }
///
/// 未释放实例数量
///
public static int ActiveZoneCount { get { return s_active_zone_count.Value; } }
//------------------------------------------------------------------------
// 基础数据
private InstanceZoneListener mListener;
private TemplateManager mTemplates;
private IFormula mFormula = TemplateManager.Factory.Formula;
private IQuestAdapter mQuestAdapter;
private SyncMessageQueue mSyncActionQueue = new SyncMessageQueue();
private ConcurrentQueue mSendingEvents = new ConcurrentQueue();
private InstanceZoneObjectMap mObjects;
public TemplateManager Templates { get { return mTemplates; } }
public IQuestAdapter QuestAdapter { get { return mQuestAdapter; } }
public int UpdateIntervalMS { get { return mLastInterval; } }
private readonly int mMaxUnitCount;
private int mLastInterval = 0;
private ulong mTimer = 0;
private long mCurPassTimeMS = 0;
private long mQueryPassTimeMS = 0;
private int mQueryPassTimeSEC = 0;
private bool mHalfSync = false;
readonly public long mCreateTime;
readonly private Random random;
readonly private Logger log;
public string UUID { get; set; }
//记录触发器总览,避免日志过多
public long mTotalTimeUse;
public long mTotalTrigers;
//------------------------------------------------------------------------
readonly private ZoneInfo m_TerrainSrc;
readonly private SpaceDivision mSpaceDiv;
public ZoneInfo TerrainSrc { get { return m_TerrainSrc; } }
public ZoneInfo Terrain { get { return path_terrain_data.Data; } }
public int SpaceDivSize { get; private set; }
[Desc("单位当前帧位移的最小距离")]
public float MinStep { get; private set; }
[Desc("最大单位数量")]
public int MaxUnitCount { get { return mMaxUnitCount; } }
[Desc("场景中是否存在Area")]
public bool HasArea { get { return mHasArea; } }
//山大王id
protected int mKingID;
//绑定服务器
protected string mBindGameSrvId;
//------------------------------------------------------------------------
///
///
///
///
/// 消息接收者
/// 场景数据
/// 空间分割参数
/// 最大单位数
/// 随机种子
internal InstanceZone(TemplateManager templates, InstanceZoneListener listener, ZoneEditor.SceneData data, GSCreateAreaData gsData,
int spaceDivSize, int maxUnitCount, int randomSeed)
{
mCreateTime = TimeUtil.GetTimestampMS();
InstanceZone.s_alloc_zone_count++;
InstanceZone.s_active_zone_count++;
var info = data.ZoneData;
this.log = LoggerFactory.GetLogger(string.Format("InstanceZone({0})", info.TemplateID));
this.random = TemplateManager.Factory.CreateRandom(randomSeed);// new Random(randomSeed);
this.mTemplates = templates;
this.IsSyncZ = false;
this.MinStep = MoveHelper.GetDistance(1000 / templates.CFG.SYSTEM_FPS, templates.CFG.OBJECT_MOVE_TO_MIN_STEP_SEC);
if (spaceDivSize < 1)
{
throw new Exception("SpaceDivSize must large than map 1 !");
}
this.mMaxUnitCount = maxUnitCount;
this.mListener = listener;
this.m_TerrainSrc = info;
this.SpaceDivSize = spaceDivSize;
this.mSpaceDiv = new SpaceDivision(
m_TerrainSrc.TotalWidth,
m_TerrainSrc.TotalHeight,
spaceDivSize * m_TerrainSrc.GridCellW,
spaceDivSize * m_TerrainSrc.GridCellH);
this.mObjects = new InstanceZoneObjectMap("zoneId:" + this.GetSceneID());
// this.path_terrain_data = new InstanceZoneManhattanMap(templates, info.Clone() as ZoneInfo);
// this.path_finder = new AstarManhattan(path_terrain_data, true, spaceDivSize);
// this.path_terrain_area_gen = new ManhattanMapAreaGenerator(path_terrain_data.Data);
this.InitTerrain(data, spaceDivSize, out this.path_terrain_data, out this.path_finder, out this.path_terrain_area_gen);
this.mQuestAdapter = TemplateManager.Factory.CreateQuestAdapter(this);
this.baseInit(data, gsData);
}
protected virtual void baseInit(ZoneEditor.SceneData data, GSCreateAreaData gsData)
{
}
// -----------------------------------------------------------------------------------
~InstanceZone()
{
InstanceZone.s_alloc_zone_count--;
}
protected override void Disposing()
{
base.Disposing();
this.ClearEvents();
foreach (var obj in mObjects.Objects)
{
obj.Dispose();
}
this.mObjects.Dispose();
this.mObjects = null;
foreach (var flg in mFlags.Values)
{
flg.Dispose();
}
this.mFlags.Clear();
this.DisposeTerrain();
this.mSpaceDiv.Dispose();
this.mQuestAdapter.Dispose();
this.mQuestAdapter = null;
this.mListener = null;
this.mTemplates = null;
this.mFormula = null;
this.mSyncActionQueue = null;
this.mSendingEvents = null;
this.mTasks.Clear();
this.mTasks = null;
this.mTimeTasks.Dispose();
this.mTimeTasks = null;
this.EnvironmentVarMap.Clear();
this.mFlags.Clear();
this.m_UnitsPos.Clear();
this.m_UnitsStates.Clear();
InstanceZone.s_active_zone_count--;
}
// -----------------------------------------------------------------------------------
protected Logger Log { get { return log; } }
public int TotalWidth { get { return m_TerrainSrc.TotalWidth; } }
public int TotalHeight { get { return m_TerrainSrc.TotalHeight; } }
public int GridCellW { get { return m_TerrainSrc.GridCellW; } }
public int GridCellH { get { return m_TerrainSrc.GridCellH; } }
public int XCount { get { return m_TerrainSrc.XCount; } }
public int YCount { get { return m_TerrainSrc.YCount; } }
public ulong Tick { get { return mTimer; } }
///
/// 是否发 SyncPosEvent 包
///
public bool SyncPos
{
get { return sync_pos_list.Enable; }
set { sync_pos_list.Enable = value; }
}
///
/// 是否为低速率网络同步(将优化为半字通信)
///
public bool IsHalfSync
{
get { return mHalfSync; }
set
{
if (value && TotalWidth <= 255 && TotalHeight <= 255)
{
mHalfSync = value;
}
else
{
mHalfSync = false;
}
}
}
///
/// 同步包是否包含Z
///
public bool IsSyncZ
{
get;
set;
}
public long PassTimeMS { get { return mQueryPassTimeMS; } }
public int PassTimeSEC { get { return mQueryPassTimeSEC; } }
public Random RandomN { get { return random; } }
// public void Trace(string text)
// {
// log.Info(text);
// }
// -----------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
#region TIMING_AND_TASK
private SyncMessageQueue> mTasks = new SyncMessageQueue>();
private TimeTaskQueue mTimeTasks = new TimeTaskQueue();
private void doTask(Action task)
{
task(this);
}
///
/// 【线程安全】向主线程排一个任务
///
///
public void queueTask(Action task)
{
mTasks.Enqueue(task);
}
public string GetInfo()
{
if (this.mObjects == null)
{
return "对象:-1";
}
return "对象:" + AllObjectsCount + ", 单位:" + AllUnitsCount + ", 法术:" + AllSpellsCount + ", 道具:" + AllItemsCount + ", 玩家:" + AllPlayersCount;
}
///
/// 【线程安全】增加时间任务
///
///
///
///
///
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)
{
if (intervalMS <= 0)
{
log.Error("增加定时任务异常:" + intervalMS);
return null;
}
return mTimeTasks.AddTimePeriodicMS(intervalMS, handler);
}
#endregion
//-----------------------------------------------------------------------------------
///
/// 【线程安全】向当前场景输入指令
///
///
public void pushAction(Action act)
{
mSyncActionQueue.Enqueue(act);
}
protected internal void queueEventInternal(Event evt)
{
mSendingEvents.Enqueue(evt);
}
///
/// 【内部调用】输出消息
///
public void queueEvent(ZoneEvent evt, GameEntity sender = null)
{
if (sender != null) { evt.sender = sender; }
this.queueEventInternal(evt);
}
///
/// 【内部调用】输出消息
///
///
///
public void queueObjectEvent(InstanceZoneObject obj, ObjectEvent evt, bool force = false)
{
if (mSendingEvents == null)
{
if (mObjects == null)
{
log.Warn("queueObjectEvent exception1: " + this.GetSceneID() + ", mObjects null, " + this.UUID + ", " + evt.GetType()
+ ", " + new StackTrace().ToString());
}
else
{
log.Warn("queueObjectEvent exception2: " + this.GetSceneID() + ", Players: " + this.AllPlayersCount + ", Items: "
+ this.AllItemsCount + ", Units: " + this.AllUnitsCount + ", " + this.UUID + ", " + evt.GetType() + ", " + new StackTrace().ToString());
}
return;
}
if (obj.ID == 0)
return;
if (!force && !obj.IsInZone)
return;
obj.onSendingEvent(ref evt);
if (evt != null)
{
evt.object_id = obj.ID;
evt.sender = obj;
mSendingEvents.Enqueue(evt);
}
}
///
/// 立即发送指令
///
///
///
///
public void sendActorResponse(InstanceZoneObject obj, ActorRequest req, ActorResponse rsp)
{
if (obj.ID == 0)
return;
if (!obj.IsInZone)
return;
rsp.MessageID = req.MessageID;
rsp.object_id = obj.ID;
rsp.sender = obj;
mSendingEvents.Enqueue(rsp);
}
public void sendMessageBox(string msg)
{
queueEventInternal(new TestMessageBox(msg));
}
public virtual int GetSceneID() { return 0; }
//-----------------------------------------------------------------------------------
public void RecvMessageFromGameServer(ZoneServer.SendMessageR2B msg)
{
LastRecvMessageR2B = msg;
if (mOnRecvFromGS != null)
{
mOnRecvFromGS.Invoke(this, msg);
}
}
public void SendMessageToGameServer(string msg)
{
ZoneServer.SendMessageB2R b2r = new ZoneServer.SendMessageB2R();
b2r.Message = msg;
LastSentMessageB2R = b2r;
if (mOnSendToGS != null)
{
mOnSendToGS.Invoke(this, b2r);
}
}
public void SendEventToGameServer(IExternalizable evt)
{
ZoneServer.SendEventB2R b2r = new ZoneServer.SendEventB2R();
b2r.evt = evt;
if (mOnSendMessageB2REvent != null)
{
mOnSendMessageB2REvent.Invoke(this, b2r);
}
}
public bool CheckAutoDropItem()
{
return this.mListener.CheckDropItem();
}
//-----------------------------------------------------------------------------------
public virtual void Update(int intervalMS, bool slowRefresh)
{
beginEventsRecord();
this.mLastInterval = intervalMS;
this.MinStep = MoveHelper.GetDistance(intervalMS, Templates.CFG.OBJECT_MOVE_TO_MIN_STEP_SEC);
if (mTimer == 0)
{
mCurPassTimeMS = 0;
mQueryPassTimeMS = 0;
mQueryPassTimeSEC = 0;
foreach (InstanceFlag f in mFlags.Values)
{
f.OnStart();
}
if (mOnInit != null)
mOnInit.Invoke(this);
}
mTasks.ProcessMessages(doTask);
mSyncActionQueue.ProcessMessages(updateAction);
mObjects.Refresh();
var objetes = mObjects.Objects;
{
// clean space div state
foreach (InstanceZoneObject u in objetes)
{
u.onUpdate(this, slowRefresh);
}
mSpaceDiv.ClearSpaceNearChanges();
bool dirty = false;
foreach (InstanceZoneObject u in objetes)
{
if (u.Enable)
{
dirty = u.updatePos(this);
u.mCurCellNode.MarkPosDirty(dirty);
if (dirty && u.ClientVisible && u.SyncPos)
{
if (mOnObjectPosChanged != null)
{
mOnObjectPosChanged.Invoke(this, u);
}
sync_pos_list.Add(u);
}
}
}
}
foreach (InstanceFlag f in mFlags.Values)
{
f.update();
}
if (mOnUpdate != null)
{
mOnUpdate.Invoke(this);
}
updateEvents();
mTimeTasks.Update(intervalMS);
mCurPassTimeMS += intervalMS;
mQueryPassTimeMS = mCurPassTimeMS;
mQueryPassTimeSEC = (int)(mCurPassTimeMS / 1000);
mTimer++;
}
private void updateAction(Action act)
{
if (act is SystemMessage)
{
processSystemMessage(act as SystemMessage);
}
else if (act is ObjectAction)
{
ObjectAction oa = (ObjectAction)act;
InstanceUnit unit = act.sender as InstanceUnit;
if (unit == null)
{
unit = mObjects.GetObject(oa.object_id);
}
if (unit != null)
{
unit.doAction(oa);
if (mOnHandleObjectAction != null)
{
mOnHandleObjectAction.Invoke(unit, oa);
}
mFormula.OnUnitHandleNetMessage(unit, oa);
}
else
{
log.Info("Drop message : " + oa);
}
}
else
{
if (mOnHandleAction != null)
{
mOnHandleAction.Invoke(this, act);
}
mFormula.OnZoneHandleNetMessage(this, act);
}
}
private void updateEvents()
{
if (sync_pos_list.Enable)
{
queueEvent(sync_pos_list.AsEvent(this));
}
sync_pos_list.Clear();
while (mSendingEvents.TryDequeue(out Event evt))
{
//log.Info("---->onEvent:" + evt.ToString());
mListener.onEventHandler(evt);
if (mOnPostEvent != null)
{
mOnPostEvent.Invoke(this, evt);
}
if (evt is GameOverEvent && mOnGameOver != null)
{
mOnGameOver.Invoke(this, evt as GameOverEvent);
}
}
}
virtual protected void processSystemMessage(SystemMessage msg)
{
if (msg is Ping)
{
queueEventInternal(new Pong(msg as Ping));
}
}
//-------------------------------------------------------------------------------------------
#region OBJECTS
private uint mObjectIDIndexer = 0;
internal uint genObjectID()
{
return ++mObjectIDIndexer;
}
// 获取一个单位
public T getObject(uint obj_id) where T : InstanceZoneObject
{
if (obj_id == 0) return null;
T go = mObjects.GetObject(obj_id);
if (go != null)
{
return go;
}
return null;
}
public InstanceUnit getUnit(uint obj_id)
{
if (obj_id == 0) return null;
return mObjects.GetObject(obj_id);
}
public InstanceUnit getUnitByTemplateID(int templateId)
{
if (templateId == 0) return null;
foreach (InstanceUnit u in mObjects.Units)
{
if (u.Info.TemplateID == templateId)
{
return u;
}
}
return null;
}
public InstanceUnit getTheWeightOneAtForce(int force)
{
float weightest = -999;
InstanceUnit theone = null;
foreach (InstanceUnit u in mObjects.Units)
{
if (u.Force == force && u.Weight > weightest)
{
theone = u;
weightest = u.Weight;
}
}
return theone;
}
public InstanceUnit getUnitByName(string name)
{
if (string.IsNullOrEmpty(name))
{
return null;
}
foreach (InstanceUnit u in mObjects.Units)
{
if (name.Equals(u.Name))
{
return u;
}
}
return null;
}
public InstancePlayer getPlayerByUUID(string playerUUID)
{
if (string.IsNullOrEmpty(playerUUID))
{
return null;
}
return mObjects.GetPlayer(playerUUID);
}
public InstanceItem getItemByName(string name)
{
if (string.IsNullOrEmpty(name))
{
return null;
}
foreach (InstanceItem u in mObjects.Items)
{
if (name.Equals(u.Name))
{
return u;
}
}
return null;
}
public InstanceUnit getUnitByID(int UnitID)
{
foreach (InstanceUnit obj in mObjects.Units)
{
if (obj.ID == UnitID)
{
return obj;
}
}
return null;
}
public int getDeadUnit(int count, int force, ref List list)
{
int n = 0;
foreach(var obj in mObjects.Units)
{
if(obj.is_dead() && obj.Force == force && !list.Exists(u => u.ID == obj.ID))
{
list.Add(obj);
if (++n >= count) break;
}
}
return n;
}
public bool IsObjectMapNull()
{
return this.mObjects == null;
}
public IEnumerable AllPlayers { get { return mObjects.Players; } }
public int AllPlayersCount { get { return mObjects.PlayersCount; } }
public IEnumerable AllUnits { get { return mObjects.Units; } }
public int AllUnitsCount { get { return mObjects.UnitsCount; } }
public IEnumerable AllSpells { get { return mObjects.Spells; } }
public int AllSpellsCount { get { return mObjects.SpellsCount; } }
public IEnumerable AllItems { get { return mObjects.Items; } }
public int AllItemsCount { get { return mObjects.ItemsCount; } }
public IEnumerable AllObjects { get { return mObjects.Objects; } }
public int AllObjectsCount { get { return mObjects.ObjectsCount; } }
[Obsolete("use {@link #AllUnits} {@link #AllSpells} {@link #AllItems} for best performance!")]
public IEnumerable allObjs()
{
return mObjects.Objects;
}
[Obsolete("use {@link #AllUnitsCount} {@link #AllSpellsCount} {@link #AllItemsCount} for best performance!")]
public int allObjsCount()
{
return mObjects.ObjectsCount;
}
[Obsolete]
public List selectUnits(Predicate select) where T : InstanceUnit
{
List ret = new List(mObjects.UnitsCount);
foreach (InstanceUnit obj in mObjects.Units)
{
if (select(obj as T))
{
ret.Add(obj as T);
}
}
return ret;
}
public void selectUnits(Predicate select, List ret) where T : InstanceUnit
{
foreach (InstanceUnit obj in mObjects.Units)
{
if (select(obj as T))
{
ret.Add(obj as T);
}
}
}
public T selectRandomUnit(Predicate select) where T : InstanceUnit
{
T ret = null;
using (var list = ListObjectPool.AllocAutoRelease())
{
foreach (InstanceUnit obj in mObjects.Units)
{
if (obj is T && select(obj as T))
{
list.Add(obj as T);
}
}
if (list.Count > 0)
{
ret = CUtils.GetRandomInArray(list, random) as T;
}
}
return ret;
}
public T selectUnit(Predicate select) where T : InstanceUnit
{
foreach (InstanceUnit obj in mObjects.Units)
{
if (select(obj as T))
{
return obj as T;
}
}
return null;
}
//-------------------------------------------------------------------------------------------
///
/// 创建一个单位实体
///
virtual public InstanceZoneObject CreateUnit(UnitInfo info, string name, int force, int alliesForce, int level)
{
InstanceUnit unit = TemplateManager.Factory.CreateUnit(this, info, name, force, alliesForce, level);
if (unit != null)
{
return unit;
}
switch (info.UType)
{
case UnitInfo.UnitType.TYPE_PLAYER:
return new InstancePlayer(this, info, name, force, level, alliesForce);
case UnitInfo.UnitType.TYPE_MANUAL:
return new InstanceManual(this, info, name, force, level);
case UnitInfo.UnitType.TYPE_PET:
return new InstancePet(this, info, name, force, level);
case UnitInfo.UnitType.TYPE_SUMMON:
return new InstanceSummon(this, info, name, force, level);
case UnitInfo.UnitType.TYPE_BUILDING:
return new InstanceBuilding(this, info, name, force, level);
case UnitInfo.UnitType.TYPE_MONSTER:
return new InstanceGuard(this, info, name, force, level);
case UnitInfo.UnitType.TYPE_NPC:
return new InstanceGuard(this, info, name, force, level);
default:
return new InstanceGuard(this, info, name, force, level);
}
}
//-------------------------------------------------------------------------------------------
public InstanceUnit AddUnit(int unitTemplateID, string name, int force, int level, float x, float y, float direction, bool pointLv = false, uint CustomId = 0, string alias = null)
{
UnitInfo info = Templates.getUnit(unitTemplateID);
if (info != null)
{
return AddUnit(info, name, force, level, x, y, direction, null, "", 0, pointLv, CustomId, alias);
}
return null;
}
///
/// 添加一个单位
///
/// 单位模板
/// 场景中名字(Key)
/// 单位阵营
/// 单位等级
/// 坐标
/// 坐标
/// 方向
/// 召唤者
///
public InstanceUnit AddUnit(UnitInfo info, string name, int force, int level, float x, float y, float direction,
InstanceUnit summoner = null, String clientShowName = "", int gsFlag = 0, bool pointLv = false, uint CustomId = 0, string alias = null)
{
AddUnitEvent add;
return AddUnit(info, name, force, level, x, y, direction, out add, summoner, clientShowName, gsFlag, 0, pointLv, CustomId, alias);
}
///
/// 添加一个单位
///
/// 单位模板
/// 场景中名字(Key)
/// 单位阵营
/// 单位等级
/// 坐标
/// 坐标
/// 方向
/// 输出事件
/// 召唤者
///
///
private long mAddUnitPrintTime = 0;
public InstanceUnit AddUnit(UnitInfo info, string name, int force, int level, float x, float y, float direction,
out AddUnitEvent add, InstanceUnit summoner = null, String clientShowName = "", int gsFlag = 0, int alliesForce = 0, bool pointLv = false, uint CustomId = 0, string alias = null)
{
add = null;
if (mObjects.UnitsCount >= mMaxUnitCount)
{
if (mAddUnitPrintTime < CommonLang.CUtils.localTimeMS)
{
mAddUnitPrintTime = CommonLang.CUtils.localTimeMS + 3000;
log.Warn(string.Format("--Zone AddUnit to max: {0}, UUID: {1}, ID: {2} 单位数量:{3}", this.GetSceneID(), this.UUID, info.TemplateID, GetZoneUnitInfo()));
}
return null;
}
if (mTryAddUnit != null && !mTryAddUnit.Invoke(info))
{
//log.Info(string.Format("Zone Unit TryAdd max: {0}, {1}, 单位数量:{2}", this.TerrainSrc.ID, info.TemplateID, mObjects.UnitsCount));
return null;
}
// 创建实体单位
InstanceZoneObject ret = CreateUnit(info, name, force, alliesForce, level);
// 存入单位列表
if (ret is InstanceUnit)
{
InstanceUnit unit = ret as InstanceUnit;
unit.Alias = alias;
unit.gameServerFlag = gsFlag;
if(CustomId > 0 && mObjects.ContainsObjectByKey(CustomId))
{
log.Warn(string.Format("--Zone AddUnit failed, ID Exist: id:{0} template:{1}", CustomId, info.TemplateID));
return null;
}
// 存入单位列表
if (unit.tryAdd(x, y, direction, CustomId))
{
mObjects.AddObject(unit);
this.LastAddedUnit = unit;
if (unit is ISummonedUnit)
{
((ISummonedUnit)unit).SummonerUnit = summoner;
}
try
{
unit.onAdded(this, pointLv);
if (mOnUnitAdded != null)
mOnUnitAdded.Invoke(this, unit);
add = new AddUnitEvent();
add.sender = unit;
if (unit.ClientVisible)
{
if (clientShowName != null && !unit.IsPlayer && clientShowName.Length > 0)
{
unit.SetDiaplayerName(clientShowName);
}
//// 阵营判断
//if(info.UType == UnitType.TYPE_MONSTER && force > 1)
//{
// add.flag = 1;
//}
queueEvent(add);
}
}
catch (Exception err)
{
log.Warn("AddUnit catch :" + name + ", e:" + err);
add.ErrorMessage = err.Message;
return null;
}
finally
{
add.Sync = unit.GenSyncUnitInfo(true);
}
return unit;
}
}
return null;
}
/** 获取场景单位异常信息 */
private string GetZoneUnitInfo(int nMinNums = 50)
{
HashMap mInfo = new HashMap();
foreach (InstanceUnit obj in mObjects.Units)
{
mInfo.Put(obj.Info.ID, mInfo.Get(obj.Info.ID) + 1);
}
string finalStr = "";
foreach (int unitID in mInfo.Keys)
{
int count = mInfo.Get(unitID);
if (count < nMinNums)
{
continue;
}
finalStr = finalStr + (unitID) + "-" + count + ", ";
}
return finalStr;
}
public InstanceItem AddItem(ItemTemplate template, string name, float x, float y, float direction, int force, string disPlayName,
out AddItemEvent add, InstanceUnit creater, int from)
{
add = null;
if (mTryAddItem != null && !mTryAddItem.Invoke(template))
{
//log.Info(string.Format("Zone item TryAdd max: {0}, {1}", this.mSceneType, template.TemplateID));
return null;
}
InstanceItem ret = TemplateManager.Factory.CreateItem(this, template, name, force, creater, disPlayName, from);
ret.setPos(x, y);
if (ret.tryAdd(x, y, direction))
{
mObjects.AddObject(ret);
this.LastCreatedInstanceItem = ret;
add = new AddItemEvent();
add.sender = ret;
if (ret.ClientVisible)
{
queueEvent(add);
}
try
{
ret.onAdded(this);
if (mItemAdded != null)
mItemAdded.Invoke(this, ret, creater);
}
catch (Exception err)
{
log.Warn("AddItem: " + template.ID + ", catch: " + err);
add.ErrorMessage = err.Message;
return null;
}
finally
{
add.Sync = ret.GenSyncItemInfo(true, null);
}
return ret;
}
return null;
}
public InstanceItem AddItem(ItemTemplate template, string name, float x, float y, float direction, int force, string disPlayName, InstanceUnit creater, int from = 0)
{
AddItemEvent add;
return AddItem(template, name, x, y, direction, force, disPlayName, out add, creater, from);
}
///
/// 添加一个法术或飞行道具
///
///
///
///
/// 此法术的最初发起者
///
///
///
///
///
///
///
public InstanceSpell AddSpell(
XmdsSkillType fromSkillType,
SpellTemplate template,
LaunchSpell launch,
InstanceZoneObject sender,
InstanceUnit launcher,
uint target_obj_id,
Vector2 targetPos,
float startX,
float startY,
float direction,
SpellChainLevelInfo chain = null,
int actionIndex = -1,
int maxAffectUnit = 0,
Dictionary damageList = null,
int spellIndex = 0,
JSGCreateSpellData createData = null)
{
if (template != null && sender != null)
{
InstanceUnit target = getUnit(target_obj_id);
switch (template.MType)
{
// case SpellTemplate.MotionType.Missile:
// if (target == null)
// {
// return null;
// }
// break;
case SpellTemplate.MotionType.BindingTarget:
if (target == null)
{
return null;
}
startX = target.X;
startY = target.Y;
break;
case SpellTemplate.MotionType.SelectTarget:
if (targetPos != null)
{
startX = targetPos.X;
startY = targetPos.Y;
}
break;
case SpellTemplate.MotionType.SeekerMissile:
case SpellTemplate.MotionType.SeekerSelectTarget:
{
target = null;
target_obj_id = 0;
}
break;
case SpellTemplate.MotionType.Chain:
if (target == null)
{
return null;
}
break;
case SpellTemplate.MotionType.Cannon:
if (target == null && targetPos == null)
{
targetPos = new Vector2(startX, startY);
}
break;
}
// 创建实体单位
//InstanceSpell ret = new InstanceSpell(this, template, launch, launcher, sender, chainLevel);
InstanceSpell ret = TemplateManager.Factory.CreateSpell(this, template, launch, launcher, sender, fromSkillType, damageList, spellIndex, createData);
//ret.Direction = direction;
ret.BindActionIndex = actionIndex;
ret.MaxAffectUnit = (maxAffectUnit == 0) ? ret.Info.MaxAffectUnit : maxAffectUnit;
ret.faceTo(direction);
ret.setChainInfo(chain);
ret.setTargetPos(targetPos);
ret.setTarget(target);
// 存入单位列表
float xChanage, yChange;
launch.GetXModify(launcher, out xChanage, out yChange);
if (ret.tryAdd(startX + xChanage, startY + yChange, direction))
{
//System.Console.WriteLine("--AddSpell: " + ret.Info.ID + ", " + ret.ID);
launcher.Virtual.DispatchSendSpellOverEvent(launch, template, ret.X, ret.Y);
mObjects.AddObject(ret);
this.LastLaunchSpell = ret.Info;
ret.onAdded(this);
if (ret.ClientVisible)
{
// 产生事件
AddSpellEvent evt = new AddSpellEvent(ret);
evt.sender = ret;
queueEvent(evt);
}
return ret;
}
}
return null;
}
// 移除一个单位
public bool RemoveObject(InstanceZoneObject obj)
{
//Console.WriteLine("RemoveObject : " + obj.ID);
if (mObjects.RemoveObject(obj))
{
obj.onRemoved(this);
if (obj is InstanceUnit)
{
InstanceUnit unit = obj as InstanceUnit;
mFormula.OnUnitRemoved(unit);
if (mOnUnitRemoved != null)
mOnUnitRemoved.Invoke(this, unit);
}
else if (obj is InstanceItem)
{
if (this.mOnItemRemoved != null)
this.mOnItemRemoved.Invoke(this, (InstanceItem)obj);
}
if (obj.ClientVisible)
{
RemoveObjectEvent remove = new RemoveObjectEvent(obj.ID);
remove.sender = obj;
queueEvent(remove);
}
obj.Dispose();
return true;
}
return false;
}
public InstanceZoneObject RemoveObjectByID(uint oid)
{
var obj = mObjects.GetObject(oid);
if (obj != null && RemoveObject(obj))
{
return obj;
}
return null;
}
public InstanceZoneObject RemoveUnitByID(uint unitTemplateId)
{
InstanceUnit obj = mObjects.GetUnit(unitTemplateId);
if (obj != null && RemoveObject(obj))
{
return obj;
}
return null;
}
public InstanceZoneObject RemoveSpellByLaunchIDAndSpellID(int launchId, int spellId)
{
InstanceSpell spell = mObjects.GetSpllByLanuchAndSpellId(launchId, spellId);
if (spell != null && RemoveObject(spell))
{
return spell;
}
return null;
}
public InstanceZoneObject RemoveItemByID(uint unitTemplateId)
{
InstanceItem obj = mObjects.GetItem(unitTemplateId);
if (obj != null && RemoveObject(obj))
{
Console.WriteLine("成功移除单位:" + unitTemplateId);
return obj;
}
return null;
}
public int GetZoneKingID()
{
return this.mKingID;
}
public string GetBindGameSrvID()
{
return this.mBindGameSrvId;
}
//----------------------------------------------------------------------------------------------------------------------------------------
private class InstanceZoneObjectMap
{
private class DirtyList where T : InstanceZoneObject
{
private static Logger log = LoggerFactory.GetLogger("DirtyList");
private bool dirty = true;
private List mObjectsCollection = new List();
private HashMap mObjects = new HashMap();
public int Count { get { return mObjects.Count; } }
public void Add(K key, T obj)
{
dirty = true;
mObjects.Add(key, obj);
}
public void Put(K key, T obj)
{
dirty = true;
mObjects.Put(key, obj);
}
public bool Remove(K key)
{
if (mObjects.Remove(key))
{
dirty = true;
return true;
}
return false;
}
public void Dispose()
{
mObjectsCollection.Clear();
mObjects.Clear();
}
public T Get(K key)
{
return mObjects.Get(key);
}
public bool ContainsKey(K key)
{
return mObjects.ContainsKey(key);
}
public IEnumerable GetCollection(string logFlag)
{
try
{
if (dirty)
{
dirty = false;
mObjectsCollection.Clear();
mObjectsCollection.AddRange(mObjects.Values);
}
return mObjectsCollection;
}
catch (Exception err)
{
log.Warn("GetCollectioncatch:" + logFlag + ", CollectCnt: " + mObjectsCollection.Count +
", mObjectsCnt: " + mObjects.Count + ", e:" + err);
}
return mObjects.Values;
}
}
private DirtyList mObjects = new DirtyList();
private DirtyList mObjects_MirrorUnits = new DirtyList();
private DirtyList mObjects_MirrorSpells = new DirtyList();
private DirtyList mObjects_MirrorItems = new DirtyList();
private DirtyList mObjects_MirrorPlayers = new DirtyList();
private string logFlag = "";
public InstanceZoneObjectMap(string logFlag)
{
this.logFlag = logFlag;
}
internal void Refresh()
{
//mObjects.Refresh();
//mObjects_MirrorUnits.Refresh();
//mObjects_MirrorSpells.Refresh();
//mObjects_MirrorItems.Refresh();
//mObjects_MirrorPlayers.Refresh();
}
public void AddObject(InstanceZoneObject obj)
{
mObjects.Add(obj.ID, obj);
if (obj is InstanceUnit)
{
mObjects_MirrorUnits.Add(obj.ID, obj as InstanceUnit);
}
else if (obj is InstanceSpell)
{
mObjects_MirrorSpells.Add(obj.ID, obj as InstanceSpell);
}
else if (obj is InstanceItem)
{
mObjects_MirrorItems.Add(obj.ID, obj as InstanceItem);
}
if (obj is InstancePlayer)
{
var p = obj as InstancePlayer;
mObjects_MirrorPlayers.Put(p.PlayerUUID, p);
}
}
public bool RemoveObject(InstanceZoneObject obj)
{
if (mObjects.Remove(obj.ID))
{
if (obj is InstanceUnit)
{
mObjects_MirrorUnits.Remove(obj.ID);
}
else if (obj is InstanceSpell)
{
mObjects_MirrorSpells.Remove(obj.ID);
}
else if (obj is InstanceItem)
{
mObjects_MirrorItems.Remove(obj.ID);
}
if (obj is InstancePlayer)
{
var p = obj as InstancePlayer;
mObjects_MirrorPlayers.Remove(p.PlayerUUID);
}
return true;
}
return false;
}
private InstanceZoneObject GetObject(uint id)
{
return mObjects.Get(id);
}
public bool ContainsObject(InstanceZoneObject obj)
{
return mObjects.ContainsKey(obj.ID);
}
public bool ContainsObjectByKey(uint id)
{
return mObjects.ContainsKey(id);
}
public void Dispose()
{
mObjects.Dispose();
mObjects_MirrorUnits.Dispose();
mObjects_MirrorSpells.Dispose();
mObjects_MirrorItems.Dispose();
mObjects_MirrorPlayers.Dispose();
}
public T GetObject(uint id) where T : InstanceZoneObject
{
Type type = typeof(T);
if (type.IsSubclassOf(typeof(InstanceUnit)))
{
return mObjects_MirrorUnits.Get(id) as T;
}
else if (type.IsSubclassOf(typeof(InstanceSpell)))
{
return mObjects_MirrorSpells.Get(id) as T;
}
else if (type.IsSubclassOf(typeof(InstanceItem)))
{
return mObjects_MirrorItems.Get(id) as T;
}
else
{
return mObjects.Get(id) as T;
}
}
public InstanceUnit GetUnit(uint unitTemplateId)
{
foreach (InstanceUnit obj in mObjects_MirrorUnits.GetCollection(logFlag))
{
if (obj.Info.ID == unitTemplateId)
{
return obj;
}
}
return null;
}
public InstanceSpell GetSpllByLanuchAndSpellId(int launchId, int spellId)
{
foreach (InstanceSpell obj in mObjects_MirrorSpells.GetCollection(logFlag))
{
if (obj.Info.ID == spellId && obj.LauncherID == launchId)
{
return obj;
}
}
return null;
}
public InstanceItem GetItem(uint itemId)
{
return mObjects_MirrorItems.Get(itemId);
}
public InstancePlayer GetPlayer(string uuid)
{
return mObjects_MirrorPlayers.Get(uuid);
}
public int ObjectsCount { get { return mObjects.Count; } }
public IEnumerable Objects { get { return mObjects.GetCollection(logFlag); } }
public int UnitsCount { get { return mObjects_MirrorUnits.Count; } }
public IEnumerable Units { get { return mObjects_MirrorUnits.GetCollection(logFlag); } }
public int SpellsCount { get { return mObjects_MirrorSpells.Count; } }
public IEnumerable Spells { get { return mObjects_MirrorSpells.GetCollection(logFlag); } }
public int ItemsCount { get { return mObjects_MirrorItems.Count; } }
public IEnumerable Items { get { return mObjects_MirrorItems.GetCollection(logFlag); } }
public int PlayersCount { get { return mObjects_MirrorPlayers.Count; } }
public IEnumerable Players { get { return mObjects_MirrorPlayers.GetCollection(logFlag); } }
}
#endregion
//------------------------------------------------------------------------------------
#region CALL_BACK
internal void cb_unitDamageCallBack(InstanceUnit target, InstanceUnit attacker, int reduceHP, AttackSource source)
{
LastHittedUnit = target;
LastAttackUnit = attacker;
if (attacker != null)
attacker.callback_onAttack(this, target, reduceHP, source);
if (target != null)
target.callback_onDamage(this, attacker, reduceHP, source);
if (mOnUnitDamage != null)
mOnUnitDamage.Invoke(this, target, attacker, reduceHP, source);
}
internal void cb_unitDeadCallBack(InstanceUnit obj, InstanceUnit attacker)
{
try
{
if (obj.mProcessDeadCallbackTime > CommonLang.CUtils.localTimeMS)
{
long processTime = CommonLang.TimeUtil.GetTimestampMS() - (CommonLang.CUtils.localTimeMS - (obj.mProcessDeadCallbackTime - 60000));
log.Warn("cb_unitDeadCallBack 跳过:" + processTime + ", " + obj.Parent.GetSceneID() + ", ID:" + obj.Info.ID + ", UID:" + obj.PlayerUUID);
return;
}
if (obj.IsMonster && obj.Virtual.GetMaType() >= 4 && obj.Level >= 80)
{
log.Info("boss死亡:" + obj.Parent.GetSceneID() + ", 单位id=" + obj.Info.ID + ", 处理死亡时间:" + obj.mProcessDeadCallbackTime
+ ", SceneUID: " + obj.mZone.UUID + ", " + (attacker == null ? "null" : attacker.PlayerUUID));
if (attacker != null && attacker.IsPlayerUnit)
{
JSGHackerModule.OnPlayerKillMonster(attacker, obj);
}
}
if (obj.mProcessDeadCallbackTime > 0)
{
log.Warn("单位多次回调死亡逻辑:" + this.GetSceneID() + ", " + this.UUID + ", " + obj.Info.ID + ", attackID:" +
(attacker == null ? -1 : attacker.Info.ID) + ", UUID" + (attacker == null ? "null" : attacker.PlayerUUID) + ", " + obj.mProcessDeadCallbackTime);
}
obj.mProcessDeadCallbackTime = CommonLang.CUtils.localTimeMS + 60000;
obj.mDeadTime = this.PassTimeMS;
statisticForceDead(obj);
LastHittedUnit = obj;
LastKilledUnit = obj;
//if (attacker == null)
// attacker = obj;
LastAttackUnit = attacker;
obj.doDead(attacker);
if (attacker != null)
{
obj.deadDropItems(attacker.Force);
attacker.CurrentMoney += obj.Info.DropMoney;
}
mFormula.OnUnitDead(obj, attacker);
obj.callback_onDead(this, attacker);
if (mOnUnitDead != null)
{
mOnUnitDead.Invoke(this, obj, attacker);
}
}
catch (Exception e)
{
log.Error("cb_unitDeadCallBackcatch: " + this.GetSceneID() + ", " + (obj == null ? -1 : obj.Info.ID) + ", " + (attacker == null ? -1 : attacker.Info.ID)
+ ",UUID: " + (obj == null ? "null" : obj.PlayerUUID) + ", " + (attacker == null ? "null" : attacker.PlayerUUID) + ", e: " + e);
}
}
internal void cb_unitActivatedCallBack(InstanceUnit obj)
{
nearChange(obj);
LastActivatedUnit = obj;
obj.callback_onActivated(this);
if (mOnUnitActivated != null)
mOnUnitActivated.Invoke(this, obj);
}
internal void cb_unitRebirthCallBack(InstanceUnit obj)
{
LastRebirthUnit = obj;
obj.callback_onRebirth(this);
if (mOnUnitRebirth != null)
mOnUnitRebirth.Invoke(this, obj);
}
internal void cb_unitGotInventoryItemCallBack(InstanceUnit obj, ItemTemplate item, int count)
{
LastUnitGotInventoryItem = item;
obj.callback_onGotInventoryItem(this, item);
if (mOnUnitGotInventoryItem != null)
mOnUnitGotInventoryItem.Invoke(this, obj, item, count);
}
internal void cb_unitLostInventoryItemCallBack(InstanceUnit obj, ItemTemplate item, int count)
{
LastUnitLostInventoryItem = item;
obj.callback_onLostInventoryItem(this, item);
if (mOnUnitLostInventoryItem != null)
mOnUnitLostInventoryItem.Invoke(this, obj, item, count);
}
internal int cb_unitGotInstanceItemCallBack(InstanceUnit obj, InstanceItem item)
{
LastUnitGotInstanceItem = item;
obj.callback_onGotInstanceItem(this, item);
short times = 0;
if (mOnUnitGotInstanceItem != null)
{
InstancePlayer player = (obj as InstancePlayer);
if (player == null)
{
return 0;
}
if (item.unitPickInfo != null)
{
if (item.Info.maxPickTimes > 0)
{
times = item.unitPickInfo.Get(player.PlayerUUID);
if (times >= item.Info.maxPickTimes)
{
player.Virtual.SendMsgToClient(XmdsConstConfig.TIPS_PICK_MAX);
return item.Info.maxPickTimes;
}
}
item.unitPickInfo.Put(player.PlayerUUID, ++times);
item.TotalPickTimes++;
}
mOnUnitGotInstanceItem.Invoke(this, obj, item);
}
return times;
}
internal void cb_unitUseItemCallBack(InstanceUnit obj, ItemTemplate item, InstanceUnit item_creater)
{
LastUnitUseItem = item;
obj.callback_onUseItem(this, item, item_creater);
if (mOnUnitUseItem != null)
mOnUnitUseItem.Invoke(this, obj, item, item_creater);
}
internal void cb_unitGotBuffCallBack(InstanceUnit obj, InstanceUnit.BuffState buff)
{
LastUnitGotBuff = buff.Data;
obj.callback_onGotBuff(this, buff);
if (mOnUnitGotBuff != null)
mOnUnitGotBuff.Invoke(this, obj, buff);
}
internal void cb_unitLostBuffCallBack(InstanceUnit obj, InstanceUnit.BuffState buff)
{
obj.callback_onLostBuff(this, buff);
if (mOnUnitLostBuff != null)
mOnUnitLostBuff.Invoke(this, obj, buff);
}
internal void cb_unitGotMoneyCallBack(InstanceUnit obj, int add_money)
{
if (mOnUnitGotMoney != null)
{
mOnUnitGotMoney.Invoke(obj, add_money);
}
}
internal void cb_unitPickUnitCallBack(InstanceUnit src, InstanceUnit pickable)
{
LastPickableUnit = pickable;
if (mOnUnitPickUnit != null)
{
mOnUnitPickUnit.Invoke(this, src, pickable);
}
}
public void cb_unitOutBattleCallBack(InstanceUnit obj)
{
if (mOnUnitOutBattle != null)
{
mOnUnitOutBattle.Invoke(this, obj);
}
}
internal bool cb_unitTryPickItem(InstanceUnit unit, InstanceItem item)
{
LastPickingItem = item;
LastPickingItemUnit = unit;
bool ret = true;
if (mTryPickItem != null)
{
foreach (TryPickItemHandler trypick in mTryPickItem.GetInvocationList())
{
if (!trypick.Invoke(this, unit, item))
{
ret = false;
}
}
}
return ret;
}
internal void cb_unitFinishPickItem(InstanceUnit unit, InstanceItem item)
{
if (mFinishPickItem != null)
{
mFinishPickItem.Invoke(this, unit, item);
}
}
internal void cb_unitLaunchSkill(InstanceUnit unit, CommonAI.Zone.Instance.InstanceUnit.SkillState ss)
{
LastLaunchSkill = ss.Data;
LastLaunchSkillUnit = unit;
if (mOnUnitLaunchSkill != null)
{
mOnUnitLaunchSkill.Invoke(this, unit, ss);
}
}
internal void cb_playerReady(InstancePlayer player)
{
if (mPlayerReady != null)
{
mPlayerReady.Invoke(player);
}
}
#endregion
//-------------------------------------------------------------------------------------------
#region UNIT_ATTACK
///
/// 获得两个对象是否是队友
///
///
///
///
public virtual bool IsTeammates(InstanceUnit src, InstanceUnit dst)
{
return false;
}
///
/// 测试是否可见,单位间可交互(AOI)
///
///
///
///
public virtual bool IsVisibleAOI(InstanceZoneObject src, InstanceZoneObject dst)
{
if (src.AoiStatus == dst.AoiStatus)
{
if (dst is InstanceUnit)
{
return (dst as InstanceUnit).IsVisible;
}
return true;
}
else if (src.AoiStatus != null)
{
return src.AoiStatus.CanSeeOther;
}
else if (dst.AoiStatus != null)
{
return dst.AoiStatus.CanSeeMe;
}
return false;
}
///
/// 测试是否可攻击
///
///
///
///
///
///
///
public virtual bool IsAttackable(InstanceUnit src, InstanceUnit target, SkillTemplate.CastTarget expectTarget, AttackReason reason, ITemplateData weapon)
{
if (src == null || target == null)
{
return false;
}
if (!IsVisibleAOI(src, target))
{
return false;
}
if (target.CanWhiplashDeadBody)
{
if (!target.IsAttackable)
return false;
if (!target.IsVisible)
return false;
if (target.IsInvincible)
return false;
}
else
{
if (!target.IsActive)
return false;
if (!target.IsVisible)
return false;
if (target.IsInvincible)
return false;
}
switch (expectTarget)
{
case SkillTemplate.CastTarget.Enemy:
return src.Force != target.Force;
case SkillTemplate.CastTarget.PetForMaster:
if (src is InstancePet)
{
return (src as InstancePet).Master == target;
}
return false;
case SkillTemplate.CastTarget.Alias:
return (src != target) && (src.Force == target.Force);
case SkillTemplate.CastTarget.AlliesIncludeSelf:
return (src.Force == target.Force);
case SkillTemplate.CastTarget.AlliesExcludeSelf:
return (src != target) && (src.Force == target.Force);
case SkillTemplate.CastTarget.EveryOne:
return true;
case SkillTemplate.CastTarget.EveryOneExcludeSelf:
return (src != target);
case SkillTemplate.CastTarget.Self:
return src == target;
case SkillTemplate.CastTarget.EnemyAndSelf:
return src.Force != target.Force || src == target;
case SkillTemplate.CastTarget.NA:
default:
return false;
}
}
///
/// 扫描所有可攻击对象
///
///
///
///
///
///
public void getAttackableUnits(InstanceUnit src, List list, SkillTemplate.CastTarget expectTarget, AttackReason reason, ITemplateData weapon)
{
for (int i = list.Count - 1; i >= 0; --i)
{
InstanceUnit o = list[i];
if (!IsAttackable(src, o, expectTarget, reason, weapon))
{
list.RemoveAt(i);
}
}
}
///
/// 对单个单位攻击。
///
///
///
///
/// 判断IsAttackable
///
public bool unitAttackSingle(
InstanceUnit src,
AttackSource attack,
InstanceUnit target,
SkillTemplate.CastTarget expectTarget)
{
if (IsAttackable(src, target, expectTarget, AttackReason.Attack, attack.Weapon))
{
target.doHitAttack(src, attack);
return true;
}
return false;
}
///
/// 某个单位对指定列表里的 IsAttackable 单位发起攻击。
/// 此操作会修改List
///
///
///
/// 调用完成后,列表中未命中单位会自动移除。
/// 判断IsAttackable
///
public int unitAttack(
InstanceUnit src,
AttackSource attack,
List list,
SkillTemplate.CastTarget expectTarget)
{
int count = 0;
for (int i = list.Count - 1; i >= 0; --i)
{
InstanceUnit o = list[i];
if (IsAttackable(src, o, expectTarget, AttackReason.Attack, attack.Weapon))
{
o.doHitAttack(src, attack);
count++;
}
else
{
list.RemoveAt(i);
}
}
return count;
}
///
/// 直接对列表中的单位攻击,不做任何判断。
///
///
///
///
public int unitAttackDirect(
InstanceUnit src,
AttackSource attack,
List list)
{
int count = 0;
for (int i = list.Count - 1; i >= 0; --i)
{
InstanceUnit o = list[i];
o.doHitAttack(src, attack);
count++;
}
return count;
}
///
/// 某个单位发起周身攻击
///
///
///
///
///
///
public int unitAttackRound(
InstanceUnit src,
AttackSource attack,
float range,
SkillTemplate.CastTarget expectTarget)
{
using (var list = ListObjectPool.AllocAutoRelease())
{
getObjectsRoundRange(
Collider.Object_HitBody_TouchRound,
src.X, src.Y, range,
list, src.AoiStatus);
return unitAttack(src, attack, list, expectTarget);
}
}
///
/// 某个单位发起扇形范围攻击
///
///
///
///
///
///
///
///
public int unitAttackFan(
InstanceUnit src,
AttackSource attack,
float direction,
float range,
float angle,
SkillTemplate.CastTarget expectTarget)
{
float dr = angle / 2;
using (var list = ListObjectPool.AllocAutoRelease())
{
getObjectsFanRange(
Collider.Object_HitBody_TouchFan,
src.X, src.Y, range,
direction - dr,
direction + dr,
list, src.AoiStatus);
return unitAttack(src, attack, list, expectTarget);
}
}
//-------------------------------------------------------------------------------------------------------
// 单位释放法术
//-------------------------------------------------------------------------------------------------------
public void unitLaunchSpell(
XmdsSkillType fromSkillType,
InstanceUnit launcher,
LaunchSpell launch,
float startX,
float startY,
uint targetUnitID = 0,
Vector2 targetPos = null, int actionIndex = -1, int maxAffectUnit = 0, float pointDir = 0)
{
if (launch == null)
{
log.Error("单位释放技能异常: " + launcher.Info.ID + ", " + new StackTrace().ToString());
return;
}
if (CUtils.RandomPercent(RandomN, launch.LaunchPercent))
{
float direction = pointDir == 0 ? launcher.Direction : pointDir;
if (targetPos != null)
{
//direction = MathVector.getDegree(startX, startY, targetPos.x, targetPos.y);
targetPos = (Vector2)targetPos.Clone();
}
SpellTemplate spell = Templates.getSpell(launch.SpellID);
if (spell == null)
{
log.Error("unitLaunchSpell找不到法术模板:" + launcher.PlayerUUID + ", " + launch.SpellID + ", SN: " + launch.SerialNumber);
return;
}
JSGCreateSpellData createData;
if (spell != null && launch.Count > 0 && mFormula.TryLaunchSpell(launcher, launch, ref spell, out createData, ref startX, ref startY))
{
SpellChainLevelInfo chain = null;
if (launch.ChainLevel > 0)
{
chain = new SpellChainLevelInfo(launch);
}
switch (launch.PType)
{
case LaunchSpell.PosType.POS_TYPE_FAN:
{
float startAngle = direction - launch.Angle / 2f;// + launch.StartAngle;
float interAngle = launch.Count > 1 ? launch.Angle / (launch.Count - 1) : 0;
for (int i = 0; i < launch.Count; i++)
{
AddSpell(fromSkillType, spell, launch, launcher, launcher,
targetUnitID, targetPos, startX, startY,
startAngle + interAngle * i, chain, actionIndex, maxAffectUnit);
}
}
break;
case LaunchSpell.PosType.POS_TYPE_TOSAMETARGET:
{
InstanceUnit target = SeekSpellAttackable(launcher, spell, launcher.AoiStatus, startX, startY, launch.SeekingTargetRange,
spell.ExpectTarget, SeekingExpect.Nearest, null);
if (target != null)
{
launcher.faceTo(target.X, target.Y);
launcher.SendForceSync();
targetPos = new Vector2(target.X, target.Y);
//Console.WriteLine("-------------targetPos 1 - " + target.X + ", " + target.Y);
//Console.WriteLine("-------------targetPos 2 - " + targetPos);
int[] index = { 0, -1, 1 };
float testAngle = (float)Math.Atan2(targetPos.Y - launcher.Y, targetPos.X - launcher.X);
float xBase = 3.0f;
float xAdd = (float)(xBase * Math.Sin(testAngle)); //角Dir的对边
float yAdd = (float)(xBase * Math.Cos(testAngle)); //Dir的邻边
for (int i = 0; i < launch.Count; i++)
{
float tempX = startX - xAdd * index[i];
float tempY = startY + yAdd * index[i];
float angle = (float)Math.Atan2(targetPos.Y - tempY, targetPos.X - tempX);
AddSpell(fromSkillType, spell, launch, launcher, launcher,
targetUnitID, targetPos, tempX, tempY,
angle, chain, actionIndex, maxAffectUnit);
}
}
else
{
int[] index = { 0, -1, 1 };
float xBase = 3.0f;
float xAdd = (float)(xBase * Math.Sin(direction)); //角Dir的对边
float yAdd = (float)(xBase * Math.Cos(direction)); //Dir的邻边
float[] startAngleTemp = { 0, launch.Angle, launch.Angle * 1.2f, launch.Angle * 1.4f, launch.Angle * 1.5f };
for (int i = 0; i < launch.Count; i++)
{
float tempX = startX - xAdd * index[i];
float tempY = startY + yAdd * index[i];
AddSpell(fromSkillType, spell, launch, launcher, launcher,
targetUnitID, targetPos, tempX, tempY,
direction - startAngleTemp[i] * index[i], chain, actionIndex, maxAffectUnit);
}
}
}
break;
case LaunchSpell.PosType.POS_TYPE_CYCLE:
{
float startAngle = direction + launch.StartAngle;
float interAngle = CMath.PI_MUL_2 / launch.Count;
InstanceSpell[] spellBrothers = null;
if (launch.Count > 1 && spell.MType == SpellTemplate.MotionType.Foxfire)
{
spellBrothers = new InstanceSpell[launch.Count];
}
for (int i = 0; i < launch.Count; i++)
{
var sb = AddSpell(fromSkillType, spell, launch, launcher, launcher,
targetUnitID, targetPos, startX, startY,
startAngle + interAngle * i, chain, actionIndex, maxAffectUnit);
if (spellBrothers != null)
{
spellBrothers[i] = sb;
sb.brothers = spellBrothers;
}
}
}
break;
case LaunchSpell.PosType.POS_TYPE_X:
{
float startAngle = direction + launch.StartAngle;
float[] interAngle = { launch.Angle, CMath.PI_F - launch.Angle, CMath.PI_F + launch.Angle, CMath.PI_F * 2 - launch.Angle };
Dictionary damageList = (spell.HitIntervalMS <= 0 ? new Dictionary() : null);
for (int i = 0; i < 4; i++)
{
AddSpell(fromSkillType, spell, launch, launcher, launcher, targetUnitID, targetPos,
startX, startY, startAngle + interAngle[i], chain, actionIndex, maxAffectUnit, damageList);
}
}
break;
case LaunchSpell.PosType.POS_TYPE_RANDOM_DIRECTION:
{
for (int i = 0; i < launch.Count; i++)
{
float d = (float)(random.NextDouble() * CMath.PI_MUL_2);
AddSpell(fromSkillType, spell, launch, launcher,
launcher, targetUnitID, targetPos, startX,
startY, d, chain, actionIndex, maxAffectUnit);
}
}
break;
case LaunchSpell.PosType.POS_TYPE_AREA:
using (var enemy_list = ListObjectPool.AllocAutoRelease())
{
SeekSpellAttackable(enemy_list, startX, startY, launcher, spell, launch, chain);
for (int i = 0; i < launch.Count && i < enemy_list.Count; i++)
{
AddSpell(fromSkillType, spell, launch, launcher, launcher, enemy_list[i].ID, null,
startX, startY, direction, chain, actionIndex, maxAffectUnit);
}
}
break;
case LaunchSpell.PosType.POS_TYPE_RANDOM_FOR_SPELL:
launch_randomTypeSpell(fromSkillType, spell, launcher, launch, chain, launcher, actionIndex);
break;
case LaunchSpell.PosType.POS_TYPE_RANDOM_POS:
launch_randomPosSpell(fromSkillType, spell, launcher, launch, chain, launcher, actionIndex);
break;
case LaunchSpell.PosType.POS_TYPE_MANY_CANNON:
launch_ManyCannon(fromSkillType, spell, launcher, launch, chain, launcher, targetUnitID, actionIndex, createData);
break;
case LaunchSpell.PosType.POS_TYPE_DEFAULT_SINGLE:
default:
{
AddSpell(fromSkillType, spell, launch, launcher, launcher,
targetUnitID, targetPos, startX, startY,
direction + launch.StartAngle, chain, actionIndex, maxAffectUnit);
}
break;
}
}
}
}
// 单位释放法术
public void spellLaunchSpell(
XmdsSkillType fromSkillType,
InstanceSpell sender,
LaunchSpell launch,
float startX,
float startY,
uint targetUnitID = 0,
Vector2 targetPos = null, int actionIndex = -1, int maxAffectUnit = 0)
{
switch (launch.SenderUnit)
{
case LaunchSpell.LaunchSpllSenderUnit.Launcher:
this.unitLaunchSpell(fromSkillType, sender.Launcher, launch, startX, startY, targetUnitID, targetPos);
return;
}
if (CUtils.RandomPercent(RandomN, launch.LaunchPercent))
{
SpellChainLevelInfo chain = sender.ChainInfo;
if (chain != null)
{
if (!chain.TryLaunch(launch.SpellID))
{
// chain is end //
return;
}
}
SpellTemplate spell = Templates.getSpell(launch.SpellID);
JSGCreateSpellData createData;
if (spell != null && launch.Count > 0 && mFormula.TryLaunchSpell(sender.Launcher, launch, ref spell, out createData, ref startX, ref startY))
{
float direction = sender.Direction;
if (targetPos != null)
{
direction = MathVector.getDegree(startX, startY, targetPos.X, targetPos.Y);
targetPos = (Vector2)targetPos.Clone();
}
switch (launch.PType)
{
case LaunchSpell.PosType.POS_TYPE_FAN:
{
float startAngle = direction - launch.Angle / 2f + launch.StartAngle;
float interAngle = launch.Count > 1 ? launch.Angle / (launch.Count - 1) : 0;
for (int i = 0; i < launch.Count; i++)
{
AddSpell(fromSkillType, spell, launch, sender, sender.Launcher,
targetUnitID, targetPos, startX, startY,
startAngle + interAngle * i, chain, actionIndex, maxAffectUnit);
}
}
break;
case LaunchSpell.PosType.POS_TYPE_CYCLE:
{
float startAngle = direction + launch.StartAngle;
float interAngle = CMath.PI_MUL_2 / launch.Count;
for (int i = 0; i < launch.Count; i++)
{
AddSpell(fromSkillType, spell, launch, sender, sender.Launcher,
targetUnitID, targetPos, startX, startY,
startAngle + interAngle * i, chain, actionIndex, maxAffectUnit);
}
}
break;
case LaunchSpell.PosType.POS_TYPE_X:
{
float startAngle = direction + launch.StartAngle;
float[] interAngle = { launch.Angle, CMath.PI_F - launch.Angle, CMath.PI_F + launch.Angle, CMath.PI_F * 2 - launch.Angle };
Dictionary damageList = (spell.HitIntervalMS <= 0 ? new Dictionary() : null);
for (int i = 0; i < launch.Count; i++)
{
AddSpell(fromSkillType, spell, launch, sender, sender.Launcher, targetUnitID,
targetPos, startX, startY, startAngle + interAngle[i], chain, actionIndex, maxAffectUnit, damageList);
}
}
break;
case LaunchSpell.PosType.POS_TYPE_RANDOM_FOR_SPELL:
launch_randomTypeSpell(fromSkillType, spell, sender, launch, chain, sender.Launcher, actionIndex);
break;
case LaunchSpell.PosType.POS_TYPE_MANY_CANNON:
launch_ManyCannon(fromSkillType, spell, sender, launch, chain, sender.Launcher, targetUnitID, actionIndex, createData);
break;
case LaunchSpell.PosType.POS_TYPE_RANDOM_POS:
launch_randomPosSpell(fromSkillType, spell, sender, launch, chain, sender.Launcher, actionIndex);
break;
case LaunchSpell.PosType.POS_TYPE_RANDOM_DIRECTION:
{
for (int i = 0; i < launch.Count; i++)
{
float d = (float)(random.NextDouble() * CMath.PI_MUL_2);
AddSpell(fromSkillType, spell, launch, sender, sender.Launcher,
targetUnitID, targetPos, startX, startY, d, chain, actionIndex, maxAffectUnit);
}
}
break;
case LaunchSpell.PosType.POS_TYPE_AREA:
using (var enemy_list = ListObjectPool.AllocAutoRelease())
{
SeekSpellAttackable(enemy_list, startX, startY, sender.Launcher, spell, launch, chain);
for (int i = 0; i < launch.Count && i < enemy_list.Count; i++)
{
AddSpell(fromSkillType, spell, launch, sender, sender.Launcher,
enemy_list[i].ID, targetPos, startX, startY, direction, chain, actionIndex, maxAffectUnit);
}
}
break;
case LaunchSpell.PosType.POS_TYPE_DEFAULT_SINGLE:
default:
{
AddSpell(fromSkillType, spell, launch, sender, sender.Launcher,
targetUnitID, targetPos, startX, startY, direction, chain, actionIndex, maxAffectUnit);
}
break;
}
}
}
}
public void attackLaunchSpell(
XmdsSkillType fromSkillType,
InstanceUnit attacker,
InstanceUnit damage,
AttackSource source,
int serverExt = 0)
{
LaunchSpell launch = source.Attack.Spell;
if (launch == null)
return;
InstanceZoneObject sender;
if (source.FromSpellUnit != null)
{
sender = source.FromSpellUnit;
}
else
{
sender = attacker;
}
switch (launch.SenderUnit)
{
case LaunchSpell.LaunchSpllSenderUnit.Launcher:
sender = attacker;
break;
case LaunchSpell.LaunchSpllSenderUnit.DamagedUnit:
sender = damage;
break;
}
if (CUtils.RandomPercent(RandomN, launch.LaunchPercent))
{
float startX = damage.X;
float startY = damage.Y;
SpellTemplate spell = Templates.getSpell(launch.SpellID);
JSGCreateSpellData createData;
if (spell != null && launch.Count > 0 && mFormula.TryLaunchSpell(attacker, launch, ref spell, out createData, ref startX, ref startY))
{
SpellChainLevelInfo chain = null;
if (source.FromSpellUnit != null && source.FromSpellUnit.ChainInfo != null)
{
chain = source.FromSpellUnit.ChainInfo;
if (!chain.TryLaunch(launch.SpellID))
{
// chain is end //
return;
}
}
switch (launch.PType)
{
case LaunchSpell.PosType.POS_TYPE_FAN:
{
float startAngle = sender.Direction - launch.Angle / 2f + launch.StartAngle;
float interAngle = launch.Count > 1 ? launch.Angle / (launch.Count - 1) : 0;
for (int i = 0; i < launch.Count; i++)
{
AddSpell(fromSkillType, spell, launch, sender, attacker, damage.ID, null,
startX, startY, startAngle + interAngle * i, chain, serverExt);
}
}
break;
case LaunchSpell.PosType.POS_TYPE_CYCLE:
{
float startAngle = sender.Direction + launch.StartAngle;
float interAngle = CMath.PI_MUL_2 / launch.Count;
for (int i = 0; i < launch.Count; i++)
{
AddSpell(fromSkillType, spell, launch, sender, attacker, damage.ID, null,
startX, startY, startAngle + interAngle * i, chain, serverExt);
}
}
break;
case LaunchSpell.PosType.POS_TYPE_X:
{
float startAngle = sender.Direction + launch.StartAngle;
float[] interAngle = { launch.Angle, CMath.PI_F - launch.Angle, CMath.PI_F + launch.Angle, CMath.PI_F * 2 - launch.Angle };
Dictionary damageList = (spell.HitIntervalMS <= 0 ? new Dictionary() : null);
for (int i = 0; i < launch.Count; i++)
{
AddSpell(fromSkillType, spell, launch, sender, attacker, damage.ID, null,
startX, startY, startAngle + interAngle[i], chain, serverExt, 0, damageList);
}
}
break;
case LaunchSpell.PosType.POS_TYPE_RANDOM_FOR_SPELL:
launch_randomTypeSpell(fromSkillType, spell, sender, launch, chain, attacker, serverExt);
break;
case LaunchSpell.PosType.POS_TYPE_MANY_CANNON:
launch_ManyCannon(fromSkillType, spell, sender, launch, chain, attacker, damage.ID, serverExt, createData);
break;
case LaunchSpell.PosType.POS_TYPE_RANDOM_POS:
launch_randomPosSpell(fromSkillType, spell, sender, launch, chain, attacker, serverExt);
break;
case LaunchSpell.PosType.POS_TYPE_RANDOM_DIRECTION:
{
for (int i = 0; i < launch.Count; i++)
{
float d = (float)(random.NextDouble() * CMath.PI_MUL_2);
AddSpell(fromSkillType, spell, launch, sender, attacker, damage.ID, null,
startX, startY, d, chain, serverExt);
}
}
break;
case LaunchSpell.PosType.POS_TYPE_AREA:
using (var enemy_list = ListObjectPool.AllocAutoRelease())
{
SeekSpellAttackable(enemy_list, startX, startY, attacker, spell, launch, chain);
for (int i = 0; i < launch.Count && i < enemy_list.Count; i++)
{
AddSpell(fromSkillType, spell, launch, sender, attacker, enemy_list[i].ID, null,
startX, startY, 0, chain, serverExt);
}
}
break;
case LaunchSpell.PosType.POS_TYPE_DEFAULT_SINGLE:
default:
{
AddSpell(fromSkillType, spell, launch, sender, attacker, damage.ID, null,
startX, startY, sender.Direction, chain, serverExt);
}
break;
}
}
}
}
private void launch_randomTypeSpell(XmdsSkillType fromSkillType, SpellTemplate spell, InstanceZoneObject sender,
LaunchSpell launch, SpellChainLevelInfo chain, InstanceUnit attacker, int serverExt = 0)
{
using (var list = ListObjectPool.AllocAutoRelease())
{
attacker.Parent.getObjectsRoundRange(
(obj, dx, dy, dr) =>
{
var u = obj as InstanceUnit;
//己方单位.
if ((attacker.IsPlayer && !u.IsPlayer) || (!attacker.IsPlayer && u.IsPlayer))
{
return CMath.includeRoundPoint(dx, dy, dr, u.X, u.Y);
}
return false;
},
attacker.X,
attacker.Y,
launch.SeekingTargetRange,
list, attacker.AoiStatus);
int maxCount = launch.Count == 0 ? list.Count : Math.Min(launch.Count, list.Count);
for (int i = 0; i < maxCount; i++)
{
float r = (float)(random.NextDouble() * spell.BodySize);
float a = (float)(random.NextDouble() * CMath.PI_MUL_2);
float x = (float)(list[i].X + Math.Cos(a) * r);
float y = (float)(list[i].Y + Math.Sin(a) * r);
float d = (float)(random.NextDouble() * CMath.PI_MUL_2);
AddSpell(fromSkillType, spell, launch, sender, attacker, 0, null,
x, y, d, chain, serverExt);
}
}
}
private void launch_randomPosSpell(XmdsSkillType fromSkillType, SpellTemplate spell, InstanceZoneObject sender,
LaunchSpell launch, SpellChainLevelInfo chain, InstanceUnit attacker, int serverExt = 0)
{
for (int i = 0; i < launch.Count; i++)
{
float x = (float)(random.NextDouble() * launch.SpellRange / 2);
float y = (float)(random.NextDouble() * launch.SpellRange / 2);
float d = (float)(random.NextDouble() * CMath.PI_MUL_2);
int randX = random.Next() % 2 == 0 ? 1 : -1;
int randY = random.Next() % 2 == 0 ? 1 : -1;
AddSpell(fromSkillType, spell, launch, sender, attacker, 0, null,
sender.X + x * randX, sender.Y + y * randY, d, chain, serverExt);
}
}
public InstanceSpell launch_ManyCannon(XmdsSkillType fromSkillType, SpellTemplate spell, InstanceZoneObject sender,
LaunchSpell launch, SpellChainLevelInfo chain, InstanceUnit attacker, uint targetUnitID, int serverExt, JSGCreateSpellData createData)
{
//float angleOffset = targetUnitID == 0 ? launch.StartAngle / 3 : launch.StartAngle;
float angleOffset = JSGModule.GetCurveStartAngleOffect(attacker, getUnit(targetUnitID), launch.StartAngle, spell.SeekingRange);
float startAngle = CMath.OpitimizeRadians(attacker.Direction) + angleOffset;
float launchX = attacker.X - (float)(1.0f * Math.Cos(attacker.Direction));
float launchY = attacker.Y - (float)(1.0f * Math.Sin(attacker.Direction));
Vector2 targetPos = JSGModule.GetCurveDefaultTargetPos(attacker, spell.SeekingRange);
//System.Console.WriteLine("targetPos: " + targetPos.X + ", " + targetPos.Y);
int totalCount = createData == null ? launch.Count : createData.mMaxSpellCount;
return AddSpell(fromSkillType, spell, launch, sender, attacker, targetUnitID, targetPos,
launchX, launchY, startAngle, chain, serverExt, 0, null, totalCount - 1, createData);
}
public void spellSummonUnit(InstanceSpell summoner, SummonUnit summon)
{
float x = summoner.X;
float y = summoner.Y;
float radius = summoner.BodyBlockSize;
UnitInfo info = Templates.getUnit(summon.UnitTemplateID);
if (info.UType != UnitType.TYPE_SUMMON || info.LifeTimeMS <= 0)
{
log.Warn("召唤非召唤类单位1:" + summoner.ID + ", 召唤id: " + summon.UnitTemplateID);
return;
}
//UnitInfo un = (UnitInfo)info.Clone();
//un.UType = UnitInfo.UnitType.TYPE_SUMMON;
string name = null;
if (TemplateManager.Formula.TrySummonUnit(summoner.Launcher, summon, ref info, ref name))
{
for (int i = 0; i < summon.Count; i++)
{
float dx, dy, dr;
//float angle = (float)RandomN.NextDouble() * CMath.PI_MUL_2;
//float lengt = (float)RandomN.NextDouble() * radius;
//dx = x + (float)Math.Cos(angle) * lengt;
//dy = y + (float)Math.Sin(angle) * lengt;
//dr = (float)RandomN.NextDouble() * CMath.PI_MUL_2;
//召唤单位时判断当前位置能否行走,防止被召唤单位卡在地图里.Editor by Alex.
var pos = PathFinder.FindNearRandomMoveableNode(RandomN, x, y, radius, true);
if (pos == null)
{
dx = summoner.Launcher.X;
dy = summoner.Launcher.Y;
}
else
{
dx = pos.PosX;
dy = pos.PosY;
}
dr = summoner.Direction;
InstanceUnit unit = null;
if (!summoner.Launcher.IsActive)
{
unit = AddUnit(info, name, summoner.Launcher.Force, summon.UnitLevel, dx, dy, dr, null);
}
else
{
unit = AddUnit(info, name, summoner.Launcher.Force, summon.UnitLevel, dx, dy, dr, summoner.Launcher);
}
if (unit != null)
{
if (info.LifeTimeMS > 0)
{
AddTimeDelayMS(info.LifeTimeMS, (task) =>
{
unit.kill();
});
}
if (summon.Effect != null)
{
queueEvent(new AddEffectEvent(unit.ID, dx, dy, dr, summon.Effect));
}
}
}
}
}
public void unitSummonUnit(InstanceUnit summoner, SummonUnit summon)
{
float x = summoner.X;
float y = summoner.Y;
MathVector.movePolar(ref x, ref y, summoner.Direction, summoner.BodyBlockSize * 4);
float radius = summoner.BodyBlockSize * 2;
UnitInfo info = Templates.getUnit(summon.UnitTemplateID);
if (info.UType != UnitType.TYPE_SUMMON || info.LifeTimeMS <= 0)
{
log.Warn("召唤非召唤类单位2:" + summoner.ID + ", 召唤id: " + summon.UnitTemplateID);
return;
}
//UnitInfo un = (UnitInfo)info.Clone();
//un.UType = UnitInfo.UnitType.TYPE_SUMMON;
string name = null;
if (TemplateManager.Formula.TrySummonUnit(summoner, summon, ref info, ref name))
{
for (int i = 0; i < summon.Count; i++)
{
float angle = (float)RandomN.NextDouble() * CMath.PI_MUL_2;
float lengt = (float)RandomN.NextDouble() * radius;
float dx = x + (float)Math.Cos(angle) * lengt;
float dy = y + (float)Math.Sin(angle) * lengt;
float dr = (float)RandomN.NextDouble() * CMath.PI_MUL_2;
InstanceUnit unit = AddUnit(info, name, summoner.Force, summon.UnitLevel, dx, dy, dr, summoner);
if (unit != null)
{
if (info.LifeTimeMS > 0)
{
AddTimeDelayMS(info.LifeTimeMS, (task) =>
{
unit.kill();
});
}
if (summon.Effect != null)
{
queueEvent(new AddEffectEvent(unit.ID, dx, dy, dr, summon.Effect));
}
}
}
}
}
public InstanceUnit summonUnit(InstanceUnit summoner, UnitInfo info, string name, int level, float x, float y, float direction)
{
if (info.UType != UnitType.TYPE_SUMMON || info.LifeTimeMS <= 0)
{
log.Warn("召唤非召唤类单位3:" + summoner.ID + ", 召唤id: " + info.ID);
return null;
}
InstanceUnit unit = AddUnit(info, name, summoner.Force, level, x, y, direction, summoner);
if (unit != null)
{
if (info.LifeTimeMS > 0)
{
AddTimeDelayMS(info.LifeTimeMS, (task) =>
{
unit.kill();
});
}
}
return unit;
}
///
/// 锁定范围内指定目标
///
///
///
///
///
///
///
///
///
public virtual InstanceUnit SeekSpellAttackable(
InstanceUnit launcher,
SpellTemplate spellData,
ObjectAoiStatus aoiStatus,
float X, float Y, float range,
SkillTemplate.CastTarget expectTarget,
SpellTemplate.SeekingExpect expectSeeking,
SpellChainLevelInfo chain)
{
using (var list = ListObjectPool.AllocAutoRelease())
{
getObjectsRoundRange((InstanceZoneObject o, float x, float y, float r) =>
{
InstanceUnit u = o as InstanceUnit;
if (chain != null)
{
switch (expectSeeking)
{
case SpellTemplate.SeekingExpect.RandomIgnoreInChain:
case SpellTemplate.SeekingExpect.NearestIgnoreInChain:
case SpellTemplate.SeekingExpect.FarthestIgnoreInChain:
if (chain.ContainsTarget(u))
{
return false;
}
break;
default:
if (chain.LastTarget == u)
{
return false;
}
break;
}
}
if (IsAttackable(launcher, u, expectTarget, AttackReason.Look, spellData))
{
return CMath.intersectRound(x, y, r, o.X, o.Y, o.BodyHitSize);
}
return false;
}, X, Y, range, list, aoiStatus);
switch (expectSeeking)
{
case SpellTemplate.SeekingExpect.Random:
case SpellTemplate.SeekingExpect.RandomIgnoreInChain:
CUtils.RandomList(RandomN, list);
break;
case SpellTemplate.SeekingExpect.Nearest:
case SpellTemplate.SeekingExpect.NearestIgnoreInChain:
list.Sort(new ObjectSorterNearest(X, Y));
break;
case SpellTemplate.SeekingExpect.Farthest:
case SpellTemplate.SeekingExpect.FarthestIgnoreInChain:
list.Sort(new ObjectSorterFarthest(X, Y));
break;
case SpellTemplate.SeekingExpect.TheOne:
list.Sort((a, b) => { return (int)(b.Weight - a.Weight); });
break;
}
if (list.Count > 0)
{
return list[0];
}
}
return null;
}
public virtual void SeekSpellAttackable(List ret, float X, float Y,
InstanceUnit Launcher,
SpellTemplate spell,
LaunchSpell launch,
SpellChainLevelInfo chain)
{
getObjectsRoundRange((InstanceZoneObject o, float x, float y, float r) =>
{
InstanceUnit u = o as InstanceUnit;
if (chain != null)
{
switch (launch.SeekingTargetExpect)
{
case SpellTemplate.SeekingExpect.RandomIgnoreInChain:
case SpellTemplate.SeekingExpect.NearestIgnoreInChain:
case SpellTemplate.SeekingExpect.FarthestIgnoreInChain:
if (chain.ContainsTarget(u))
{
return false;
}
break;
default:
if (chain.LastTarget == u)
{
return false;
}
break;
}
}
if (IsAttackable(Launcher, u, spell.ExpectTarget, AttackReason.Look, spell))
{
return CMath.intersectRound(x, y, r, o.X, o.Y, o.BodyHitSize);
}
return false;
}, X, Y, launch.SeekingTargetRange, ret, Launcher.AoiStatus);
switch (launch.SeekingTargetExpect)
{
case SpellTemplate.SeekingExpect.Random:
case SpellTemplate.SeekingExpect.RandomIgnoreInChain:
CUtils.RandomList(RandomN, ret);
break;
case SpellTemplate.SeekingExpect.Nearest:
case SpellTemplate.SeekingExpect.NearestIgnoreInChain:
ret.Sort(new ObjectSorterNearest(X, Y));
break;
case SpellTemplate.SeekingExpect.Farthest:
case SpellTemplate.SeekingExpect.FarthestIgnoreInChain:
ret.Sort(new ObjectSorterFarthest(X, Y));
break;
}
}
/**游戏服场景标识通知*/
public virtual void GSZoneFlagNotifyMsg(int value1)
{
}
#endregion
//-------------------------------------------------------------------------------------------------------//
#region EDITOR_AND_SCRIPT
readonly private HashMap mFlags = new HashMap();
private bool mHasArea = false;
protected bool addFlag(InstanceFlag flag)
{
if (!mFlags.ContainsKey(flag.Name))
{
mFlags.Add(flag.Name, flag);
flag.onAdded();
if (flag is ZoneArea)
{
mHasArea = true;
}
return true;
}
return false;
}
public InstanceFlag getFlag(string name)
{
if (string.IsNullOrEmpty(name))
{
return null;
}
return mFlags.Get(name);
}
public T getFlagAs(string name) where T : InstanceFlag
{
return mFlags.Get(name) as T;
}
public bool setFlag(string name, bool enable)
{
InstanceFlag flag = getFlag(name);
if (flag != null)
{
flag.Enable = enable;
return true;
}
return false;
}
#endregion
//-------------------------------------------------------------------------------------------------------//
#region Environment
private HashMap EnvironmentVarMap = new HashMap();
public void AddEnvironmentVar(string key, object value, bool syncToClient)
{
if (!string.IsNullOrEmpty(key))
{
EnvironmentVar var = EnvironmentVarMap.Get(key);
if (var != null)
{
if (EnvironmentVar.ALWAYS_SYNC_ENVIRONMENT_VAR || (var.SyncToClient && var.Value != value))
{
queueEvent(new SyncEnvironmentVarEvent(key, value));
}
var.Value = value;
}
else
{
var = new EnvironmentVar(key, syncToClient, value);
EnvironmentVarMap.Add(key, var);
if (EnvironmentVar.ALWAYS_SYNC_ENVIRONMENT_VAR || var.SyncToClient)
{
queueEvent(new SyncEnvironmentVarEvent(key, value));
}
}
}
}
public void SetEnvironmentVar(string key, object value)
{
if (!string.IsNullOrEmpty(key))
{
EnvironmentVar var = EnvironmentVarMap.Get(key);
if (var != null)
{
if (EnvironmentVar.ALWAYS_SYNC_ENVIRONMENT_VAR || (var.SyncToClient && var.Value != value))
{
queueEvent(new SyncEnvironmentVarEvent(key, value));
}
var.Value = value;
}
}
}
public T GetEnvironmentVarAs(string key)
{
if (!string.IsNullOrEmpty(key))
{
EnvironmentVar var = EnvironmentVarMap.Get(key);
if (var != null)
{
try
{
return (T)var.Value;
}
catch (Exception err)
{
log.Warn("GetEnvironmentVarAs : " + key + ", catch: " + err);
}
}
}
return default(T);
}
public int ListEnvironmentVars(List list)
{
list.AddRange(EnvironmentVarMap.Values);
return EnvironmentVarMap.Count;
}
public ClientStruct.ZoneEnvironmentVar[] GetCurrentZoneVars()
{
ClientStruct.ZoneEnvironmentVar[] ret = new ClientStruct.ZoneEnvironmentVar[EnvironmentVarMap.Count];
int i = 0;
foreach (EnvironmentVar var in EnvironmentVarMap.Values)
{
ret[i] = new ClientStruct.ZoneEnvironmentVar();
ret[i].Key = var.Key;
ret[i].Value = var.Value;
ret[i].SyncToClient = var.SyncToClient;
i++;
}
return ret;
}
protected void BindZoneVar(ZoneVar var, BindValuesAdapter api)
{
if (string.IsNullOrEmpty(var.Key))
{
// Error
return;
}
if (var.Value is IEditorValue)
{
IEditorValue evalue = (var.Value as IEditorValue);
AddEnvironmentVar(var.Key, evalue.GetEnvValue(api), var.SyncToClient);
}
else if (var.Value is Array)
{
Array array = var.Value as Array;
for (int i = 0; i < array.Length; i++)
{
object e = array.GetValue(i);
if (e is IEditorValue)
{
string key = string.Format(var.Key + "[{0}]", i);
IEditorValue evalue = (e as IEditorValue);
AddEnvironmentVar(key, evalue.GetEnvValue(api), var.SyncToClient);
}
}
}
}
#endregion
//-------------------------------------------------------------------------------------------------------//
#region QUEST
///
/// 【第三方系统通知】任务已接受
///
///
///
internal void gs_OnQuestAccepted(string playerUUID, string quest)
{
queueTask((InstanceZone zone) =>
{
InstancePlayer p = getPlayerByUUID(playerUUID);
if (p != null)
{
p.doQuestAccepted(quest);
if (mOnQuestAccepted != null)
mOnQuestAccepted.Invoke(p, quest);
}
});
}
///
/// 【第三方系统通知】任务已完成
///
///
///
internal void gs_OnQuestCommitted(string playerUUID, string quest)
{
queueTask((InstanceZone zone) =>
{
InstancePlayer p = getPlayerByUUID(playerUUID);
if (p != null)
{
if (mOnQuestCommitted != null)
mOnQuestCommitted.Invoke(p, quest);
p.doQuestCommitted(quest);
}
});
}
///
/// 【第三方系统通知】任务已放弃
///
///
///
internal void gs_OnQuestDropped(string playerUUID, string quest)
{
queueTask((InstanceZone zone) =>
{
InstancePlayer p = getPlayerByUUID(playerUUID);
if (p != null)
{
if (mOnQuestDropped != null)
mOnQuestDropped.Invoke(p, quest);
p.doQuestDropped(quest);
}
});
}
///
/// 【第三方系统通知】任务状态已改变
///
///
///
///
///
internal void gs_OnQuestStatusChanged(string playerUUID, string quest, string key, string value)
{
queueTask((InstanceZone zone) =>
{
InstancePlayer p = getPlayerByUUID(playerUUID);
if (p != null)
{
p.doQuestStatusChanged(quest, key, value);
if (mOnQuestStatusChanged != null)
mOnQuestStatusChanged.Invoke(p, quest, key, value);
}
});
}
//给单个玩家发送消息
internal void doSendMsgToPlayer(InstancePlayer player, CommonLang.Protocol.IMessage msg)
{
mQuestAdapter.DoSendMsgToPlayer(player.PlayerUUID, msg);
}
///
/// 本地通知游戏服
///
///
///
///
internal void doAcceptQuest(InstancePlayer player, string quest, string args)
{
mQuestAdapter.DoAcceptQuest(player.PlayerUUID, quest, args);
}
///
/// 本地通知游戏服
///
///
///
///
internal void doCommitQuest(InstancePlayer player, string quest, string args)
{
mQuestAdapter.DoCommitQuest(player.PlayerUUID, quest, args);
}
///
/// 本地通知游戏服
///
///
///
///
internal void doDropQuest(InstancePlayer player, string quest, string args)
{
mQuestAdapter.DoDropQuest(player.PlayerUUID, quest, args);
}
///
/// 本地通知游戏服
///
///
///
///
///
internal void doUpdateQuestStatus(InstancePlayer player, string quest, string key, string value)
{
mQuestAdapter.DoUpdateQuestStatus(player.PlayerUUID, quest, key, value);
}
#endregion
//-------------------------------------------------------------------------------------------------------//
}
}