feat: cache the handlers that are loaded from reflection

This commit is contained in:
Somebody
2025-07-31 17:48:01 +08:00
parent 19cd76c502
commit db172b0b0f
14 changed files with 512 additions and 315 deletions

View File

@@ -83,9 +83,9 @@ public class ServerOption
public ServerAnnounce ServerAnnounce { get; set; } = new();
public ServerProfile ServerProfile { get; set; } = new();
public bool AutoCreateUser { get; set; } = true;
public bool SavePersonalDebugFile { get; set; } = false;
public LogOption LogOption { get; set; } = new();
public int FarmingDropRate { get; set; } = 1;
public bool UseCache { get; set; } = true;
public bool UseCache { get; set; } = false; // didnt recommend
public int ValidFarmingDropRate()
{
@@ -93,6 +93,18 @@ public class ServerOption
}
}
public class LogOption
{
#if DEBUG
public bool EnableGamePacketLog { get; set; } = true;
#else
public bool EnableGamePacketLog { get; set; } = false;
#endif
public bool LogPacketToConsole { get; set; } = true;
public bool DisableLogDetailPacket { get; set; } = false;
public bool SavePersonalDebugFile { get; set; } = false;
}
public class ServerAnnounce
{
public bool EnableAnnounce { get; set; } = true;

View File

@@ -1,10 +1,7 @@
using System.Collections.Concurrent;
using System.Net;
using System.Reflection;
using EggLink.DanhengServer.Kcp.KcpSharp;
using EggLink.DanhengServer.Util;
using Google.Protobuf;
using Google.Protobuf.Reflection;
namespace EggLink.DanhengServer.Kcp;
@@ -73,24 +70,21 @@ public class DanhengConnection
public void LogPacket(string sendOrRecv, ushort opcode, byte[] payload)
{
if (!ConfigManager.Config.ServerOption.LogOption.EnableGamePacketLog) return;
try
{
//Logger.DebugWriteLine($"{sendOrRecv}: {Enum.GetName(typeof(OpCode), opcode)}({opcode})\r\n{Convert.ToHexString(payload)}");
if (IgnoreLog.Contains(opcode)) return;
var typ = AppDomain.CurrentDomain.GetAssemblies()
.SingleOrDefault(assembly => assembly.GetName().Name == "DanhengProto")!.GetTypes()
.First(t => t.Name == $"{LogMap[opcode]}"); //get the type using the packet name
var descriptor =
typ.GetProperty("Descriptor", BindingFlags.Public | BindingFlags.Static)?.GetValue(
null, null) as MessageDescriptor; // get the static property Descriptor
var packet = descriptor?.Parser.ParseFrom(payload);
var formatter = JsonFormatter.Default;
var asJson = formatter.Format(packet);
if (ConfigManager.Config.ServerOption.LogOption.DisableLogDetailPacket) throw new Exception();
var asJson = PacketLogHelper.ConvertPacketToJson(opcode, payload);
var output = $"{sendOrRecv}: {LogMap[opcode]}({opcode})\r\n{asJson}";
#if DEBUG
Logger.Debug(output);
#endif
if (DebugFile == "" || !ConfigManager.Config.ServerOption.SavePersonalDebugFile) return;
if (ConfigManager.Config.ServerOption.LogOption.LogPacketToConsole)
Logger.Debug(output);
if (DebugFile == "" || !ConfigManager.Config.ServerOption.LogOption.SavePersonalDebugFile) return;
var sw = GetWriter();
sw.WriteLine($"[{DateTime.Now:HH:mm:ss}] [GameServer] [DEBUG] " + output);
sw.Flush();
@@ -98,10 +92,11 @@ public class DanhengConnection
catch
{
var output = $"{sendOrRecv}: {LogMap.GetValueOrDefault(opcode, "UnknownPacket")}({opcode})";
#if DEBUG
Logger.Debug(output);
#endif
if (DebugFile != "" && ConfigManager.Config.ServerOption.SavePersonalDebugFile)
if (ConfigManager.Config.ServerOption.LogOption.LogPacketToConsole)
Logger.Debug(output);
if (DebugFile != "" && ConfigManager.Config.ServerOption.LogOption.SavePersonalDebugFile)
{
var sw = GetWriter();
sw.WriteLine($"[{DateTime.Now:HH:mm:ss}] [GameServer] [DEBUG] " + output);

View File

@@ -25,7 +25,8 @@ public class DanhengListener
KeepAliveOptions = new KcpKeepAliveOptions(1000, 30000)
};
public static Type BaseConnection { get; set; } = typeof(DanhengConnection);
public delegate DanhengConnection ConnectionCreatedHandler(KcpConversation conversation, IPEndPoint remote);
public static ConnectionCreatedHandler? CreateConnection { get; set; } = null;
private static Socket? UDPListener => UDPClient?.Client;
private static IKcpMultiplexConnection? Multiplex => KCPTransport?.Connection;
@@ -120,8 +121,8 @@ public class DanhengListener
{
var convId = Connections.GetNextAvailableIndex();
var convo = Multiplex?.CreateConversation(convId, rcv.RemoteEndPoint, ConvOpt);
if (convo == null) return;
var con = (DanhengConnection)Activator.CreateInstance(BaseConnection, convo, rcv.RemoteEndPoint)!;
if (convo == null || CreateConnection == null) return;
var con = CreateConnection(convo, rcv.RemoteEndPoint);
RegisterConnection(con);
await SendHandshakeResponse(con, enet);
}

View File

@@ -0,0 +1,63 @@
using System.Collections.Concurrent;
using System.Reflection;
using EggLink.DanhengServer.Proto;
using Google.Protobuf;
using Google.Protobuf.Reflection;
namespace EggLink.DanhengServer.Kcp;
public static class PacketLogHelper
{
private delegate IMessage ParseIMessage(byte[] data);
private static ConcurrentDictionary<ushort, ParseIMessage> CachedParsers { get; } = [];
public static string ConvertPacketToJson(ushort opcode, byte[] payload)
{
var descriptor = GetParser(opcode);
if (descriptor == null)
{
throw new Exception();
}
var message = descriptor(payload);
var formatter = JsonFormatter.Default;
var asJson = formatter.Format(message);
return asJson ?? throw new Exception();
}
private static ParseIMessage? GetParser(ushort opcode)
{
if (CachedParsers.TryGetValue(opcode, out var parser))
{
return parser;
}
lock (CachedParsers)
{
// try to find the descriptor by opcode
var asbly = Assembly.GetAssembly(typeof(PlayerGetTokenCsReq));
if (asbly == null) return null;
var typ = asbly.GetType($"EggLink.DanhengServer.Proto.{DanhengConnection.LogMap[opcode]}");
if (typ == null) return null;
var desc = typ.GetProperty("Descriptor", BindingFlags.Public | BindingFlags.Static);
if (desc?.GetMethod == null) return null;
// get parser
if (desc.GetValue(null) is not MessageDescriptor parserProperty) return null;
var parserMethod = parserProperty.Parser.GetType().GetMethod("ParseFrom", [typeof(byte[])]);
if (parserMethod == null) return null;
parser = (ParseIMessage)Delegate.CreateDelegate(
typeof(ParseIMessage),
parserProperty.Parser,
parserMethod
);
CachedParsers[opcode] = parser;
return parser;
}
}
}

View File

@@ -35,17 +35,6 @@ public class ChessRogueInstance : BaseRogueInstance
EventManager = new RogueEventManager(player, this);
RogueType = rogueSubMode == RogueSubModeEnum.ChessRogueNous ? 160 : 130;
var types = Assembly.GetExecutingAssembly().GetTypes();
foreach (var type in types)
{
var attr = type.GetCustomAttribute<ModifierEffectAttribute>();
if (attr == null) continue;
var handler = (ModifierEffectHandler)Activator.CreateInstance(type, null)!;
ModifierEffectHandlers.Add(attr.EffectType, handler);
}
foreach (var difficulty in areaExcel.DifficultyID)
if (GameData.RogueDLCDifficultyData.TryGetValue(difficulty, out var diff))
DifficultyExcel.Add(diff);
@@ -69,7 +58,7 @@ public class ChessRogueInstance : BaseRogueInstance
public int BossAeonId { get; set; }
public List<RogueDLCDifficultyExcel> DifficultyExcel { get; set; } = [];
public ChessRogueDiceInstance DiceInstance { get; set; }
public Dictionary<ModifierEffectTypeEnum, ModifierEffectHandler> ModifierEffectHandlers { get; set; } = [];
public static Dictionary<ModifierEffectTypeEnum, ModifierEffectHandler> ModifierEffectHandlers { get; set; } = [];
public Dictionary<int, ChessRogueCellInstance> RogueCells { get; set; } = [];
public ChessRogueCellInstance? CurCell { get; set; }

View File

@@ -39,7 +39,7 @@ public class ChessRogueDiceModifierInstance(int modifierId, ChessRogueDiceSurfac
{
var effect = EffectConfig.EffectType;
instance.ModifierEffectHandlers.TryGetValue(effect, out var handler);
ChessRogueInstance.ModifierEffectHandlers.TryGetValue(effect, out var handler);
if (handler != null)
await handler.SelectCell(this, instance, selectCellId);
@@ -51,7 +51,7 @@ public class ChessRogueDiceModifierInstance(int modifierId, ChessRogueDiceSurfac
{
var effect = EffectConfig.EffectType;
instance.ModifierEffectHandlers.TryGetValue(effect, out var handler);
ChessRogueInstance.ModifierEffectHandlers.TryGetValue(effect, out var handler);
if (handler != null)
await handler.SelectModifierCell(this, instance, selectCellId);
@@ -63,7 +63,7 @@ public class ChessRogueDiceModifierInstance(int modifierId, ChessRogueDiceSurfac
{
var effect = EffectConfig.EffectType;
instance.ModifierEffectHandlers.TryGetValue(effect, out var handler);
ChessRogueInstance.ModifierEffectHandlers.TryGetValue(effect, out var handler);
if (handler != null)
await handler.OnConfirmed(this, instance);
@@ -75,7 +75,7 @@ public class ChessRogueDiceModifierInstance(int modifierId, ChessRogueDiceSurfac
{
var effect = EffectConfig.EffectType;
instance.ModifierEffectHandlers.TryGetValue(effect, out var handler);
ChessRogueInstance.ModifierEffectHandlers.TryGetValue(effect, out var handler);
if (handler != null)
handler.BeforeBattle(this, battle, instance);
@@ -87,7 +87,7 @@ public class ChessRogueDiceModifierInstance(int modifierId, ChessRogueDiceSurfac
{
var effect = EffectConfig.EffectType;
instance.ModifierEffectHandlers.TryGetValue(effect, out var handler);
ChessRogueInstance.ModifierEffectHandlers.TryGetValue(effect, out var handler);
if (handler != null)
await handler.AfterBattle(this, battle);

View File

@@ -1,5 +1,4 @@
using System.Reflection;
using EggLink.DanhengServer.Data;
using EggLink.DanhengServer.Data;
using EggLink.DanhengServer.Data.Config;
using EggLink.DanhengServer.Database;
using EggLink.DanhengServer.Database.Inventory;
@@ -19,39 +18,16 @@ using MissionData = EggLink.DanhengServer.Database.Quests.MissionData;
namespace EggLink.DanhengServer.GameServer.Game.Mission;
public class MissionManager : BasePlayerManager
public class MissionManager(PlayerInstance player) : BasePlayerManager(player)
{
#region Initializer & Properties
public MissionData Data { get; set; }
public Dictionary<FinishActionTypeEnum, MissionFinishActionHandler> ActionHandlers = [];
public Dictionary<MissionFinishTypeEnum, MissionFinishTypeHandler> FinishTypeHandlers = [];
public MissionData Data { get; set; } = DatabaseHelper.Instance!.GetInstanceOrCreateNew<MissionData>(player.Uid);
public static readonly Dictionary<FinishActionTypeEnum, MissionFinishActionHandler> ActionHandlers = [];
public static readonly Dictionary<MissionFinishTypeEnum, MissionFinishTypeHandler> FinishTypeHandlers = [];
public readonly List<int> SkipSubMissionList = []; // bug
public MissionManager(PlayerInstance player) : base(player)
{
Data = DatabaseHelper.Instance!.GetInstanceOrCreateNew<MissionData>(player.Uid);
var types = Assembly.GetExecutingAssembly().GetTypes();
foreach (var type in types)
{
var attr = type.GetCustomAttribute<MissionFinishActionAttribute>();
if (attr != null)
{
var handler = (MissionFinishActionHandler)Activator.CreateInstance(type, null)!;
ActionHandlers.Add(attr.FinishAction, handler);
}
var attr2 = type.GetCustomAttribute<MissionFinishTypeAttribute>();
if (attr2 != null)
{
var handler = (MissionFinishTypeHandler)Activator.CreateInstance(type, null)!;
FinishTypeHandlers.Add(attr2.FinishType, handler);
}
}
}
#endregion
#region Mission Actions

View File

@@ -10,14 +10,9 @@ using EggLink.DanhengServer.Util;
namespace EggLink.DanhengServer.GameServer.Game.Mission;
public class StoryLineManager : BasePlayerManager
public class StoryLineManager(PlayerInstance player) : BasePlayerManager(player)
{
public StoryLineManager(PlayerInstance player) : base(player)
{
StoryLineData = DatabaseHelper.Instance!.GetInstanceOrCreateNew<StoryLineData>(player.Uid);
}
public StoryLineData StoryLineData { get; set; }
public StoryLineData StoryLineData { get; set; } = DatabaseHelper.Instance!.GetInstanceOrCreateNew<StoryLineData>(player.Uid);
public async ValueTask CheckIfEnterStoryLine()
{

View File

@@ -1,44 +1,18 @@
using System.Reflection;
using EggLink.DanhengServer.Data;
using EggLink.DanhengServer.Data;
using EggLink.DanhengServer.Enums.Rogue;
using EggLink.DanhengServer.GameServer.Game.Player;
using EggLink.DanhengServer.GameServer.Server.Packet.Send.RogueCommon;
namespace EggLink.DanhengServer.GameServer.Game.Rogue.Event;
public class RogueEventManager
public class RogueEventManager(PlayerInstance player, BaseRogueInstance rogueInstance)
{
public Dictionary<DialogueEventCostTypeEnum, RogueEventCostHandler> CostHandler = [];
public Dictionary<DialogueEventTypeEnum, RogueEventEffectHandler> EffectHandler = [];
public PlayerInstance Player;
public BaseRogueInstance Rogue;
public static Dictionary<DialogueEventCostTypeEnum, RogueEventCostHandler> CostHandler = [];
public static Dictionary<DialogueEventTypeEnum, RogueEventEffectHandler> EffectHandler = [];
public PlayerInstance Player = player;
public BaseRogueInstance Rogue = rogueInstance;
public List<RogueEventInstance> RunningEvent = [];
public RogueEventManager(PlayerInstance player, BaseRogueInstance rogueInstance)
{
Player = player;
Rogue = rogueInstance;
var types = Assembly.GetExecutingAssembly().GetTypes();
foreach (var type in types)
{
var attr = type.GetCustomAttribute<RogueEventAttribute>();
if (attr == null) continue;
if (attr.EffectType != DialogueEventTypeEnum.None)
{
// Effect
var effect = (RogueEventEffectHandler)Activator.CreateInstance(type, null)!;
EffectHandler.Add(attr.EffectType, effect);
}
else
{
// Cost
var cost = (RogueEventCostHandler)Activator.CreateInstance(type, null)!;
CostHandler.Add(attr.CostType, cost);
}
}
}
public void OnNextRoom()
{
RunningEvent.Clear(); // Clear all running events

View File

@@ -1,4 +1,5 @@
using EggLink.DanhengServer.Data;
using System.Collections.Concurrent;
using EggLink.DanhengServer.Data;
using EggLink.DanhengServer.Data.Config;
using EggLink.DanhengServer.Data.Config.Task;
using EggLink.DanhengServer.Enums.Avatar;
@@ -22,9 +23,13 @@ public class AbilityLevelTask(PlayerInstance player)
#region Selector
public List<BaseGameEntity> TargetAlias(TargetEvaluator selector, BaseGameEntity casterEntity,
List<BaseGameEntity> targetEntities)
public async ValueTask<object> TargetAlias(AbilityLevelParam param)
{
await ValueTask.CompletedTask;
var selector = param.TargetEvaluator!;
var casterEntity = param.CasterEntity;
var targetEntities = param.TargetEntities;
if (selector is TargetAlias target)
return target.Alias switch
{
@@ -33,7 +38,7 @@ public class AbilityLevelTask(PlayerInstance player)
_ => targetEntities
};
return [];
return new List<BaseGameEntity>();
}
#endregion
@@ -69,14 +74,13 @@ public class AbilityLevelTask(PlayerInstance player)
{
var methodName = param.Act.Type.Replace("RPG.GameCore.", "");
var method = GetType().GetMethod(methodName);
if (method != null)
{
var res = method.Invoke(this, [param]);
if (res is AbilityLevelResult result) return result;
// try to get from cache
var method = GetOrCreateExecuteTask(methodName);
if (method == null) return new AbilityLevelResult();
if (res is ValueTask<AbilityLevelResult> valueTask) return await valueTask;
}
var res = method(param);
var re = await res;
if (re is AbilityLevelResult result) return result;
}
catch (Exception e)
{
@@ -86,11 +90,28 @@ public class AbilityLevelTask(PlayerInstance player)
return new AbilityLevelResult();
}
private ExecuteTask? GetOrCreateExecuteTask(string methodName)
{
// try to get from cache
if (_cachedTasks.TryGetValue(methodName, out var method)) return method;
var methodProp = GetType().GetMethod(methodName);
if (methodProp == null) return null;
method = (ExecuteTask)Delegate.CreateDelegate(typeof(ExecuteTask), this, methodProp);
_cachedTasks[methodName] = method; // cached
return method;
}
private delegate ValueTask<object> ExecuteTask(AbilityLevelParam param);
private readonly ConcurrentDictionary<string, ExecuteTask> _cachedTasks = [];
#endregion
#region Task
public async ValueTask<AbilityLevelResult> PredicateTaskList(AbilityLevelParam param)
public async ValueTask<object> PredicateTaskList(AbilityLevelParam param)
{
BattleInstance? instance = null;
List<HitMonsterInstance> battleInfos = [];
@@ -99,32 +120,23 @@ public class AbilityLevelTask(PlayerInstance player)
{
// handle predicateCondition
var methodName = predicateTaskList.Predicate.Type.Replace("RPG.GameCore.", "");
var method = GetType().GetMethod(methodName);
var method = GetOrCreateExecuteTask(methodName);
var res = true;
if (method != null)
{
var resp = method.Invoke(this, [param with { Act = predicateTaskList.Predicate }]);
if (resp is not bool res) return new AbilityLevelResult(instance, battleInfos);
res = predicateTaskList.Predicate.Inverse ? !res : res;
if (res)
foreach (var task in predicateTaskList.SuccessTaskList)
{
var result = await TriggerTask(param with { Act = task });
if (result.BattleInfos != null) battleInfos.AddRange(result.BattleInfos);
if (result.Instance != null) instance = result.Instance;
}
var resp = await method(param with { Act = predicateTaskList.Predicate });
if (resp is not bool r)
{
res = false;
}
else
foreach (var task in predicateTaskList.FailedTaskList)
{
var result = await TriggerTask(param with { Act = task });
if (result.BattleInfos != null) battleInfos.AddRange(result.BattleInfos);
if (result.Instance != null) instance = result.Instance;
}
{
res = predicateTaskList.Predicate.Inverse ? !r : r;
}
}
else
{
if (res)
foreach (var task in predicateTaskList.SuccessTaskList)
{
var result = await TriggerTask(param with { Act = task });
@@ -132,13 +144,20 @@ public class AbilityLevelTask(PlayerInstance player)
if (result.Instance != null) instance = result.Instance;
}
}
else
foreach (var task in predicateTaskList.FailedTaskList)
{
var result = await TriggerTask(param with { Act = task });
if (result.BattleInfos != null) battleInfos.AddRange(result.BattleInfos);
if (result.Instance != null) instance = result.Instance;
}
}
return new AbilityLevelResult(instance, battleInfos);
}
public async ValueTask<AbilityLevelResult> AdventureTriggerAttack(AbilityLevelParam param)
public async ValueTask<object> AdventureTriggerAttack(AbilityLevelParam param)
{
BattleInstance? instance = null;
List<HitMonsterInstance> battleInfos = [];
@@ -146,39 +165,37 @@ public class AbilityLevelTask(PlayerInstance player)
if (param.Act is AdventureTriggerAttack adventureTriggerAttack)
{
var methodName = adventureTriggerAttack.AttackTargetType.Type.Replace("RPG.GameCore.", "");
var method = GetType().GetMethod(methodName);
if (method != null)
var method = GetOrCreateExecuteTask(methodName);
if (method == null) return new AbilityLevelResult();
var resp = await method(param with { TargetEvaluator = adventureTriggerAttack.AttackTargetType });
if (resp is List<BaseGameEntity> target)
{
var resp = method.Invoke(this,
[adventureTriggerAttack.AttackTargetType, param.CasterEntity, param.TargetEntities]);
if (resp is List<BaseGameEntity> target)
foreach (var task in adventureTriggerAttack.OnAttack)
{
foreach (var task in adventureTriggerAttack.OnAttack)
var result = await TriggerTask(param with { Act = task });
if (result.BattleInfos != null) battleInfos.AddRange(result.BattleInfos);
}
if (target.Count > 0 && adventureTriggerAttack.TriggerBattle)
{
foreach (var task in adventureTriggerAttack.OnBattle)
{
var result = await TriggerTask(param with { Act = task });
if (result.BattleInfos != null) battleInfos.AddRange(result.BattleInfos);
}
if (target.Count > 0 && adventureTriggerAttack.TriggerBattle)
foreach (var entity in param.TargetEntities)
{
foreach (var task in adventureTriggerAttack.OnBattle)
{
var result = await TriggerTask(param with { Act = task });
if (result.BattleInfos != null) battleInfos.AddRange(result.BattleInfos);
}
var type = MonsterBattleType.TriggerBattle;
if (entity is EntityMonster { IsAlive: false })
type = MonsterBattleType.DirectDieSkipBattle;
foreach (var entity in param.TargetEntities)
{
var type = MonsterBattleType.TriggerBattle;
if (entity is EntityMonster { IsAlive: false })
type = MonsterBattleType.DirectDieSkipBattle;
battleInfos.Add(new HitMonsterInstance(entity.EntityId, type));
}
instance = await Player.BattleManager!.StartBattle(param.CasterEntity, param.TargetEntities,
param.Request.SkillIndex == 1);
battleInfos.Add(new HitMonsterInstance(entity.EntityId, type));
}
instance = await Player.BattleManager!.StartBattle(param.CasterEntity, param.TargetEntities,
param.Request.SkillIndex == 1);
}
}
}
@@ -186,7 +203,7 @@ public class AbilityLevelTask(PlayerInstance player)
return new AbilityLevelResult(instance, battleInfos);
}
public async ValueTask<AbilityLevelResult> AddMazeBuff(AbilityLevelParam param)
public async ValueTask<object> AddMazeBuff(AbilityLevelParam param)
{
BattleInstance? instance = null;
List<HitMonsterInstance> battleInfos = [];
@@ -194,32 +211,29 @@ public class AbilityLevelTask(PlayerInstance player)
if (param.Act is AddMazeBuff addMazeBuff)
{
var methodName = addMazeBuff.TargetType.Type.Replace("RPG.GameCore.", "");
var method = GetType().GetMethod(methodName);
if (method != null)
{
var resp = method.Invoke(this,
[addMazeBuff.TargetType, param.CasterEntity, param.TargetEntities]);
var method = GetOrCreateExecuteTask(methodName);
if (method == null) return new AbilityLevelResult();
var resp = await method(param with { TargetEvaluator = addMazeBuff.TargetType });
Dictionary<string, float> dynamic = [];
foreach (var dynamicValue in addMazeBuff.DynamicValues)
dynamic.Add(dynamicValue.Key, dynamicValue.Value.GetValue());
Dictionary<string, float> dynamic = [];
foreach (var dynamicValue in addMazeBuff.DynamicValues)
dynamic.Add(dynamicValue.Key, dynamicValue.Value.GetValue());
if (resp is not List<BaseGameEntity> target) return new AbilityLevelResult(instance, battleInfos);
if (resp is not List<BaseGameEntity> target) return new AbilityLevelResult(instance, battleInfos);
foreach (var entity in target)
await entity.AddBuff(new SceneBuff(addMazeBuff.ID, 1,
(param.CasterEntity as AvatarSceneInfo)?.AvatarInfo.BaseAvatarId ?? 0,
addMazeBuff.LifeTime.FixedValue.Value < -1 ? 20 : -1)
{
DynamicValues = dynamic
});
}
foreach (var entity in target)
await entity.AddBuff(new SceneBuff(addMazeBuff.ID, 1,
(param.CasterEntity as AvatarSceneInfo)?.AvatarInfo.BaseAvatarId ?? 0,
addMazeBuff.LifeTime.FixedValue.Value < -1 ? 20 : -1)
{
DynamicValues = dynamic
});
}
return new AbilityLevelResult(instance, battleInfos);
}
public async ValueTask<AbilityLevelResult> AdventureFireProjectile(AbilityLevelParam param)
public async ValueTask<object> AdventureFireProjectile(AbilityLevelParam param)
{
BattleInstance? instance = null;
List<HitMonsterInstance> battleInfos = [];
@@ -248,7 +262,7 @@ public class AbilityLevelTask(PlayerInstance player)
return new AbilityLevelResult(instance, battleInfos);
}
public async ValueTask<AbilityLevelResult> NewAdventureFireProjectile(AbilityLevelParam param)
public async ValueTask<object> NewAdventureFireProjectile(AbilityLevelParam param)
{
BattleInstance? instance = null;
List<HitMonsterInstance> battleInfos = [];
@@ -277,7 +291,7 @@ public class AbilityLevelTask(PlayerInstance player)
return new AbilityLevelResult(instance, battleInfos);
}
public async ValueTask<AbilityLevelResult> CreateSummonUnit(AbilityLevelParam param)
public async ValueTask<object> CreateSummonUnit(AbilityLevelParam param)
{
if (param.Act is CreateSummonUnit createSummonUnit)
{
@@ -304,7 +318,7 @@ public class AbilityLevelTask(PlayerInstance player)
return new AbilityLevelResult();
}
public async ValueTask<AbilityLevelResult> DestroySummonUnit(AbilityLevelParam param)
public async ValueTask<object> DestroySummonUnit(AbilityLevelParam param)
{
if (param.Act is DestroySummonUnit destroySummonUnit)
await Player.SceneInstance!.RemoveSummonUnitById(destroySummonUnit.SummonUnit.SummonUnitID); // TODO
@@ -312,7 +326,7 @@ public class AbilityLevelTask(PlayerInstance player)
return new AbilityLevelResult();
}
public async ValueTask<AbilityLevelResult> AddAdventureModifier(AbilityLevelParam param)
public async ValueTask<object> AddAdventureModifier(AbilityLevelParam param)
{
if (param.Act is AddAdventureModifier addAdventureModifier)
{
@@ -325,7 +339,7 @@ public class AbilityLevelTask(PlayerInstance player)
return new AbilityLevelResult();
}
public async ValueTask<AbilityLevelResult> RemoveAdventureModifier(AbilityLevelParam param)
public async ValueTask<object> RemoveAdventureModifier(AbilityLevelParam param)
{
if (param.Act is RemoveAdventureModifier removeAdventureModifier)
{
@@ -338,7 +352,7 @@ public class AbilityLevelTask(PlayerInstance player)
return new AbilityLevelResult();
}
public async ValueTask<AbilityLevelResult> RemoveSelfModifier(AbilityLevelParam param)
public async ValueTask<object> RemoveSelfModifier(AbilityLevelParam param)
{
if (param.ModifierName != null)
if (param.CasterEntity is IGameModifier mod)
@@ -347,7 +361,7 @@ public class AbilityLevelTask(PlayerInstance player)
return new AbilityLevelResult();
}
public async ValueTask<AbilityLevelResult> RefreshMazeBuffTime(AbilityLevelParam param)
public async ValueTask<object> RefreshMazeBuffTime(AbilityLevelParam param)
{
if (param.Act is RefreshMazeBuffTime refreshMazeBuffTime)
{
@@ -361,7 +375,7 @@ public class AbilityLevelTask(PlayerInstance player)
return new AbilityLevelResult();
}
public async ValueTask<AbilityLevelResult> AdvModifyMaxMazeMP(AbilityLevelParam param)
public async ValueTask<object> AdvModifyMaxMazeMP(AbilityLevelParam param)
{
await ValueTask.CompletedTask;
@@ -379,7 +393,7 @@ public class AbilityLevelTask(PlayerInstance player)
return new AbilityLevelResult();
}
public async ValueTask AdventureSetAttackTargetMonsterDie(AbilityLevelParam param)
public async ValueTask<object> AdventureSetAttackTargetMonsterDie(AbilityLevelParam param)
{
var avatar = param.CasterEntity as AvatarSceneInfo;
if (GameData.AvatarConfigData.TryGetValue(avatar?.AvatarInfo.AvatarId ?? 0, out var excel))
@@ -418,14 +432,18 @@ public class AbilityLevelTask(PlayerInstance player)
await instance.GainMoney(Random.Shared.Next(20, 60));
}
}
return new AbilityLevelResult();
}
#endregion
#region Predicate
public bool ByAllowInstantKill(AbilityLevelParam param)
public async ValueTask<object> ByAllowInstantKill(AbilityLevelParam param)
{
await ValueTask.CompletedTask;
foreach (var targetEntity in param.TargetEntities)
if (targetEntity is EntityMonster monster)
if (monster.MonsterData.Rank < MonsterRankEnum.Elite)
@@ -434,30 +452,31 @@ public class AbilityLevelTask(PlayerInstance player)
return false;
}
public bool ByIsContainAdventureModifier(AbilityLevelParam param)
public async ValueTask<object> ByIsContainAdventureModifier(AbilityLevelParam param)
{
await ValueTask.CompletedTask;
if (param.Act is ByIsContainAdventureModifier byIsContain)
{
// get target
var result = false;
var methodName = byIsContain.TargetType.Type.Replace("RPG.GameCore.", "");
var method = GetType().GetMethod(methodName);
if (method != null)
{
var resp = method.Invoke(this,
[byIsContain.TargetType, param.CasterEntity, param.TargetEntities]);
if (resp is List<BaseGameEntity> target)
foreach (var entity in target)
var method = GetOrCreateExecuteTask(methodName);
if (method == null) return false;
var resp = await method(param with { TargetEvaluator = byIsContain.TargetType });
if (resp is List<BaseGameEntity> target)
foreach (var entity in target)
{
if (entity is not IGameModifier modifier) continue;
if (modifier.Modifiers.Contains(byIsContain.ModifierName))
{
if (entity is not IGameModifier modifier) continue;
if (modifier.Modifiers.Contains(byIsContain.ModifierName))
{
result = true;
break;
}
result = true;
break;
}
}
}
return result;
}
@@ -465,42 +484,50 @@ public class AbilityLevelTask(PlayerInstance player)
return false;
}
public bool AdventureByInMotionState(AbilityLevelParam param)
public async ValueTask<object> AdventureByInMotionState(AbilityLevelParam param)
{
await ValueTask.CompletedTask;
return true;
}
public bool AdventureByPlayerCurrentSkillType(AbilityLevelParam param)
public async ValueTask<object> AdventureByPlayerCurrentSkillType(AbilityLevelParam param)
{
await ValueTask.CompletedTask;
if (param.Act is AdventureByPlayerCurrentSkillType byPlayerCurrentSkillType)
return param.Request.SkillIndex == (uint)byPlayerCurrentSkillType.SkillType;
return false;
}
public bool ByCompareCarryMazebuff(AbilityLevelParam param)
public async ValueTask<object> ByCompareCarryMazebuff(AbilityLevelParam param)
{
await ValueTask.CompletedTask;
if (param.Act is ByCompareCarryMazebuff byCompareCarryMazebuff)
return param.CasterEntity.BuffList.Any(x => x.BuffId == byCompareCarryMazebuff.BuffID);
return false;
}
public bool ByAnd(AbilityLevelParam param)
public async ValueTask<object> ByAnd(AbilityLevelParam param)
{
await ValueTask.CompletedTask;
if (param.Act is ByAnd byAnd)
{
foreach (var task in byAnd.PredicateList)
{
var methodName = task.Type.Replace("RPG.GameCore.", "");
var method = GetType().GetMethod(methodName);
if (method != null)
{
var resp = method.Invoke(this, [param with { Act = task }]);
if (resp is not bool res) return false;
res = task.Inverse ? !res : res;
if (!res) return false;
}
var method = GetOrCreateExecuteTask(methodName);
if (method == null) return false;
var resp = await method(param with { Act = task });
if (resp is not bool res) return false;
res = task.Inverse ? !res : res;
if (!res) return false;
}
return true;
@@ -520,4 +547,5 @@ public record AbilityLevelParam(
BaseGameEntity CasterEntity,
List<BaseGameEntity> TargetEntities,
SceneCastSkillCsReq Request,
string? ModifierName);
string? ModifierName,
TargetEvaluator? TargetEvaluator = null);

View File

@@ -3,6 +3,8 @@ using EggLink.DanhengServer.GameServer.Game.Scene;
using EggLink.DanhengServer.GameServer.Game.Scene.Entity;
using EggLink.DanhengServer.GameServer.Server.Packet.Send.Lineup;
using EggLink.DanhengServer.Proto;
using System.Collections.Concurrent;
using EggLink.DanhengServer.Util;
namespace EggLink.DanhengServer.GameServer.Game.Task.AvatarTask;
@@ -10,9 +12,11 @@ public class SummonUnitLevelTask
{
#region Task Condition
public bool ByIsContainAdventureModifier(TaskConfigInfo act, List<BaseGameEntity> targetEntities,
public async ValueTask<object?> ByIsContainAdventureModifier(TaskConfigInfo act, List<BaseGameEntity> targetEntities,
EntitySummonUnit? summonUnit)
{
await ValueTask.CompletedTask;
return true;
}
@@ -31,19 +35,40 @@ public class SummonUnitLevelTask
{
var methodName = act.Type.Replace("RPG.GameCore.", "");
var method = GetType().GetMethod(methodName);
if (method != null) _ = method.Invoke(this, [act, targetEntities, summonUnit]);
// try to get from cache
var method = GetOrCreateExecuteTask(methodName);
if (method == null) return;
method(act, targetEntities, summonUnit);
}
catch
catch (Exception e)
{
Logger.GetByClassName().Error("An error occured, ", e);
}
}
private ExecuteTask? GetOrCreateExecuteTask(string methodName)
{
// try to get from cache
if (_cachedTasks.TryGetValue(methodName, out var method)) return method;
var methodProp = GetType().GetMethod(methodName);
if (methodProp == null) return null;
method = (ExecuteTask)Delegate.CreateDelegate(typeof(ExecuteTask), this, methodProp);
_cachedTasks[methodName] = method; // cached
return method;
}
private delegate ValueTask<object?> ExecuteTask(TaskConfigInfo act, List<BaseGameEntity> targetEntities, EntitySummonUnit? summonUnit);
private readonly ConcurrentDictionary<string, ExecuteTask> _cachedTasks = [];
#endregion
#region Task
public async ValueTask PredicateTaskList(TaskConfigInfo act, List<BaseGameEntity> targetEntities,
public async ValueTask<object?> PredicateTaskList(TaskConfigInfo act, List<BaseGameEntity> targetEntities,
EntitySummonUnit? summonUnit)
{
if (act is PredicateTaskList predicateTaskList)
@@ -51,26 +76,25 @@ public class SummonUnitLevelTask
// handle predicateCondition
var methodName = predicateTaskList.Predicate.Type.Replace("RPG.GameCore.", "");
var method = GetType().GetMethod(methodName);
if (method != null)
{
var resp = method.Invoke(this, [predicateTaskList.Predicate, targetEntities, summonUnit]);
if (resp is bool res && res)
foreach (var task in predicateTaskList.SuccessTaskList)
TriggerTask(task, targetEntities, summonUnit);
else
foreach (var task in predicateTaskList.FailedTaskList)
TriggerTask(task, targetEntities, summonUnit);
}
var method = GetOrCreateExecuteTask(methodName);
if (method == null) return null;
var resp = await method(predicateTaskList.Predicate, targetEntities, summonUnit);
if (resp is true)
foreach (var task in predicateTaskList.SuccessTaskList)
TriggerTask(task, targetEntities, summonUnit);
else
foreach (var task in predicateTaskList.FailedTaskList)
TriggerTask(task, targetEntities, summonUnit);
}
await ValueTask.CompletedTask;
return null;
}
public async ValueTask AddMazeBuff(TaskConfigInfo act, List<BaseGameEntity> targetEntities,
public async ValueTask<object?> AddMazeBuff(TaskConfigInfo act, List<BaseGameEntity> targetEntities,
EntitySummonUnit? summonUnit)
{
if (act is not AddMazeBuff addMazeBuff) return;
if (act is not AddMazeBuff addMazeBuff) return null;
var buff = new SceneBuff(addMazeBuff.ID, 1, summonUnit?.CreateAvatarId ?? 0)
{
@@ -86,12 +110,14 @@ public class SummonUnitLevelTask
await monster.AddBuff(buff);
}
return null;
}
public async ValueTask RemoveMazeBuff(TaskConfigInfo act, List<BaseGameEntity> targetEntities,
public async ValueTask<object?> RemoveMazeBuff(TaskConfigInfo act, List<BaseGameEntity> targetEntities,
EntitySummonUnit? summonUnit)
{
if (act is not RemoveMazeBuff removeMazeBuff) return;
if (act is not RemoveMazeBuff removeMazeBuff) return null;
foreach (var targetEntity in targetEntities)
{
@@ -99,12 +125,14 @@ public class SummonUnitLevelTask
await monster.RemoveBuff(removeMazeBuff.ID);
}
return null;
}
public async ValueTask RefreshMazeBuffTime(TaskConfigInfo act, List<BaseGameEntity> targetEntities,
public async ValueTask<object?> RefreshMazeBuffTime(TaskConfigInfo act, List<BaseGameEntity> targetEntities,
EntitySummonUnit? summonUnit)
{
if (act is not RefreshMazeBuffTime refreshMazeBuffTime) return;
if (act is not RefreshMazeBuffTime refreshMazeBuffTime) return null;
var buff = new SceneBuff(refreshMazeBuffTime.ID, 1, summonUnit?.CreateAvatarId ?? 0)
{
@@ -118,9 +146,11 @@ public class SummonUnitLevelTask
await monster.AddBuff(buff);
}
return null;
}
public async ValueTask TriggerHitProp(TaskConfigInfo act, List<BaseGameEntity> targetEntities,
public async ValueTask<object?> TriggerHitProp(TaskConfigInfo act, List<BaseGameEntity> targetEntities,
EntitySummonUnit? summonUnit)
{
foreach (var targetEntity in targetEntities)
@@ -145,6 +175,8 @@ public class SummonUnitLevelTask
prop.Scene.Player.RogueManager!.GetRogueInstance()?.OnPropDestruct(prop);
}
return null;
}
#endregion

View File

@@ -7,7 +7,9 @@ using EggLink.DanhengServer.Enums.Scene;
using EggLink.DanhengServer.Enums.Task;
using EggLink.DanhengServer.GameServer.Game.Player;
using EggLink.DanhengServer.GameServer.Game.Scene.Entity;
using EggLink.DanhengServer.GameServer.Game.Task.AvatarTask;
using EggLink.DanhengServer.Proto;
using System.Collections.Concurrent;
namespace EggLink.DanhengServer.GameServer.Game.Task;
@@ -17,8 +19,10 @@ public class LevelTask(PlayerInstance player)
#region Prop Target
public EntityProp? TargetFetchAdvPropEx(TargetEvaluator act, SubMissionData subMission, GroupInfo? group = null)
public async ValueTask<object?> TargetFetchAdvPropEx(TargetEvaluator act, SubMissionData subMission, GroupInfo? group = null)
{
await ValueTask.CompletedTask;
if (act is TargetFetchAdvPropEx fetch)
{
if (fetch.FetchType != TargetFetchAdvPropFetchTypeEnum.SinglePropByPropID) return null;
@@ -51,33 +55,54 @@ public class LevelTask(PlayerInstance player)
{
var methodName = act.Type.Replace("RPG.GameCore.", "");
var method = GetType().GetMethod(methodName);
if (method != null) _ = method.Invoke(this, [act, subMission, group]);
var method = GetOrCreateExecuteTask(methodName);
if (method != null) _ = method(act, subMission, group);
}
catch
{
}
}
private ExecuteTask? GetOrCreateExecuteTask(string methodName)
{
// try to get from cache
if (_cachedTasks.TryGetValue(methodName, out var method)) return method;
var methodProp = GetType().GetMethod(methodName);
if (methodProp == null) return null;
method = (ExecuteTask)Delegate.CreateDelegate(typeof(ExecuteTask), this, methodProp);
_cachedTasks[methodName] = method; // cached
return method;
}
private delegate ValueTask<object?> ExecuteTask(TaskConfigInfo act, SubMissionData subMission, GroupInfo? group = null);
private readonly ConcurrentDictionary<string, ExecuteTask> _cachedTasks = [];
#endregion
#region Task
public async ValueTask PlayMessage(TaskConfigInfo act, SubMissionData subMission, GroupInfo? group = null)
public async ValueTask<object?> PlayMessage(TaskConfigInfo act, SubMissionData subMission, GroupInfo? group = null)
{
if (act is PlayMessage message) await Player.MessageManager!.AddMessageSection(message.MessageSectionID);
return null;
}
public async ValueTask DestroyProp(TaskConfigInfo act, SubMissionData subMission, GroupInfo? group = null)
public async ValueTask<object?> DestroyProp(TaskConfigInfo act, SubMissionData subMission, GroupInfo? group = null)
{
if (act is DestroyProp destroyProp)
foreach (var entity in Player.SceneInstance!.Entities.Values)
if (entity is EntityProp prop && prop.GroupId == destroyProp.GroupID.GetValue() &&
prop.InstId == destroyProp.ID.GetValue())
await Player.SceneInstance.RemoveEntity(entity);
return null;
}
public async ValueTask TriggerCustomString(TaskConfigInfo act, SubMissionData subMission, GroupInfo? group = null)
public async ValueTask<object?> TriggerCustomString(TaskConfigInfo act, SubMissionData subMission, GroupInfo? group = null)
{
if (act is TriggerCustomString triggerCustomString)
{
@@ -91,21 +116,27 @@ public class LevelTask(PlayerInstance player)
await Player.MissionManager!.HandleFinishType(MissionFinishTypeEnum.PropState);
}
return null;
}
public async ValueTask EnterMap(TaskConfigInfo act, SubMissionData subMission, GroupInfo? group = null)
public async ValueTask<object?> EnterMap(TaskConfigInfo act, SubMissionData subMission, GroupInfo? group = null)
{
if (act is EnterMap enterMap)
await Player.EnterSceneByEntranceId(enterMap.EntranceID, enterMap.GroupID, enterMap.AnchorID, true);
return null;
}
public async ValueTask EnterMapByCondition(TaskConfigInfo act, SubMissionData subMission, GroupInfo? group = null)
public async ValueTask<object?> EnterMapByCondition(TaskConfigInfo act, SubMissionData subMission, GroupInfo? group = null)
{
if (act is EnterMapByCondition enterMapByCondition)
await Player.EnterSceneByEntranceId(enterMapByCondition.EntranceID.GetValue(), 0, 0, true);
return null;
}
public async ValueTask TriggerPerformance(TaskConfigInfo act, SubMissionData subMission, GroupInfo? group = null)
public async ValueTask<object?> TriggerPerformance(TaskConfigInfo act, SubMissionData subMission, GroupInfo? group = null)
{
if (act is TriggerPerformance triggerPerformance)
{
@@ -117,63 +148,68 @@ public class LevelTask(PlayerInstance player)
subMission);
}
await System.Threading.Tasks.Task.CompletedTask;
await ValueTask.CompletedTask;
return null;
}
public async ValueTask PredicateTaskList(TaskConfigInfo act, SubMissionData subMission, GroupInfo? group = null)
public async ValueTask<object?> PredicateTaskList(TaskConfigInfo act, SubMissionData subMission, GroupInfo? group = null)
{
if (act is PredicateTaskList predicateTaskList)
{
// handle predicateCondition
var methodName = predicateTaskList.Predicate.Type.Replace("RPG.GameCore.", "");
var method = GetType().GetMethod(methodName);
if (method != null)
{
var resp = method.Invoke(this, [predicateTaskList.Predicate, subMission, group]);
if (resp is bool res && res)
foreach (var task in predicateTaskList.SuccessTaskList)
TriggerTask(task, subMission, group);
else
foreach (var task in predicateTaskList.FailedTaskList)
TriggerTask(task, subMission, group);
}
var method = GetOrCreateExecuteTask(methodName);
if (method == null) return null;
var resp = await method(predicateTaskList.Predicate, subMission, group);
if (resp is true)
foreach (var task in predicateTaskList.SuccessTaskList)
TriggerTask(task, subMission, group);
else
foreach (var task in predicateTaskList.FailedTaskList)
TriggerTask(task, subMission, group);
}
await System.Threading.Tasks.Task.CompletedTask;
return null;
}
public async ValueTask ChangePropState(TaskConfigInfo act, SubMissionData subMission, GroupInfo? group = null)
public async ValueTask<object?> ChangePropState(TaskConfigInfo act, SubMissionData subMission, GroupInfo? group = null)
{
if (subMission.SubMissionInfo?.FinishType == MissionFinishTypeEnum.PropState)
foreach (var entity in Player.SceneInstance!.Entities.Values)
if (entity is EntityProp prop && prop.GroupId == subMission.SubMissionInfo.ParamInt1 &&
prop.InstId == subMission.SubMissionInfo.ParamInt2)
try
{
if (prop.Excel.PropStateList.Contains(PropStateEnum.Closed))
{
await prop.SetState(PropStateEnum.Closed);
}
else
{
await prop.SetState(
prop.Excel.PropStateList[prop.Excel.PropStateList.IndexOf(prop.State) + 1]);
if (subMission.SubMissionInfo?.FinishType != MissionFinishTypeEnum.PropState) return null;
// Elevator
foreach (var id in prop.PropInfo.UnlockControllerID)
foreach (var entity2 in Player.SceneInstance!.Entities.Values)
if (entity2 is EntityProp prop2 && prop2.GroupId == id.Key &&
id.Value.Contains(prop2.InstId))
await prop2.SetState(PropStateEnum.Closed);
}
}
catch
foreach (var entity in Player.SceneInstance!.Entities.Values)
if (entity is EntityProp prop && prop.GroupId == subMission.SubMissionInfo.ParamInt1 &&
prop.InstId == subMission.SubMissionInfo.ParamInt2)
try
{
if (prop.Excel.PropStateList.Contains(PropStateEnum.Closed))
{
await prop.SetState(PropStateEnum.Closed);
}
else
{
await prop.SetState(
prop.Excel.PropStateList[prop.Excel.PropStateList.IndexOf(prop.State) + 1]);
// Elevator
foreach (var id in prop.PropInfo.UnlockControllerID)
foreach (var entity2 in Player.SceneInstance!.Entities.Values)
if (entity2 is EntityProp prop2 && prop2.GroupId == id.Key &&
id.Value.Contains(prop2.InstId))
await prop2.SetState(PropStateEnum.Closed);
}
}
catch
{
// ignored
}
return null;
}
public async ValueTask CreateTrialPlayer(TaskConfigInfo act, SubMissionData subMission, GroupInfo? group = null)
public async ValueTask<object?> CreateTrialPlayer(TaskConfigInfo act, SubMissionData subMission, GroupInfo? group = null)
{
if (subMission.SubMissionInfo?.FinishType == MissionFinishTypeEnum.GetTrialAvatar)
await Player.LineupManager!.AddAvatarToCurTeam(subMission.SubMissionInfo.ParamInt1);
@@ -181,9 +217,11 @@ public class LevelTask(PlayerInstance player)
if (subMission.SubMissionInfo?.FinishType == MissionFinishTypeEnum.GetTrialAvatarList)
subMission.SubMissionInfo.ParamIntList?.ForEach(
async x => await Player.LineupManager!.AddAvatarToCurTeam(x));
return null;
}
public async ValueTask ReplaceTrialPlayer(TaskConfigInfo act, SubMissionData subMission, GroupInfo? group = null)
public async ValueTask<object?> ReplaceTrialPlayer(TaskConfigInfo act, SubMissionData subMission, GroupInfo? group = null)
{
if (subMission.SubMissionInfo?.FinishType == MissionFinishTypeEnum.GetTrialAvatar)
{
@@ -199,9 +237,11 @@ public class LevelTask(PlayerInstance player)
subMission.SubMissionInfo.ParamIntList?.ForEach(
async x => await Player.LineupManager!.AddAvatarToCurTeam(x));
}
return null;
}
public async ValueTask StoryLineReplaceTrialPlayer(TaskConfigInfo act, SubMissionData subMission, GroupInfo? group = null)
public async ValueTask<object?> StoryLineReplaceTrialPlayer(TaskConfigInfo act, SubMissionData subMission, GroupInfo? group = null)
{
if (subMission.SubMissionInfo?.FinishType == MissionFinishTypeEnum.StoryLineAddTrialAvatar)
{
@@ -209,11 +249,13 @@ public class LevelTask(PlayerInstance player)
ids.ForEach(async void (x) => await Player.LineupManager!.RemoveAvatarFromCurTeam(x.BaseAvatarId, false));
await Player.LineupManager!.AddAvatarToCurTeam(subMission.SubMissionInfo.ParamInt1);
}
return null;
}
public async ValueTask ReplaceVirtualTeam(TaskConfigInfo act, SubMissionData subMission, GroupInfo? group = null)
public async ValueTask<object?> ReplaceVirtualTeam(TaskConfigInfo act, SubMissionData subMission, GroupInfo? group = null)
{
if (Player.LineupManager!.GetCurLineup()?.IsExtraLineup() != true) return;
if (Player.LineupManager!.GetCurLineup()?.IsExtraLineup() != true) return null;
if (subMission.SubMissionInfo?.FinishType == MissionFinishTypeEnum.GetTrialAvatar)
{
@@ -230,9 +272,11 @@ public class LevelTask(PlayerInstance player)
subMission.SubMissionInfo.ParamIntList?.ForEach(
async x => await Player.LineupManager!.AddAvatarToCurTeam(x));
}
return null;
}
public async ValueTask CreateHeroTrialPlayer(TaskConfigInfo act, SubMissionData subMission,
public async ValueTask<object?> CreateHeroTrialPlayer(TaskConfigInfo act, SubMissionData subMission,
GroupInfo? group = null)
{
if (subMission.SubMissionInfo?.FinishType == MissionFinishTypeEnum.GetTrialAvatar)
@@ -266,24 +310,30 @@ public class LevelTask(PlayerInstance player)
list.ForEach(async x => await Player.LineupManager!.AddAvatarToCurTeam(x));
}
return null;
}
public async ValueTask DestroyTrialPlayer(TaskConfigInfo act, SubMissionData subMission, GroupInfo? group = null)
public async ValueTask<object?> DestroyTrialPlayer(TaskConfigInfo act, SubMissionData subMission, GroupInfo? group = null)
{
if (subMission.SubMissionInfo?.FinishType == MissionFinishTypeEnum.DelTrialAvatar)
await Player.LineupManager!.RemoveAvatarFromCurTeam(subMission.SubMissionInfo.ParamInt1);
return null;
}
public async ValueTask ChangeGroupState(TaskConfigInfo act, SubMissionData subMission, GroupInfo? group = null)
public async ValueTask<object?> ChangeGroupState(TaskConfigInfo act, SubMissionData subMission, GroupInfo? group = null)
{
if (group != null)
foreach (var entity in Player.SceneInstance?.Entities.Values.ToList() ?? [])
if (entity is EntityProp prop && prop.GroupId == group.Id)
if (prop.Excel.PropStateList.Contains(PropStateEnum.Open))
await prop.SetState(PropStateEnum.Open);
return null;
}
public async ValueTask TriggerEntityServerEvent(TaskConfigInfo act, SubMissionData subMission,
public async ValueTask<object?> TriggerEntityServerEvent(TaskConfigInfo act, SubMissionData subMission,
GroupInfo? group = null)
{
if (group != null)
@@ -292,9 +342,11 @@ public class LevelTask(PlayerInstance player)
if (prop.Excel.PropStateList.Contains(PropStateEnum.Open) &&
(prop.State == PropStateEnum.Closed || prop.State == PropStateEnum.Locked))
await prop.SetState(PropStateEnum.Open);
return null;
}
public async ValueTask TriggerEntityEvent(TaskConfigInfo act, SubMissionData subMission, GroupInfo? group = null)
public async ValueTask<object?> TriggerEntityEvent(TaskConfigInfo act, SubMissionData subMission, GroupInfo? group = null)
{
if (act is TriggerEntityEvent triggerEntityEvent)
if (group != null)
@@ -303,18 +355,22 @@ public class LevelTask(PlayerInstance player)
prop.InstId == triggerEntityEvent.InstanceID.GetValue())
if (prop.Excel.PropStateList.Contains(PropStateEnum.Closed))
await prop.SetState(PropStateEnum.Closed);
return null;
}
public async ValueTask PropSetupUITrigger(TaskConfigInfo act, SubMissionData subMission, GroupInfo? group = null)
public async ValueTask<object?> PropSetupUITrigger(TaskConfigInfo act, SubMissionData subMission, GroupInfo? group = null)
{
if (act is PropSetupUITrigger propSetupUiTrigger)
foreach (var task in propSetupUiTrigger.ButtonCallback)
TriggerTask(task, subMission, group);
await System.Threading.Tasks.Task.CompletedTask;
await ValueTask.CompletedTask;
return null;
}
public async ValueTask PropStateExecute(TaskConfigInfo act, SubMissionData subMission, GroupInfo? group = null)
public async ValueTask<object?> PropStateExecute(TaskConfigInfo act, SubMissionData subMission, GroupInfo? group = null)
{
if (act is PropStateExecute propStateExecute)
{
@@ -328,14 +384,18 @@ public class LevelTask(PlayerInstance player)
if (resp is EntityProp result) await result.SetState(propStateExecute.State);
}
}
return null;
}
#endregion
#region Task Condition
public bool ByCompareSubMissionState(TaskConfigInfo act, SubMissionData subMission, GroupInfo? group = null)
public async ValueTask<object?> ByCompareSubMissionState(TaskConfigInfo act, SubMissionData subMission, GroupInfo? group = null)
{
await ValueTask.CompletedTask;
if (act is ByCompareSubMissionState compare)
{
var mission = Player.MissionManager!.GetSubMissionStatus(compare.SubMissionID);
@@ -345,8 +405,10 @@ public class LevelTask(PlayerInstance player)
return false;
}
public bool ByCompareFloorSavedValue(TaskConfigInfo act, SubMissionData subMission, GroupInfo? group = null)
public async ValueTask<object?> ByCompareFloorSavedValue(TaskConfigInfo act, SubMissionData subMission, GroupInfo? group = null)
{
await ValueTask.CompletedTask;
if (act is ByCompareFloorSavedValue compare)
{
var value = Player.SceneData!.FloorSavedData.GetValueOrDefault(Player.Data.FloorId, []);

View File

@@ -1,5 +1,13 @@
using EggLink.DanhengServer.GameServer.Game.Lobby;
using EggLink.DanhengServer.Enums.Rogue;
using EggLink.DanhengServer.GameServer.Game.ChessRogue.Modifier.ModifierEffect;
using EggLink.DanhengServer.GameServer.Game.Lobby;
using EggLink.DanhengServer.GameServer.Game.Mission;
using EggLink.DanhengServer.GameServer.Game.Mission.FinishAction;
using EggLink.DanhengServer.GameServer.Game.Mission.FinishType;
using EggLink.DanhengServer.GameServer.Game.MultiPlayer;
using EggLink.DanhengServer.GameServer.Game.Rogue.Event;
using System.Reflection;
using EggLink.DanhengServer.GameServer.Game.ChessRogue;
namespace EggLink.DanhengServer.GameServer.Server;
@@ -7,4 +15,63 @@ public static class ServerUtils
{
public static LobbyServerManager LobbyServerManager { get; set; } = new();
public static MultiPlayerGameServerManager MultiPlayerGameServerManager { get; set; } = new();
public static void InitializeHandlers()
{
// mission handlers
{
var types = Assembly.GetExecutingAssembly().GetTypes();
foreach (var type in types)
{
var attr = type.GetCustomAttribute<MissionFinishActionAttribute>();
if (attr != null)
{
var handler = (MissionFinishActionHandler)Activator.CreateInstance(type, null)!;
MissionManager.ActionHandlers.Add(attr.FinishAction, handler);
}
var attr2 = type.GetCustomAttribute<MissionFinishTypeAttribute>();
if (attr2 != null)
{
var handler = (MissionFinishTypeHandler)Activator.CreateInstance(type, null)!;
MissionManager.FinishTypeHandlers.Add(attr2.FinishType, handler);
}
}
}
// rogue event handlers
{
var types = Assembly.GetExecutingAssembly().GetTypes();
foreach (var type in types)
{
var attr = type.GetCustomAttribute<RogueEventAttribute>();
if (attr == null) continue;
if (attr.EffectType != DialogueEventTypeEnum.None)
{
// Effect
var effect = (RogueEventEffectHandler)Activator.CreateInstance(type, null)!;
RogueEventManager.EffectHandler.Add(attr.EffectType, effect);
}
else
{
// Cost
var cost = (RogueEventCostHandler)Activator.CreateInstance(type, null)!;
RogueEventManager.CostHandler.Add(attr.CostType, cost);
}
}
}
// chess rogue modifier handlers
{
var types = Assembly.GetExecutingAssembly().GetTypes();
foreach (var type in types)
{
var attr = type.GetCustomAttribute<ModifierEffectAttribute>();
if (attr == null) continue;
var handler = (ModifierEffectHandler)Activator.CreateInstance(type, null)!;
ChessRogueInstance.ModifierEffectHandlers.Add(attr.EffectType, handler);
}
}
}
}

View File

@@ -166,7 +166,8 @@ public class EntryPoint
Logger.Info(I18NManager.Translate("Server.ServerInfo.ServerRunning", I18NManager.Translate("Word.Dispatch"),
GetConfig().HttpServer.GetDisplayAddress()));
DanhengListener.BaseConnection = typeof(Connection);
var handler = new DanhengListener.ConnectionCreatedHandler((conversation, remote) => new Connection(conversation, remote));
DanhengListener.CreateConnection = handler;
DanhengListener.StartListener();
GenerateLogMap();
@@ -326,6 +327,8 @@ public class EntryPoint
Logger.Info(I18NManager.Translate("Server.ServerInfo.LoadedItem", I18NManager.Translate("Word.Database")));
}
ServerUtils.InitializeHandlers();
// check if the database is up to date
var updated = false;
foreach (var avatarData in DatabaseHelper.GetAllInstanceFromMap<AvatarData>()!)