Compare commits

..

No commits in common. "master" and "0.1.0" have entirely different histories.

80 changed files with 523 additions and 25153 deletions

View file

@ -16,12 +16,7 @@ public class ConfigManager
logger.LogInformation("Loaded {count} config collections", _collectionsByEnum.Count); logger.LogInformation("Loaded {count} config collections", _collectionsByEnum.Count);
} }
public IEnumerable<TConfig> Enumerate<TConfig>() where TConfig : IConfig public ConfigCollection GetCollection<TConfigType>()
{
return GetCollection<TConfig>().Enumerate<TConfig>();
}
public ConfigCollection GetCollection<TConfigType>() where TConfigType : IConfig
{ {
return _collectionsByType[typeof(TConfigType)]; return _collectionsByType[typeof(TConfigType)];
} }

View file

@ -5,6 +5,5 @@ public enum ConfigType
Weapon, Weapon,
BaseProperty, BaseProperty,
LevelEntity, LevelEntity,
Blueprint, Blueprint
ItemInfo
} }

View file

@ -1,38 +0,0 @@
using Core.Config.Attributes;
namespace Core.Config;
[ConfigCollection("item/iteminfo.json")]
public class ItemInfoConfig : IConfig
{
public ConfigType Type => ConfigType.ItemInfo;
public int Identifier => Id;
public int Id { get; set; }
public int ItemType { get; set; }
public string Name { get; set; } = string.Empty;
public List<int> ShowTypes { get; set; } = [];
public string AttributesDescription { get; set; } = string.Empty;
public string BgDescription { get; set; } = string.Empty;
public string Mesh { get; set; } = string.Empty;
public int QualityId { get; set; }
public int MainTypeId { get; set; }
public int RedDotDisableRule { get; set; }
public int UseCountLimit { get; set; }
public int SortIndex { get; set; }
public int MaxCapcity { get; set; }
public int MaxStackableNum { get; set; }
public int UseLevel { get; set; }
public int BeginTimeStamp { get; set; }
public int DurationStamp { get; set; }
public bool ShowUseButton { get; set; }
public int ObtainedShow { get; set; }
public string ObtainedShowDescription { get; set; } = string.Empty;
public int EntityConfig { get; set; }
public int NumLimit { get; set; }
public bool ShowInBag { get; set; }
public bool Destructible { get; set; }
public int ItemBuffType { get; set; }
public bool SpecialItem { get; set; }
public bool UiPlayItem { get; set; }
}

View file

@ -14,7 +14,6 @@
<ItemGroup> <ItemGroup>
<None Remove="data\config\blueprint\blueprintconfig.json" /> <None Remove="data\config\blueprint\blueprintconfig.json" />
<None Remove="data\config\item\iteminfo.json" />
<None Remove="data\config\property\baseproperty.json" /> <None Remove="data\config\property\baseproperty.json" />
<None Remove="data\config\weapon\weaponconf.json" /> <None Remove="data\config\weapon\weaponconf.json" />
</ItemGroup> </ItemGroup>

File diff suppressed because it is too large Load diff

View file

@ -10,14 +10,14 @@
"ResonLevelLimit": 5, "ResonLevelLimit": 5,
"FirstPropId": { "FirstPropId": {
"Id": 7, "Id": 7,
"Value": 47, "Value": 54,
"IsRatio": false "IsRatio": false
}, },
"FirstCurve": 1, "FirstCurve": 1,
"SecondPropId": { "SecondPropId": {
"Id": 10007, "Id": 11,
"Value": 0.08100000023841858, "Value": 432,
"IsRatio": true "IsRatio": false
}, },
"SecondCurve": 2, "SecondCurve": 2,
"ResonId": 21010015, "ResonId": 21010015,
@ -26,7 +26,7 @@
"Desc": "WeaponConf_21010015_Desc", "Desc": "WeaponConf_21010015_Desc",
"DescParams": [ "DescParams": [
{ {
"ArrayString": [ "12.8%", "16%", "19.2%", "22.4%", "25.6%" ] "ArrayString": [ "12%", "15%", "18%", "21%", "24%" ]
}, },
{ {
"ArrayString": [ "8%", "10%", "12%", "14%", "16%" ] "ArrayString": [ "8%", "10%", "12%", "14%", "16%" ]
@ -35,7 +35,7 @@
"ArrayString": [ "2", "2", "2", "2", "2" ] "ArrayString": [ "2", "2", "2", "2", "2" ]
}, },
{ {
"ArrayString": [ "12", "12", "12", "12", "12" ] "ArrayString": [ "8", "8", "8", "8", "8" ]
} }
], ],
"TypeDescription": "WeaponConf_21010015_TypeDescription", "TypeDescription": "WeaponConf_21010015_TypeDescription",
@ -84,16 +84,16 @@
"Desc": "WeaponConf_21020015_Desc", "Desc": "WeaponConf_21020015_Desc",
"DescParams": [ "DescParams": [
{ {
"ArrayString": [ "12.8%", "16%", "19.2%", "22.4%", "25.6%" ] "ArrayString": [ "16%", "20%", "24%", "28%", "32%" ]
}, },
{ {
"ArrayString": [ "6%", "7.5%", "9%", "10.5%", "12%" ] "ArrayString": [ "8%", "10%", "12%", "14%", "16%" ]
}, },
{ {
"ArrayString": [ "2", "2", "2", "2", "2" ] "ArrayString": [ "2", "2", "2", "2", "2" ]
}, },
{ {
"ArrayString": [ "10", "10", "10", "10", "10" ] "ArrayString": [ "8", "8", "8", "8", "8" ]
} }
], ],
"TypeDescription": "WeaponConf_21020015_TypeDescription", "TypeDescription": "WeaponConf_21020015_TypeDescription",
@ -142,16 +142,16 @@
"Desc": "WeaponConf_21030015_Desc", "Desc": "WeaponConf_21030015_Desc",
"DescParams": [ "DescParams": [
{ {
"ArrayString": [ "12.8%", "16%", "19.2%", "22.4%", "25.6%" ] "ArrayString": [ "12%", "15%", "18%", "21%", "24%" ]
}, },
{ {
"ArrayString": [ "10%", "12.5%", "15%", "17.5%", "20%" ] "ArrayString": [ "2.4%", "3%", "3.6%", "4.2%", "4.8%" ]
}, },
{ {
"ArrayString": [ "1", "1", "1", "1", "1" ] "ArrayString": [ "5", "5", "5", "5", "5" ]
}, },
{ {
"ArrayString": [ "14", "14", "14", "14", "14" ] "ArrayString": [ "8", "8", "8", "8", "8" ]
} }
], ],
"TypeDescription": "WeaponConf_21030015_TypeDescription", "TypeDescription": "WeaponConf_21030015_TypeDescription",
@ -189,9 +189,9 @@
}, },
"FirstCurve": 1, "FirstCurve": 1,
"SecondPropId": { "SecondPropId": {
"Id": 10007, "Id": 11,
"Value": 0.08100000023841858, "Value": 864,
"IsRatio": true "IsRatio": false
}, },
"SecondCurve": 2, "SecondCurve": 2,
"ResonId": 21040015, "ResonId": 21040015,
@ -200,7 +200,7 @@
"Desc": "WeaponConf_21040015_Desc", "Desc": "WeaponConf_21040015_Desc",
"DescParams": [ "DescParams": [
{ {
"ArrayString": [ "12.8%", "16%", "19.2%", "22.4%", "25.6%" ] "ArrayString": [ "8%", "10%", "12%", "14%", "16%" ]
}, },
{ {
"ArrayString": [ "10%", "12.5%", "15%", "17.5%", "20%" ] "ArrayString": [ "10%", "12.5%", "15%", "17.5%", "20%" ]
@ -250,9 +250,9 @@
}, },
"FirstCurve": 1, "FirstCurve": 1,
"SecondPropId": { "SecondPropId": {
"Id": 10007, "Id": 11,
"Value": 0.11999999731779099, "Value": 1280,
"IsRatio": true "IsRatio": false
}, },
"SecondCurve": 2, "SecondCurve": 2,
"ResonId": 21050015, "ResonId": 21050015,
@ -261,7 +261,7 @@
"Desc": "WeaponConf_21050015_Desc", "Desc": "WeaponConf_21050015_Desc",
"DescParams": [ "DescParams": [
{ {
"ArrayString": [ "12.8%", "16%", "19.2%", "22.4%", "25.6%" ] "ArrayString": [ "16%", "20%", "24%", "28%", "32%" ]
}, },
{ {
"ArrayString": [ "3.2%", "4%", "4.8%", "5.6%", "6.4%" ] "ArrayString": [ "3.2%", "4%", "4.8%", "5.6%", "6.4%" ]
@ -1670,13 +1670,13 @@
"ResonLevelLimit": 5, "ResonLevelLimit": 5,
"FirstPropId": { "FirstPropId": {
"Id": 7, "Id": 7,
"Value": 27, "Value": 31,
"IsRatio": false "IsRatio": false
}, },
"FirstCurve": 1, "FirstCurve": 1,
"SecondPropId": { "SecondPropId": {
"Id": 10010, "Id": 10010,
"Value": 0.13680000603199005, "Value": 0.10260000079870224,
"IsRatio": true "IsRatio": true
}, },
"SecondCurve": 2, "SecondCurve": 2,
@ -1834,8 +1834,8 @@
}, },
"FirstCurve": 1, "FirstCurve": 1,
"SecondPropId": { "SecondPropId": {
"Id": 10010, "Id": 10007,
"Value": 0.13680000603199005, "Value": 0.1080000028014183,
"IsRatio": true "IsRatio": true
}, },
"SecondCurve": 2, "SecondCurve": 2,
@ -1886,7 +1886,7 @@
}, },
"FirstCurve": 1, "FirstCurve": 1,
"SecondPropId": { "SecondPropId": {
"Id": 10007, "Id": 10002,
"Value": 0.08100000023841858, "Value": 0.08100000023841858,
"IsRatio": true "IsRatio": true
}, },
@ -2248,13 +2248,13 @@
"ResonLevelLimit": 5, "ResonLevelLimit": 5,
"FirstPropId": { "FirstPropId": {
"Id": 7, "Id": 7,
"Value": 24, "Value": 26,
"IsRatio": false "IsRatio": false
}, },
"FirstCurve": 1, "FirstCurve": 1,
"SecondPropId": { "SecondPropId": {
"Id": 10010, "Id": 10010,
"Value": 0.08550000190734863, "Value": 0.06840000301599503,
"IsRatio": true "IsRatio": true
}, },
"SecondCurve": 2, "SecondCurve": 2,
@ -3128,7 +3128,7 @@
"ArrayString": [ "2", "2", "2", "2", "2" ] "ArrayString": [ "2", "2", "2", "2", "2" ]
}, },
{ {
"ArrayString": [ "14", "14", "14", "14", "14" ] "ArrayString": [ "10", "10", "10", "10", "10" ]
} }
], ],
"TypeDescription": "WeaponConf_21010016_TypeDescription", "TypeDescription": "WeaponConf_21010016_TypeDescription",
@ -3180,16 +3180,13 @@
"ArrayString": [ "12%", "15%", "18%", "21%", "24%" ] "ArrayString": [ "12%", "15%", "18%", "21%", "24%" ]
}, },
{ {
"ArrayString": [ "12%", "15%", "18%", "21%", "24%" ] "ArrayString": [ "20%", "25%", "30%", "35%", "40%" ]
},
{
"ArrayString": [ "12%", "15%", "18%", "21%", "24%" ]
}, },
{ {
"ArrayString": [ "2", "2", "2", "2", "2" ] "ArrayString": [ "2", "2", "2", "2", "2" ]
}, },
{ {
"ArrayString": [ "5", "5", "5", "5", "5" ] "ArrayString": [ "18", "18", "18", "18", "18" ]
} }
], ],
"TypeDescription": "WeaponConf_21050016_TypeDescription", "TypeDescription": "WeaponConf_21050016_TypeDescription",

View file

@ -1,5 +1,6 @@
using GameServer.Controllers.Attributes; using GameServer.Controllers.Attributes;
using GameServer.Network; using GameServer.Network;
using GameServer.Network.Messages;
using Protocol; using Protocol;
namespace GameServer.Controllers; namespace GameServer.Controllers;
@ -11,5 +12,5 @@ internal class AchievementController : Controller
} }
[NetEvent(MessageId.AchievementInfoRequest)] [NetEvent(MessageId.AchievementInfoRequest)]
public RpcResult OnAchievementInfoRequest() => Response(MessageId.AchievementInfoResponse, new AchievementInfoResponse()); public ResponseMessage OnAchievementInfoRequest() => Response(MessageId.AchievementInfoResponse, new AchievementInfoResponse());
} }

View file

@ -1,14 +0,0 @@
using Protocol;
namespace GameServer.Controllers.Attributes;
[AttributeUsage(AttributeTargets.Method)]
internal class CombatRequestAttribute : Attribute
{
public CombatRequestData.MessageOneofCase MessageCase { get; }
public CombatRequestAttribute(CombatRequestData.MessageOneofCase messageCase)
{
MessageCase = messageCase;
}
}

View file

@ -1,67 +0,0 @@
using GameServer.Controllers.Attributes;
using GameServer.Models;
using GameServer.Models.Chat;
using GameServer.Network;
using GameServer.Systems.Entity;
using Protocol;
namespace GameServer.Controllers.ChatCommands;
[ChatCommandCategory("player")]
internal class ChatPlayerCommandHandler
{
private readonly ChatRoom _helperRoom;
private readonly PlayerSession _session;
private readonly CreatureController _creatureController;
public ChatPlayerCommandHandler(ModelManager modelManager, PlayerSession session, CreatureController creatureController)
{
_helperRoom = modelManager.Chat.GetChatRoom(1338);
_session = session;
_creatureController = creatureController;
}
[ChatCommand("getpos")]
[ChatCommandDesc("/player getpos - shows current player coordinates")]
public void OnPlayerGetPosCommand(string[] _)
{
PlayerEntity? entity = _creatureController.GetPlayerEntity();
if (entity == null) return;
_helperRoom.AddMessage(1338, 0, $"Your current position: ({entity.Pos.X / 100}, {entity.Pos.Y / 100}, {entity.Pos.Z / 100})");
}
[ChatCommand("teleport")]
[ChatCommandDesc("/player teleport [x] [y] [z] - performing fast travel to specified position")]
public async Task OnPlayerTeleportCommand(string[] args)
{
if (args.Length != 3 || !float.TryParse(args[0], out float x)
|| !float.TryParse(args[1], out float y)
|| !float.TryParse(args[2], out float z))
{
_helperRoom.AddMessage(1338, 0, $"Usage: /player teleport [x] [y] [z]");
return;
}
PlayerEntity? entity = _creatureController.GetPlayerEntity();
if (entity != null)
{
await _session.Push(MessageId.TeleportNotify, new TeleportNotify
{
PosX = x * 100,
PosY = y * 100,
PosZ = z * 100,
PosA = 0,
MapId = 8,
Reason = (int)TeleportReason.Gm,
TransitionOption = new TransitionOptionPb
{
TransitionType = (int)TransitionType.Empty
}
});
}
_helperRoom.AddMessage(1338, 0, $"Successfully performed fast travel to ({x}, {y}, {z})");
}
}

View file

@ -4,6 +4,7 @@ using GameServer.Models;
using GameServer.Models.Chat; using GameServer.Models.Chat;
using GameServer.Network; using GameServer.Network;
using GameServer.Systems.Entity; using GameServer.Systems.Entity;
using Protocol;
namespace GameServer.Controllers.ChatCommands; namespace GameServer.Controllers.ChatCommands;
@ -15,16 +16,14 @@ internal class ChatSpawnCommandHandler
private readonly EntityFactory _entityFactory; private readonly EntityFactory _entityFactory;
private readonly PlayerSession _session; private readonly PlayerSession _session;
private readonly ConfigManager _configManager; private readonly ConfigManager _configManager;
private readonly CreatureController _creatureController;
public ChatSpawnCommandHandler(ModelManager modelManager, EntitySystem entitySystem, EntityFactory entityFactory, PlayerSession session, ConfigManager configManager, CreatureController creatureController) public ChatSpawnCommandHandler(ModelManager modelManager, EntitySystem entitySystem, EntityFactory entityFactory, PlayerSession session, ConfigManager configManager)
{ {
_helperRoom = modelManager.Chat.GetChatRoom(1338); _helperRoom = modelManager.Chat.GetChatRoom(1338);
_entitySystem = entitySystem; _entitySystem = entitySystem;
_entityFactory = entityFactory; _entityFactory = entityFactory;
_session = session; _session = session;
_configManager = configManager; _configManager = configManager;
_creatureController = creatureController;
} }
[ChatCommand("monster")] [ChatCommand("monster")]
@ -33,9 +32,9 @@ internal class ChatSpawnCommandHandler
{ {
if (args.Length != 4 || if (args.Length != 4 ||
!(int.TryParse(args[0], out int levelEntityId) && !(int.TryParse(args[0], out int levelEntityId) &&
float.TryParse(args[1], out float x) && int.TryParse(args[1], out int x) &&
float.TryParse(args[2], out float y) && int.TryParse(args[2], out int y) &&
float.TryParse(args[3], out float z))) int.TryParse(args[3], out int z)))
{ {
_helperRoom.AddMessage(1338, 0, "Usage: /spawn monster [id] [x] [y] [z]"); _helperRoom.AddMessage(1338, 0, "Usage: /spawn monster [id] [x] [y] [z]");
return; return;
@ -44,15 +43,19 @@ internal class ChatSpawnCommandHandler
MonsterEntity monster = _entityFactory.CreateMonster(levelEntityId); MonsterEntity monster = _entityFactory.CreateMonster(levelEntityId);
monster.Pos = new() monster.Pos = new()
{ {
X = x * 100, X = x,
Y = y * 100, Y = y,
Z = z * 100 Z = z
}; };
_entitySystem.Create(monster);
monster.InitProps(_configManager.GetConfig<BasePropertyConfig>(600000100)!); // TODO: monster property config monster.InitProps(_configManager.GetConfig<BasePropertyConfig>(600000100)!); // TODO: monster property config
_entitySystem.Add([monster]);
await _creatureController.UpdateAiHate(); await _session.Push(MessageId.EntityAddNotify, new EntityAddNotify
{
IsAdd = true,
EntityPbs = { monster.Pb }
});
_helperRoom.AddMessage(1338, 0, $"Successfully spawned monster with id {levelEntityId} at ({x}, {y}, {z})"); _helperRoom.AddMessage(1338, 0, $"Successfully spawned monster with id {levelEntityId} at ({x}, {y}, {z})");
} }

View file

@ -1,14 +1,14 @@
using System.Text; using System.Text;
using System.Text.RegularExpressions;
using GameServer.Controllers.Attributes; using GameServer.Controllers.Attributes;
using GameServer.Controllers.ChatCommands; using GameServer.Controllers.ChatCommands;
using GameServer.Models; using GameServer.Models;
using GameServer.Models.Chat; using GameServer.Models.Chat;
using GameServer.Network; using GameServer.Network;
using GameServer.Network.Messages;
using Protocol; using Protocol;
namespace GameServer.Controllers; namespace GameServer.Controllers;
internal partial class ChatController : Controller internal class ChatController : Controller
{ {
private readonly ModelManager _modelManager; private readonly ModelManager _modelManager;
@ -18,7 +18,7 @@ internal partial class ChatController : Controller
} }
[NetEvent(MessageId.PrivateChatDataRequest)] [NetEvent(MessageId.PrivateChatDataRequest)]
public async Task<RpcResult> OnPrivateChatDataRequest() public async Task<ResponseMessage> OnPrivateChatDataRequest()
{ {
if (!_modelManager.Chat.AllChatRooms.Any()) if (!_modelManager.Chat.AllChatRooms.Any())
{ {
@ -31,7 +31,7 @@ internal partial class ChatController : Controller
} }
[NetEvent(MessageId.PrivateChatRequest)] [NetEvent(MessageId.PrivateChatRequest)]
public async Task<RpcResult> OnPrivateChatRequest(PrivateChatRequest request, ChatCommandManager chatCommandManager) public async Task<ResponseMessage> OnPrivateChatRequest(PrivateChatRequest request, ChatCommandManager chatCommandManager)
{ {
ChatRoom chatRoom = _modelManager.Chat.GetChatRoom(1338); ChatRoom chatRoom = _modelManager.Chat.GetChatRoom(1338);
@ -42,8 +42,7 @@ internal partial class ChatController : Controller
} }
else else
{ {
string content = MultipleSpacesRegex().Replace(request.Content, " "); string[] split = request.Content[1..].Split(' ');
string[] split = content[1..].Split(' ');
if (split.Length >= 2) if (split.Length >= 2)
{ {
await chatCommandManager.InvokeCommandAsync(split[0], split[1], split[2..]); await chatCommandManager.InvokeCommandAsync(split[0], split[1], split[2..]);
@ -55,7 +54,7 @@ internal partial class ChatController : Controller
} }
[NetEvent(MessageId.PrivateChatOperateRequest)] [NetEvent(MessageId.PrivateChatOperateRequest)]
public RpcResult OnPrivateChatOperateRequest() => Response(MessageId.PrivateChatOperateResponse, new PrivateChatOperateResponse()); public ResponseMessage OnPrivateChatOperateRequest() => Response(MessageId.PrivateChatOperateResponse, new PrivateChatOperateResponse());
private async Task PushPrivateChatHistory() private async Task PushPrivateChatHistory()
{ {
@ -86,7 +85,4 @@ internal partial class ChatController : Controller
return builder.ToString(); return builder.ToString();
} }
[GeneratedRegex(@"\s+")]
private static partial Regex MultipleSpacesRegex();
} }

View file

@ -1,348 +0,0 @@
using System.Collections.Immutable;
using System.Linq.Expressions;
using System.Reflection;
using GameServer.Controllers.Attributes;
using GameServer.Network;
using GameServer.Systems.Entity;
using GameServer.Systems.Entity.Component;
using Microsoft.Extensions.Logging;
using Protocol;
namespace GameServer.Controllers.Combat;
internal class CombatManager
{
private delegate Task<CombatResponseData> CombatRequestHandler(CombatManager combatManager, CombatRequestContext context);
private static readonly ImmutableDictionary<CombatRequestData.MessageOneofCase, CombatRequestHandler> s_requestHandlers;
private readonly ILogger _logger;
private readonly EntitySystem _entitySystem;
private readonly PlayerSession _session;
private readonly CreatureController _creatureController;
static CombatManager()
{
s_requestHandlers = MapRequestHandlers();
}
public CombatManager(ILogger<CombatManager> logger, EntitySystem entitySystem, PlayerSession session, CreatureController creatureController)
{
_logger = logger;
_entitySystem = entitySystem;
_session = session;
_creatureController = creatureController;
}
[CombatRequest(CombatRequestData.MessageOneofCase.RTimeStopRequest)]
public CombatResponseData OnRTimeStopRequest(CombatRequestContext context) => new()
{
CombatCommon = context.Request.CombatCommon,
RTimeStopResponse = new()
};
[CombatRequest(CombatRequestData.MessageOneofCase.ActivateBuffRequest)]
public CombatResponseData OnActivateBuffRequest(CombatRequestContext context) => new()
{
CombatCommon = context.Request.CombatCommon,
ActivateBuffResponse = new()
};
[CombatRequest(CombatRequestData.MessageOneofCase.UseSkillRequest)]
public CombatResponseData OnUseSkillRequest(CombatRequestContext context) => new()
{
CombatCommon = context.Request.CombatCommon,
UseSkillResponse = new()
{
SkillSingleId = context.Request.UseSkillRequest.SkillSingleId,
UseSkillInfo = context.Request.UseSkillRequest.UseSkillInfo
}
};
[CombatRequest(CombatRequestData.MessageOneofCase.ApplyGameplayEffectRequest)]
public CombatResponseData OnApplyGameplayEffectRequest(CombatRequestContext context) => new()
{
CombatCommon = context.Request.CombatCommon,
ApplyGameplayEffectResponse = new ApplyGameplayEffectResponse()
};
[CombatRequest(CombatRequestData.MessageOneofCase.RemoveGameplayEffectRequest)]
public CombatResponseData OnRemoveGameplayEffectRequest(CombatRequestContext context) => new()
{
CombatCommon = context.Request.CombatCommon,
RemoveGameplayEffectResponse = new RemoveGameplayEffectResponse()
};
[CombatRequest(CombatRequestData.MessageOneofCase.CreateBulletRequest)]
public CombatResponseData OnCreateBulletRequest(CombatRequestContext context)
{
return new CombatResponseData
{
CombatCommon = context.Request.CombatCommon,
CreateBulletResponse = new()
};
}
[CombatRequest(CombatRequestData.MessageOneofCase.DamageExecuteRequest)]
public CombatResponseData OnDamageExecuteRequest(CombatRequestContext context)
{
DamageExecuteRequest request = context.Request.DamageExecuteRequest;
EntityBase? entity = _entitySystem.Get<EntityBase>(request.TargetEntityId);
if (entity == null)
{
return new CombatResponseData
{
RequestId = context.Request.RequestId,
CombatCommon = context.Request.CombatCommon,
DamageExecuteResponse = new()
{
ErrorCode = (int)ErrorCode.ErrThrowDamageReqEntityIsAlreadyDead
}
};
}
EntityAttributeComponent attr = entity.ComponentSystem.Get<EntityAttributeComponent>();
attr.SetAttribute(EAttributeType.Life, (int)request.DamageId); // Pakchunk patch! (cur hp instead of damageid)
if (request.DamageId <= 0 && entity.Type != EEntityType.Player) // Player death not implemented
{
_entitySystem.Destroy([entity]);
}
return new CombatResponseData
{
RequestId = context.Request.RequestId,
CombatCommon = context.Request.CombatCommon,
DamageExecuteResponse = new()
{
AttackerEntityId = request.AttackerEntityId,
TargetEntityId = request.TargetEntityId,
ShieldCoverDamage = 0,
Damage = (int)request.DamageId,
PartId = request.PartId
}
};
}
[CombatRequest(CombatRequestData.MessageOneofCase.HitRequest)]
public CombatResponseData OnHitRequest(CombatRequestContext context)
{
return new CombatResponseData
{
RequestId = context.Request.RequestId,
CombatCommon = context.Request.CombatCommon,
HitResponse = new()
{
HitInfo = context.Request.HitRequest.HitInfo
}
};
}
[CombatRequest(CombatRequestData.MessageOneofCase.LogicStateInitRequest)]
public CombatResponseData OnLogicStateInitRequest(CombatRequestContext context)
{
CombatResponseData rsp = new()
{
CombatCommon = context.Request.CombatCommon,
RequestId = context.Request.RequestId,
LogicStateInitResponse = new()
};
EntityBase? entity = _entitySystem.Get<EntityBase>(context.Request.CombatCommon.EntityId);
if (entity == null) return rsp;
EntityLogicStateComponent logicStateComponent = entity.ComponentSystem.Get<EntityLogicStateComponent>();
logicStateComponent.States = [.. context.Request.LogicStateInitRequest.InitData.States];
context.Notifies.Add(new CombatNotifyData
{
CombatCommon = context.Request.CombatCommon,
LogicStateInitNotify = new()
{
CombatCommon = context.Request.CombatCommon,
EntityId = entity.Id,
InitData = logicStateComponent.Pb.LogicStateComponentPb
}
});
return rsp;
}
[CombatRequest(CombatRequestData.MessageOneofCase.SwitchLogicStateRequest)]
public CombatResponseData OnSwitchLogicStateRequest(CombatRequestContext context)
{
CombatResponseData rsp = new()
{
CombatCommon = context.Request.CombatCommon,
RequestId = context.Request.RequestId,
SwitchLogicStateResponse = new()
};
EntityBase? entity = _entitySystem.Get<EntityBase>(context.Request.CombatCommon.EntityId);
if (entity == null)
{
rsp.SwitchLogicStateResponse.ErrorCode = (int)ErrorCode.ErrActionEntityNoExist;
return rsp;
}
EntityLogicStateComponent logicStateComponent = entity.ComponentSystem.Get<EntityLogicStateComponent>();
logicStateComponent.States = [.. context.Request.SwitchLogicStateRequest.States];
context.Notifies.Add(new CombatNotifyData
{
CombatCommon = context.Request.CombatCommon,
SwitchLogicStateNotify = new()
{
States = { logicStateComponent.States }
}
});
return rsp;
}
[CombatRequest(CombatRequestData.MessageOneofCase.BattleStateChangeRequest)]
public CombatResponseData OnBattleStateChangeRequest(CombatRequestContext context)
{
return new CombatResponseData
{
CombatCommon = context.Request.CombatCommon,
RequestId = context.Request.RequestId,
BattleStateChangeResponse = new()
};
}
[CombatRequest(CombatRequestData.MessageOneofCase.ChangeStateConfirmRequest)]
public CombatResponseData OnChangeStateConfirmRequest(CombatRequestContext context)
{
CombatResponseData rsp = new()
{
CombatCommon = context.Request.CombatCommon,
RequestId = context.Request.RequestId,
ChangeStateConfirmResponse = new()
{
Error = new()
}
};
EntityBase? entity = _entitySystem.Get<EntityBase>(context.Request.CombatCommon.EntityId);
if (entity == null)
{
rsp.ChangeStateConfirmResponse.Error.ErrorCode = (int)ErrorCode.ErrEntityIsNotAlive;
return rsp;
}
ChangeStateConfirmRequest request = context.Request.ChangeStateConfirmRequest;
if (entity.ComponentSystem.TryGet(out EntityFsmComponent? fsmComponent))
{
DFsm? dfsm = fsmComponent.Fsms.FirstOrDefault(fsm => fsm.FsmId == request.FsmId);
if (dfsm == null)
{
dfsm = new DFsm
{
FsmId = request.FsmId,
Status = 1,
Flag = (int)EFsmStateFlag.Confirmed
};
fsmComponent.Fsms.Add(dfsm);
}
dfsm.CurrentState = request.State;
context.Notifies.Add(new CombatNotifyData
{
CombatCommon = context.Request.CombatCommon,
ChangeStateConfirmNotify = new ChangeStateConfirmNotify
{
State = request.State,
FsmId = request.FsmId
}
});
}
rsp.ChangeStateConfirmResponse.State = context.Request.ChangeStateConfirmRequest.State;
rsp.ChangeStateConfirmResponse.FsmId = context.Request.ChangeStateConfirmRequest.FsmId;
return rsp;
}
[CombatRequest(CombatRequestData.MessageOneofCase.FsmConditionPassRequest)]
public CombatResponseData OnFsmConditionPassRequest(CombatRequestContext context)
{
return new CombatResponseData
{
CombatCommon = context.Request.CombatCommon,
RequestId = context.Request.RequestId,
FsmConditionPassResponse = new()
{
FsmId = context.Request.FsmConditionPassRequest.FsmId,
Error = new()
}
};
}
[CombatRequest(CombatRequestData.MessageOneofCase.AiInformationRequest)]
public CombatResponseData OnAiInformationRequest(CombatRequestContext context)
{
// Currently like this, TODO!
context.Notifies.Add(new CombatNotifyData
{
CombatCommon = new CombatCommon
{
EntityId = context.Request.CombatCommon.EntityId, // id of monster
},
AiHateNotify = new AiHateNotify
{
HateList =
{
new AiHateEntity
{
EntityId = _creatureController.GetPlayerEntity()!.Id, // id of hated entity (the player)
HatredValue = 99999
}
}
}
});
return new CombatResponseData
{
CombatCommon = context.Request.CombatCommon,
RequestId = context.Request.RequestId,
AiInformationResponse = new() // ?? contains nothing
};
}
public Task<CombatResponseData?> HandleRequest(CombatRequestContext context)
{
if (s_requestHandlers.TryGetValue(context.Request.MessageCase, out CombatRequestHandler? handler))
return handler(this, context)!;
_logger.LogWarning("Combat request not handled: {type}", context.Request.MessageCase);
return Task.FromResult<CombatResponseData?>(null);
}
private static ImmutableDictionary<CombatRequestData.MessageOneofCase, CombatRequestHandler> MapRequestHandlers()
{
var builder = ImmutableDictionary.CreateBuilder<CombatRequestData.MessageOneofCase, CombatRequestHandler>();
MethodInfo taskFromResultMethod = typeof(Task).GetMethod(nameof(Task.FromResult))!.MakeGenericMethod(typeof(CombatResponseData));
foreach (MethodInfo method in typeof(CombatManager).GetMethods())
{
CombatRequestAttribute? attribute = method.GetCustomAttribute<CombatRequestAttribute>();
if (attribute == null) continue;
ParameterExpression combatManagerParam = Expression.Parameter(typeof(CombatManager));
ParameterExpression contextParam = Expression.Parameter(typeof(CombatRequestContext));
Expression call = Expression.Call(combatManagerParam, method, contextParam);
if (method.ReturnType == typeof(CombatResponseData))
call = Expression.Call(taskFromResultMethod, call);
Expression<CombatRequestHandler> lambda = Expression.Lambda<CombatRequestHandler>(call, combatManagerParam, contextParam);
builder.Add(attribute.MessageCase, lambda.Compile());
}
return builder.ToImmutable();
}
}

View file

@ -1,14 +0,0 @@
using Protocol;
namespace GameServer.Controllers.Combat;
internal class CombatRequestContext
{
public CombatRequestData Request { get; }
public List<CombatNotifyData> Notifies { get; }
public CombatRequestContext(CombatRequestData request)
{
Request = request;
Notifies = [];
}
}

View file

@ -1,71 +1,16 @@
using GameServer.Controllers.Attributes; using GameServer.Controllers.Attributes;
using GameServer.Controllers.Combat;
using GameServer.Models;
using GameServer.Network; using GameServer.Network;
using GameServer.Systems.Entity; using GameServer.Network.Messages;
using GameServer.Systems.Event;
using Microsoft.Extensions.Logging;
using Protocol; using Protocol;
namespace GameServer.Controllers; namespace GameServer.Controllers;
internal class CombatMessageController : Controller internal class CombatMessageController : Controller
{ {
private readonly ILogger _logger; public CombatMessageController(PlayerSession session) : base(session)
public CombatMessageController(PlayerSession session, ILogger<CombatMessageController> logger) : base(session)
{ {
_logger = logger; // CombatMessageController.
} }
[NetEvent(MessageId.MovePackagePush)] [NetEvent(MessageId.CombatSendPackRequest)] // TODO: CombatSendPackRequest is important
public async Task OnMovePackagePush(MovePackagePush push, EntitySystem entitySystem, EventSystem eventSystem, ModelManager modelManager) public ResponseMessage OnCombatSendPackRequest() => Response(MessageId.CombatSendPackResponse, new CombatSendPackResponse());
{
foreach (MovingEntityData movingEntityData in push.MovingEntities)
{
EntityBase? entity = entitySystem.Get<EntityBase>(movingEntityData.EntityId);
if (entity == null)
{
_logger.LogWarning("OnMovePackagePush: moving entity not found! Id: {entityId}", movingEntityData.EntityId);
continue;
}
MoveReplaySample lastMoveReplay = movingEntityData.MoveInfos.Last();
entity.Pos.MergeFrom(lastMoveReplay.Location);
entity.Rot.MergeFrom(lastMoveReplay.Rotation);
if (entity.Id == modelManager.Creature.PlayerEntityId)
await eventSystem.Emit(GameEventType.PlayerPositionChanged);
}
}
[NetEvent(MessageId.CombatSendPackRequest)]
public async Task<RpcResult> OnCombatSendPackRequest(CombatSendPackRequest request, CombatManager combatManager)
{
CombatReceivePackNotify combatPackNotify = new();
foreach (CombatSendData sendData in request.Data)
{
if (sendData.Request != null)
{
CombatRequestContext context = new(sendData.Request);
CombatResponseData? responseData = await combatManager.HandleRequest(context);
combatPackNotify.Data.AddRange(context.Notifies.Select(notify => new CombatReceiveData
{
CombatNotifyData = notify
}));
if (responseData != null)
{
combatPackNotify.Data.Add(new CombatReceiveData
{
CombatResponseData = responseData
});
}
}
}
await Session.Push(MessageId.CombatReceivePackNotify, combatPackNotify);
return Response(MessageId.CombatSendPackResponse, new CombatSendPackResponse());
}
} }

View file

@ -1,5 +1,4 @@
global using GameServer.Controllers.Result; using GameServer.Network;
using GameServer.Network;
using GameServer.Network.Messages; using GameServer.Network.Messages;
using Google.Protobuf; using Google.Protobuf;
using Protocol; using Protocol;
@ -14,9 +13,9 @@ internal abstract class Controller
Session = session; Session = session;
} }
protected static RpcResult Response<TProtoBuf>(MessageId messageId, TProtoBuf protoBuf) where TProtoBuf : IMessage<TProtoBuf> => new(new ResponseMessage protected static ResponseMessage Response<TProtoBuf>(MessageId messageId, TProtoBuf protoBuf) where TProtoBuf : IMessage<TProtoBuf> => new()
{ {
MessageId = messageId, MessageId = messageId,
Payload = protoBuf.ToByteArray() Payload = protoBuf.ToByteArray()
}); };
} }

View file

@ -1,41 +1,27 @@
using Core.Config; using Core.Config;
using GameServer.Controllers.Attributes; using GameServer.Controllers.Attributes;
using GameServer.Extensions.Logic;
using GameServer.Models; using GameServer.Models;
using GameServer.Network; using GameServer.Network;
using GameServer.Settings; using GameServer.Network.Messages;
using GameServer.Systems.Entity; using GameServer.Systems.Entity;
using GameServer.Systems.Entity.Component; using GameServer.Systems.Entity.Component;
using GameServer.Systems.Event; using GameServer.Systems.Event;
using GameServer.Systems.Notify;
using Microsoft.Extensions.Options;
using Protocol; using Protocol;
namespace GameServer.Controllers; namespace GameServer.Controllers;
internal class CreatureController : Controller internal class CreatureController : Controller
{ {
private const float DynamicSpawnRadius = 5000;
private const float DynamicSpawnPositionDelta = 2500;
private readonly EntitySystem _entitySystem; private readonly EntitySystem _entitySystem;
private readonly EntityFactory _entityFactory; private readonly EntityFactory _entityFactory;
private readonly ModelManager _modelManager; private readonly ModelManager _modelManager;
private readonly ConfigManager _configManager; private readonly ConfigManager _configManager;
private readonly IGameActionListener _listener;
private readonly GameplayFeatureSettings _gameplayFeatures; public CreatureController(PlayerSession session, EntitySystem entitySystem, EntityFactory entityFactory, ModelManager modelManager, ConfigManager configManager) : base(session)
private readonly Vector _lastDynamicSpawnPos;
public CreatureController(PlayerSession session, EntitySystem entitySystem, EntityFactory entityFactory, ModelManager modelManager, ConfigManager configManager, IOptions<GameplayFeatureSettings> gameplayFeatures, IGameActionListener listener) : base(session)
{ {
_entitySystem = entitySystem; _entitySystem = entitySystem;
_entityFactory = entityFactory; _entityFactory = entityFactory;
_modelManager = modelManager; _modelManager = modelManager;
_configManager = configManager; _configManager = configManager;
_listener = listener;
_gameplayFeatures = gameplayFeatures.Value;
_lastDynamicSpawnPos = new();
} }
public async Task JoinScene(int instanceId) public async Task JoinScene(int instanceId)
@ -44,11 +30,19 @@ internal class CreatureController : Controller
CreateTeamPlayerEntities(); CreateTeamPlayerEntities();
CreateWorldEntities(); CreateWorldEntities();
await _listener.OnJoinedScene(CreateSceneInfo(), TransitionType.Empty); await Session.Push(MessageId.JoinSceneNotify, new JoinSceneNotify
{
MaxEntityId = 10000000,
TransitionOption = new TransitionOptionPb
{
TransitionType = (int)TransitionType.Empty
},
SceneInfo = CreateSceneInfo()
});
} }
[NetEvent(MessageId.EntityActiveRequest)] [NetEvent(MessageId.EntityActiveRequest)]
public async Task<RpcResult> OnEntityActiveRequest(EntityActiveRequest request) public async Task<ResponseMessage> OnEntityActiveRequest(EntityActiveRequest request)
{ {
EntityActiveResponse response; EntityActiveResponse response;
@ -58,8 +52,7 @@ internal class CreatureController : Controller
_entitySystem.Activate(entity); _entitySystem.Activate(entity);
response = new EntityActiveResponse response = new EntityActiveResponse
{ {
ErrorCode = (int)ErrorCode.Success, ErrorCode = (int)ErrorCode.Success
IsVisible = entity.IsVisible
}; };
response.ComponentPbs.AddRange(entity.ComponentSystem.Pb); response.ComponentPbs.AddRange(entity.ComponentSystem.Pb);
@ -74,10 +67,9 @@ internal class CreatureController : Controller
} }
[NetEvent(MessageId.SceneLoadingFinishRequest)] [NetEvent(MessageId.SceneLoadingFinishRequest)]
public async Task<RpcResult> OnSceneLoadingFinishRequest() public ResponseMessage OnSceneLoadingFinishRequest()
{ {
_modelManager.Creature.OnWorldDone(); _modelManager.Creature.OnWorldDone();
await UpdateAiHate();
return Response(MessageId.SceneLoadingFinishResponse, new SceneLoadingFinishResponse()); return Response(MessageId.SceneLoadingFinishResponse, new SceneLoadingFinishResponse());
} }
@ -85,27 +77,53 @@ internal class CreatureController : Controller
[GameEvent(GameEventType.FormationUpdated)] [GameEvent(GameEventType.FormationUpdated)]
public async Task OnFormationUpdated() public async Task OnFormationUpdated()
{ {
_entitySystem.Destroy(GetPlayerEntities().ToArray()); // Remove old entities
IEnumerable<PlayerEntity> oldEntities = _entitySystem.EnumerateEntities()
.Where(e => e is PlayerEntity entity && entity.PlayerId == _modelManager.Player.Id)
.Cast<PlayerEntity>().ToArray();
foreach (PlayerEntity oldEntity in oldEntities)
{
_entitySystem.Destroy(oldEntity);
}
await Session.Push(MessageId.EntityRemoveNotify, new EntityRemoveNotify
{
IsRemove = true,
RemoveInfos =
{
oldEntities.Select(entity => new EntityRemoveInfo
{
EntityId = entity.Id,
Type = (int)entity.Type
})
}
});
// Spawn new entities
CreateTeamPlayerEntities(); CreateTeamPlayerEntities();
_modelManager.Creature.PlayerEntityId = GetPlayerEntities().First().Id; IEnumerable<PlayerEntity> newEntities = _entitySystem.EnumerateEntities()
await _listener.OnPlayerFightRoleInfoUpdated(_modelManager.Player.Id, GetFightRoleInfos()); .Where(e => e is PlayerEntity entity && entity.PlayerId == _modelManager.Player.Id)
.Cast<PlayerEntity>();
await UpdateAiHate(); await Session.Push(MessageId.EntityAddNotify, new EntityAddNotify
}
[GameEvent(GameEventType.PlayerPositionChanged)]
public void OnPlayerPositionChanged()
{ {
_modelManager.Player.Position.MergeFrom(GetPlayerEntity()!.Pos); IsAdd = true,
EntityPbs =
if (_lastDynamicSpawnPos.GetDistance(_modelManager.Player.Position) >= DynamicSpawnPositionDelta)
{ {
_lastDynamicSpawnPos.MergeFrom(_modelManager.Player.Position); newEntities.Select(entity => entity.Pb)
ClearInactiveEntities();
SpawnDynamicEntities();
} }
});
_modelManager.Creature.PlayerEntityId = newEntities.First().Id;
await Session.Push(MessageId.UpdatePlayerAllFightRoleNotify, new UpdatePlayerAllFightRoleNotify
{
PlayerId = _modelManager.Player.Id,
FightRoleInfos = { GetFightRoleInfos() }
});
} }
[GameEvent(GameEventType.VisionSkillChanged)] [GameEvent(GameEventType.VisionSkillChanged)]
@ -147,46 +165,13 @@ internal class CreatureController : Controller
prevEntity.IsCurrentRole = false; prevEntity.IsCurrentRole = false;
if (_entitySystem.EnumerateEntities().FirstOrDefault(e => e is PlayerEntity playerEntity && playerEntity.ConfigId == roleId) is not PlayerEntity newEntity) return; PlayerEntity? newEntity = _entitySystem.EnumerateEntities().FirstOrDefault(e => e is PlayerEntity playerEntity && playerEntity.ConfigId == roleId) as PlayerEntity;
if (newEntity == null) return;
_modelManager.Creature.PlayerEntityId = newEntity.Id; _modelManager.Creature.PlayerEntityId = newEntity.Id;
newEntity.IsCurrentRole = true; newEntity.IsCurrentRole = true;
newEntity.Pos.MergeFrom(prevEntity.Pos); await OnVisionSkillChanged();
newEntity.Rot.MergeFrom(prevEntity.Rot);
await UpdateAiHate();
}
public async Task UpdateAiHate()
{
IEnumerable<EntityBase> monsters = _entitySystem.EnumerateEntities().Where(e => e is MonsterEntity);
if (!monsters.Any()) return;
await Session.Push(MessageId.CombatReceivePackNotify, new CombatReceivePackNotify
{
Data =
{
monsters.Select(monster => new CombatReceiveData
{
CombatNotifyData = new()
{
CombatCommon = new() { EntityId = monster.Id },
AiHateNotify = new()
{
HateList =
{
GetPlayerEntities().Select(player => new AiHateEntity
{
EntityId = player.Id,
HatredValue = 99999 // currently this, TODO!
})
}
}
}
})
}
});
} }
private SceneInformation CreateSceneInfo() => new() private SceneInformation CreateSceneInfo() => new()
@ -206,7 +191,12 @@ internal class CreatureController : Controller
PlayerId = _modelManager.Player.Id, PlayerId = _modelManager.Player.Id,
Level = 1, Level = 1,
IsOffline = false, IsOffline = false,
Location = _modelManager.Player.Position, Location = new()
{
X = 4000,
Y = -2000,
Z = 260
},
PlayerName = _modelManager.Player.Name, PlayerName = _modelManager.Player.Name,
FightRoleInfos = { GetFightRoleInfos() } FightRoleInfos = { GetFightRoleInfos() }
} }
@ -215,7 +205,11 @@ internal class CreatureController : Controller
private IEnumerable<FightRoleInformation> GetFightRoleInfos() private IEnumerable<FightRoleInformation> GetFightRoleInfos()
{ {
return GetPlayerEntities().Select(playerEntity => new FightRoleInformation IEnumerable<PlayerEntity> playerEntities = _entitySystem.EnumerateEntities()
.Where(e => e is PlayerEntity entity && entity.PlayerId == _modelManager.Player.Id)
.Cast<PlayerEntity>();
return playerEntities.Select(playerEntity => new FightRoleInformation
{ {
EntityId = playerEntity.Id, EntityId = playerEntity.Id,
CurHp = playerEntity.Health, CurHp = playerEntity.Health,
@ -228,106 +222,41 @@ internal class CreatureController : Controller
private void CreateTeamPlayerEntities() private void CreateTeamPlayerEntities()
{ {
PlayerEntity[] playerEntities = new PlayerEntity[_modelManager.Formation.RoleIds.Length];
for (int i = 0; i < _modelManager.Formation.RoleIds.Length; i++) for (int i = 0; i < _modelManager.Formation.RoleIds.Length; i++)
{ {
int roleId = _modelManager.Formation.RoleIds[i]; PlayerEntity entity = _entityFactory.CreatePlayer(_modelManager.Formation.RoleIds[i], _modelManager.Player.Id);
entity.Pos = new()
PlayerEntity entity = _entityFactory.CreatePlayer(roleId, _modelManager.Player.Id); {
entity.Pos = _modelManager.Player.Position.Clone(); X = 4000,
Y = -2000,
Z = 260
};
entity.IsCurrentRole = i == 0; entity.IsCurrentRole = i == 0;
entity.ComponentSystem.Get<EntityAttributeComponent>().SetAll(_modelManager.Roles.GetRoleById(roleId)!.GetAttributeList()); _entitySystem.Create(entity);
entity.InitProps(_configManager.GetConfig<BasePropertyConfig>(entity.ConfigId)!);
CreateConcomitants(entity); // Give weapon to entity
entity.WeaponId = _modelManager.Inventory.GetEquippedWeapon(roleId)?.Id ?? 0; RoleInfoConfig roleConfig = _configManager.GetConfig<RoleInfoConfig>(entity.ConfigId)!;
WeaponConfig weaponConfig = _configManager.GetConfig<WeaponConfig>(roleConfig.InitWeaponItemId)!;
entity.WeaponId = weaponConfig.ItemId;
if (i == 0) _modelManager.Creature.PlayerEntityId = entity.Id; if (i == 0) _modelManager.Creature.PlayerEntityId = entity.Id;
if (_gameplayFeatures.UnlimitedEnergy)
{
EntityAttributeComponent attr = entity.ComponentSystem.Get<EntityAttributeComponent>();
attr.SetAttribute(EAttributeType.EnergyMax, 0);
attr.SetAttribute(EAttributeType.SpecialEnergy1Max, 0);
attr.SetAttribute(EAttributeType.SpecialEnergy2Max, 0);
attr.SetAttribute(EAttributeType.SpecialEnergy3Max, 0);
attr.SetAttribute(EAttributeType.SpecialEnergy4Max, 0);
}
playerEntities[i] = entity;
}
_entitySystem.Add(playerEntities);
}
private void CreateConcomitants(PlayerEntity entity)
{
(int roleId, int summonConfigId) = entity.ConfigId switch
{
1302 => (5002, 10070301),
_ => (-1, -1)
};
if (roleId != -1)
{
PlayerEntity concomitant = _entityFactory.CreatePlayer(roleId, 0);
EntityConcomitantsComponent concomitants = entity.ComponentSystem.Create<EntityConcomitantsComponent>();
concomitants.CustomEntityIds.Clear();
concomitants.VisionEntityId = concomitant.Id;
concomitants.CustomEntityIds.Add(concomitant.Id);
EntitySummonerComponent summoner = concomitant.ComponentSystem.Create<EntitySummonerComponent>();
summoner.SummonerId = entity.Id;
summoner.SummonConfigId = summonConfigId;
summoner.SummonType = ESummonType.ConcomitantCustom;
summoner.PlayerId = _modelManager.Player.Id;
concomitant.InitProps(_configManager.GetConfig<BasePropertyConfig>(roleId)!);
_entitySystem.Add([concomitant]);
} }
} }
private void CreateWorldEntities() private void CreateWorldEntities()
{ {
_lastDynamicSpawnPos.MergeFrom(_modelManager.Player.Position.Clone()); // Test monster
SpawnDynamicEntities(); MonsterEntity monster = _entityFactory.CreateMonster(102000014); // Monster001
}
private void ClearInactiveEntities()
{
_entitySystem.Destroy(_entitySystem.EnumerateEntities()
.Where(e => e is MonsterEntity && e.DynamicId != 0 &&
e.Pos.GetDistance(_modelManager.Player.Position) > DynamicSpawnRadius).ToArray());
}
private void SpawnDynamicEntities()
{
Vector playerPos = _modelManager.Player.Position;
// Currently only monsters
IEnumerable<LevelEntityConfig> entitiesToSpawn = _configManager.Enumerate<LevelEntityConfig>()
.Where(config => config.MapId == 8 && Math.Abs(config.Transform[0].X / 100 - playerPos.X) < DynamicSpawnRadius && Math.Abs(config.Transform[0].Y / 100 - playerPos.Y) < DynamicSpawnRadius &&
config.BlueprintType.StartsWith("Monster"));
List<MonsterEntity> spawnMonsters = [];
foreach (LevelEntityConfig levelEntity in entitiesToSpawn)
{
if (_entitySystem.HasDynamicEntity(levelEntity.EntityId)) continue;
MonsterEntity monster = _entityFactory.CreateMonster(levelEntity.EntityId);
monster.Pos = new() monster.Pos = new()
{ {
X = levelEntity.Transform[0].X / 100, X = 4444,
Y = levelEntity.Transform[0].Y / 100, Y = -2222,
Z = levelEntity.Transform[0].Z / 100 Z = 260
}; };
_entitySystem.Create(monster);
monster.InitProps(_configManager.GetConfig<BasePropertyConfig>(600000100)!); monster.InitProps(_configManager.GetConfig<BasePropertyConfig>(600000100)!);
spawnMonsters.Add(monster);
}
_entitySystem.Add(spawnMonsters);
} }
} }

View file

@ -1,5 +1,6 @@
using GameServer.Controllers.Attributes; using GameServer.Controllers.Attributes;
using GameServer.Network; using GameServer.Network;
using GameServer.Network.Messages;
using Protocol; using Protocol;
namespace GameServer.Controllers; namespace GameServer.Controllers;
@ -11,8 +12,8 @@ internal class DailyActivityController : Controller
} }
[NetEvent(MessageId.ActivityRequest)] [NetEvent(MessageId.ActivityRequest)]
public RpcResult OnActivityRequest() => Response(MessageId.ActivityResponse, new ActivityResponse()); public ResponseMessage OnActivityRequest() => Response(MessageId.ActivityResponse, new ActivityResponse());
[NetEvent(MessageId.LivenessRequest)] [NetEvent(MessageId.LivenessRequest)]
public RpcResult OnLivenessRequest() => Response(MessageId.LivenessResponse, new LivenessResponse()); public ResponseMessage OnLivenessRequest() => Response(MessageId.LivenessResponse, new LivenessResponse());
} }

View file

@ -1,5 +1,6 @@
using GameServer.Controllers.Attributes; using GameServer.Controllers.Attributes;
using GameServer.Network; using GameServer.Network;
using GameServer.Network.Messages;
using Protocol; using Protocol;
namespace GameServer.Controllers; namespace GameServer.Controllers;
@ -11,5 +12,5 @@ internal class ExchangeRewardController : Controller
} }
[NetEvent(MessageId.ExchangeRewardInfoRequest)] [NetEvent(MessageId.ExchangeRewardInfoRequest)]
public RpcResult OnExchangeRewardInfoRequest() => Response(MessageId.ExchangeRewardInfoResponse, new ExchangeRewardInfoResponse()); public ResponseMessage OnExchangeRewardInfoRequest() => Response(MessageId.ExchangeRewardInfoResponse, new ExchangeRewardInfoResponse());
} }

View file

@ -1,12 +1,13 @@
using GameServer.Controllers.Attributes; using GameServer.Controllers.Attributes;
using GameServer.Network; using GameServer.Network;
using GameServer.Network.Messages;
using Protocol; using Protocol;
namespace GameServer.Controllers; namespace GameServer.Controllers;
internal class ExploreProgressController : Controller internal class ExploreProgressController : Controller
{ {
private static readonly int[] s_areaIds = [1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 100, 101, 102, 103, 107, 110, 113, 124, 122, 199, 301, 302, 303, 401, 402, 403, 404, 405, 406, 407, 408, 708, 601, 602, 603, 606, 607, 608, 609, 202, 203, 204, 501, 502, 503, 504, 508, 802, 803, 805, 807, 702, 703, 704, 705, 706, 709, 1201, 1202, 1203, 1204, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1301, 119, 120, 10001, 10002, 10003, 10004, 10005, 11001, 12001, 12002, 12003, 1500001, 1500002, 14001, 14002, 14003, 14004, 14005, 14006, 14007, 14008, 14011, 14012, 14013, 14021, 14022, 123, 125, 51, 804]; private static readonly int[] s_areaIds = [1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 100, 101, 102, 103, 107, 110, 113, 124, 122, 199, 301, 302, 303, 401, 402, 403, 404, 405, 406, 407, 408, 708, 601, 602, 603, 606, 607, 608, 609, 202, 203, 204, 501, 502, 503, 504, 508, 802, 803, 805, 807, 702, 703, 704, 705, 706, 709, 1201, 1202, 1203, 1204, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1301, 119, 120, 10001, 10002, 10003, 10004, 10005, 11001, 12001, 12002, 12003, 1500001, 1500002, 14001, 14002, 14003, 14004, 14005, 14006, 14007, 14008, 14011, 14012, 14013, 14021, 14022, 123, 125, 51, 804];
private static readonly (int, int)[] s_exploreIds = [(1, 2), (2, 2), (3, 2), (11, 4), (12, 4), (13, 4), (21, 6), (22, 6), (23, 6), (24, 6), (31, 8), (32, 8), (33, 8), (34, 8), (41, 10), (42, 10), (43, 10), (44, 10), (51, 12), (52, 12), (53, 12), (54, 12), (6, 3), (7, 3), (8, 3), (9, 3), (14, 4), (15, 4), (16, 5), (17, 5), (18, 5), (19, 5), (25, 6), (26, 7), (27, 7), (28, 7), (29, 7), (45, 10), (55, 12), (4, 2), (5, 2), (20, 5), (30, 7), (35, 8)]; private static readonly (int, int)[] s_exploreIds = [(1, 2), (2, 2), (3, 2), (10, 3), (11, 4), (12, 4), (13, 4), (21, 6), (22, 6), (23, 6), (24, 6), (31, 8), (32, 8), (33, 8), (34, 8), (41, 10), (42, 10), (43, 10), (44, 10), (51, 12), (52, 12), (53, 12), (54, 12), (6, 3), (7, 3), (8, 3), (9, 3), (14, 4), (15, 4), (16, 5), (17, 5), (18, 5), (19, 5), (25, 6), (26, 7), (27, 7), (28, 7), (29, 7), (45, 10), (55, 12), (4, 2), (5, 2), (20, 5), (30, 7), (35, 8)];
public ExploreProgressController(PlayerSession session) : base(session) public ExploreProgressController(PlayerSession session) : base(session)
{ {
@ -14,7 +15,7 @@ internal class ExploreProgressController : Controller
} }
[NetEvent(MessageId.ExploreProgressRequest)] [NetEvent(MessageId.ExploreProgressRequest)]
public RpcResult OnExploreProgressRequest() public ResponseMessage OnExploreProgressRequest()
{ {
return Response(MessageId.ExploreProgressResponse, new ExploreProgressResponse return Response(MessageId.ExploreProgressResponse, new ExploreProgressResponse
{ {

View file

@ -90,13 +90,13 @@ internal class EventHandlerFactory
var builder = ImmutableDictionary.CreateBuilder<MessageId, RpcHandler>(); var builder = ImmutableDictionary.CreateBuilder<MessageId, RpcHandler>();
MethodInfo getServiceMethod = typeof(ServiceProviderServiceExtensions).GetMethod(nameof(ServiceProviderServiceExtensions.GetRequiredService), [typeof(IServiceProvider)])!; MethodInfo getServiceMethod = typeof(ServiceProviderServiceExtensions).GetMethod(nameof(ServiceProviderServiceExtensions.GetRequiredService), [typeof(IServiceProvider)])!;
MethodInfo taskFromResultMethod = typeof(Task).GetMethod(nameof(Task.FromResult))!.MakeGenericMethod(typeof(RpcResult)); MethodInfo taskFromResultMethod = typeof(Task).GetMethod(nameof(Task.FromResult))!.MakeGenericMethod(typeof(ResponseMessage));
foreach (Type type in controllerTypes) foreach (Type type in controllerTypes)
{ {
IEnumerable<MethodInfo> methods = type.GetMethods() IEnumerable<MethodInfo> methods = type.GetMethods()
.Where(method => method.GetCustomAttribute<NetEventAttribute>() != null .Where(method => method.GetCustomAttribute<NetEventAttribute>() != null
&& (method.ReturnType == typeof(Task<RpcResult>) || method.ReturnType == typeof(RpcResult))); && (method.ReturnType == typeof(Task<ResponseMessage>) || method.ReturnType == typeof(ResponseMessage)));
foreach (MethodInfo method in methods) foreach (MethodInfo method in methods)
{ {
@ -108,7 +108,7 @@ internal class EventHandlerFactory
MethodCallExpression getServiceCall = Expression.Call(getServiceMethod.MakeGenericMethod(type), serviceProviderParam); MethodCallExpression getServiceCall = Expression.Call(getServiceMethod.MakeGenericMethod(type), serviceProviderParam);
Expression handlerCall = Expression.Call(getServiceCall, method, FetchArgumentsForMethod(method, serviceProviderParam, getServiceMethod, dataParam)); Expression handlerCall = Expression.Call(getServiceCall, method, FetchArgumentsForMethod(method, serviceProviderParam, getServiceMethod, dataParam));
if (method.ReturnType == typeof(RpcResult)) // Allow non-async methods as well if (method.ReturnType == typeof(ResponseMessage)) // Allow non-async methods as well
handlerCall = Expression.Call(taskFromResultMethod, handlerCall); handlerCall = Expression.Call(taskFromResultMethod, handlerCall);
Expression<RpcHandler> lambda = Expression.Lambda<RpcHandler>(handlerCall, serviceProviderParam, dataParam); Expression<RpcHandler> lambda = Expression.Lambda<RpcHandler>(handlerCall, serviceProviderParam, dataParam);

View file

@ -1,5 +1,6 @@
using GameServer.Controllers.Attributes; using GameServer.Controllers.Attributes;
using GameServer.Network; using GameServer.Network;
using GameServer.Network.Messages;
using Protocol; using Protocol;
namespace GameServer.Controllers; namespace GameServer.Controllers;
@ -11,8 +12,8 @@ internal class FormationAttributeController : Controller
} }
[NetEvent(MessageId.TimeCheckRequest)] [NetEvent(MessageId.TimeCheckRequest)]
public RpcResult OnTimeCheckRequest() => Response(MessageId.TimeCheckResponse, new TimeCheckResponse()); public ResponseMessage OnTimeCheckRequest() => Response(MessageId.TimeCheckResponse, new TimeCheckResponse());
[NetEvent(MessageId.FormationAttrRequest)] [NetEvent(MessageId.FormationAttrRequest)]
public RpcResult OnFormationAttrRequest() => Response(MessageId.FormationAttrResponse, new FormationAttrResponse()); public ResponseMessage OnFormationAttrRequest() => Response(MessageId.FormationAttrResponse, new FormationAttrResponse());
} }

View file

@ -1,6 +1,8 @@
using GameServer.Controllers.Attributes; using GameServer.Controllers.Attributes;
using GameServer.Models; using GameServer.Models;
using GameServer.Network; using GameServer.Network;
using GameServer.Network.Messages;
using GameServer.Systems.Entity;
using GameServer.Systems.Event; using GameServer.Systems.Event;
using Protocol; using Protocol;
@ -15,7 +17,7 @@ internal class FormationController : Controller
} }
[NetEvent(MessageId.GetFormationDataRequest)] [NetEvent(MessageId.GetFormationDataRequest)]
public RpcResult OnGetFormationDataRequest() => Response(MessageId.GetFormationDataResponse, new GetFormationDataResponse public ResponseMessage OnGetFormationDataRequest() => Response(MessageId.GetFormationDataResponse, new GetFormationDataResponse
{ {
Formations = Formations =
{ {
@ -30,7 +32,7 @@ internal class FormationController : Controller
}); });
[NetEvent(MessageId.UpdateFormationRequest)] [NetEvent(MessageId.UpdateFormationRequest)]
public async Task<RpcResult> OnUpdateFormationRequest(UpdateFormationRequest request, EventSystem eventSystem) public async Task<ResponseMessage> OnUpdateFormationRequest(UpdateFormationRequest request, EventSystem eventSystem)
{ {
_modelManager.Formation.Set([.. request.Formation.RoleIds]); _modelManager.Formation.Set([.. request.Formation.RoleIds]);
await eventSystem.Emit(GameEventType.FormationUpdated); await eventSystem.Emit(GameEventType.FormationUpdated);

View file

@ -1,5 +1,6 @@
using GameServer.Controllers.Attributes; using GameServer.Controllers.Attributes;
using GameServer.Network; using GameServer.Network;
using GameServer.Network.Messages;
using Protocol; using Protocol;
namespace GameServer.Controllers; namespace GameServer.Controllers;
@ -11,11 +12,11 @@ internal class FriendSystemController : Controller
} }
[NetEvent(MessageId.FriendAllRequest)] [NetEvent(MessageId.FriendAllRequest)]
public RpcResult OnFriendAllRequest() => Response(MessageId.FriendAllResponse, new FriendAllResponse public ResponseMessage OnFriendAllRequest() => Response(MessageId.FriendAllResponse, new FriendAllResponse
{ {
FriendInfoList = FriendInfoList =
{ {
CreateDummyFriendInfo(1338, "Yangyang", "discord.gg/reversedrooms", 1402) CreateDummyFriendInfo(1338, "Taoqi", "discord.gg/reversedrooms", 1601)
} }
}); });

View file

@ -1,5 +1,6 @@
using GameServer.Controllers.Attributes; using GameServer.Controllers.Attributes;
using GameServer.Network; using GameServer.Network;
using GameServer.Network.Messages;
using Protocol; using Protocol;
namespace GameServer.Controllers; namespace GameServer.Controllers;
@ -11,5 +12,5 @@ internal class GachaController : Controller
} }
[NetEvent(MessageId.GachaInfoRequest)] [NetEvent(MessageId.GachaInfoRequest)]
public RpcResult OnGachaInfoRequest() => Response(MessageId.GachaInfoResponse, new GachaInfoResponse()); public ResponseMessage OnGachaInfoRequest() => Response(MessageId.GachaInfoResponse, new GachaInfoResponse());
} }

View file

@ -1,5 +1,6 @@
using GameServer.Controllers.Attributes; using GameServer.Controllers.Attributes;
using GameServer.Network; using GameServer.Network;
using GameServer.Network.Messages;
using Protocol; using Protocol;
namespace GameServer.Controllers; namespace GameServer.Controllers;
@ -11,5 +12,5 @@ internal class InfluenceReputationController : Controller
} }
[NetEvent(MessageId.InfluenceInfoRequest)] [NetEvent(MessageId.InfluenceInfoRequest)]
public RpcResult OnInfluenceInfoRequest() => Response(MessageId.InfluenceInfoResponse, new InfluenceInfoResponse()); public ResponseMessage OnInfluenceInfoRequest() => Response(MessageId.InfluenceInfoResponse, new InfluenceInfoResponse());
} }

View file

@ -1,10 +1,6 @@
using Core.Config; using GameServer.Controllers.Attributes;
using GameServer.Controllers.Attributes;
using GameServer.Extensions.Logic;
using GameServer.Models;
using GameServer.Network; using GameServer.Network;
using GameServer.Systems.Entity; using GameServer.Network.Messages;
using GameServer.Systems.Event;
using Protocol; using Protocol;
namespace GameServer.Controllers; namespace GameServer.Controllers;
@ -16,101 +12,14 @@ internal class InventoryController : Controller
} }
[NetEvent(MessageId.NormalItemRequest)] [NetEvent(MessageId.NormalItemRequest)]
public RpcResult OnNormalItemRequest(ModelManager modelManager) => Response(MessageId.NormalItemResponse, new NormalItemResponse public ResponseMessage OnNormalItemRequest() => Response(MessageId.NormalItemResponse, new NormalItemResponse());
{
NormalItemList = { modelManager.Inventory.ItemList }
});
[NetEvent(MessageId.WeaponItemRequest)] [NetEvent(MessageId.WeaponItemRequest)]
public RpcResult OnWeaponItemRequest(ModelManager modelManager) => Response(MessageId.WeaponItemResponse, new WeaponItemResponse public ResponseMessage OnWeaponItemRequest() => Response(MessageId.WeaponItemResponse, new WeaponItemResponse());
{
WeaponItemList =
{
modelManager.Inventory.WeaponList
}
});
[NetEvent(MessageId.PhantomItemRequest)] [NetEvent(MessageId.PhantomItemRequest)]
public RpcResult OnPhantomItemRequest() => Response(MessageId.PhantomItemResponse, new PhantomItemResponse()); public ResponseMessage OnPhantomItemRequest() => Response(MessageId.PhantomItemResponse, new PhantomItemResponse());
[NetEvent(MessageId.ItemExchangeInfoRequest)] [NetEvent(MessageId.ItemExchangeInfoRequest)]
public RpcResult OnItemExchangeInfoRequest() => Response(MessageId.ItemExchangeInfoResponse, new ItemExchangeInfoResponse()); public ResponseMessage OnItemExchangeInfoRequest() => Response(MessageId.ItemExchangeInfoResponse, new ItemExchangeInfoResponse());
[NetEvent(MessageId.EquipTakeOnRequest)]
public RpcResult OnEquipTakeOnRequest(EquipTakeOnRequest request, ModelManager modelManager, CreatureController creatureController, RoleController roleController, ConfigManager configManager)
{
WeaponItem? weapon = modelManager.Inventory.GetWeaponById(request.Data.EquipIncId);
if (weapon == null) return Response(MessageId.EquipTakeOnResponse, new EquipTakeOnResponse
{
ErrorCode = (int)ErrorCode.ErrItemIdInvaild
});
WeaponConfig weaponConf = configManager.GetConfig<WeaponConfig>(weapon.Id)!;
roleInfo? role = modelManager.Roles.GetRoleById(request.Data.RoleId);
if (role == null) return Response(MessageId.EquipTakeOnResponse, new EquipTakeOnResponse
{
ErrorCode = (int)ErrorCode.NotValidRole
});
// Take off previous weapon
WeaponItem? prevWeapon = modelManager.Inventory.WeaponList.SingleOrDefault(weapon => weapon.RoleId == role.RoleId);
if (prevWeapon != null) prevWeapon.RoleId = 0;
// Set new weapon
weapon.RoleId = role.RoleId;
roleController.ApplyWeaponPropertiesToRole(role.RoleId, weaponConf);
// Update entity (if this role is currently active)
PlayerEntity? entity = creatureController.GetPlayerEntityByRoleId(request.Data.RoleId);
entity?.ChangeEquipment(weapon.Id);
entity?.ChangeGameplayAttributes(role.GetAttributeList());
// Response
EquipTakeOnResponse response = new()
{
DataList =
{
new RoleLoadEquipData
{
RoleId = request.Data.RoleId,
Pos = request.Data.Pos,
EquipIncId = request.Data.EquipIncId
}
}
};
if (prevWeapon != null)
{
response.DataList.Add(new RoleLoadEquipData
{
EquipIncId = prevWeapon.IncrId
});
}
return Response(MessageId.EquipTakeOnResponse, response);
}
[GameEvent(GameEventType.EnterGame)]
public async Task OnEnterGame()
{
await Session.Push(MessageId.ItemPkgOpenNotify, new ItemPkgOpenNotify
{
OpenPkg = { 0, 2, 1, 3, 4, 5, 6, 7 }
});
}
[GameEvent(GameEventType.DebugUnlockAllItems)]
public void DebugUnlockAllWeapons(ConfigManager configManager, ModelManager modelManager)
{
foreach (WeaponConfig weaponConf in configManager.Enumerate<WeaponConfig>())
{
modelManager.Inventory.AddNewWeapon(weaponConf.ItemId);
}
foreach (ItemInfoConfig itemInfo in configManager.Enumerate<ItemInfoConfig>())
{
modelManager.Inventory.AddItem(itemInfo.Id, itemInfo.MaxStackableNum);
}
}
} }

View file

@ -1,6 +1,8 @@
using GameServer.Controllers.Attributes; using GameServer.Controllers.Attributes;
using GameServer.Network; using GameServer.Network;
using GameServer.Network.Messages;
using GameServer.Systems.Event; using GameServer.Systems.Event;
using Microsoft.Extensions.Logging;
using Protocol; using Protocol;
namespace GameServer.Controllers; namespace GameServer.Controllers;
@ -12,36 +14,29 @@ internal class LoginController : Controller
} }
[NetEvent(MessageId.LoginRequest)] [NetEvent(MessageId.LoginRequest)]
public async Task<RpcResult> OnLoginRequest(EventSystem eventSystem) public async Task<ResponseMessage> OnLoginRequest(EventSystem eventSystem)
{ {
await eventSystem.Emit(GameEventType.Login); await eventSystem.Emit(GameEventType.Login);
// Debug
await eventSystem.Emit(GameEventType.DebugUnlockAllRoles);
await eventSystem.Emit(GameEventType.DebugUnlockAllItems);
return Response(MessageId.LoginResponse, new LoginResponse return Response(MessageId.LoginResponse, new LoginResponse
{ {
Code = 0, Code = 0,
Platform = "CBT3_EU", Platform = "PC",
Timestamp = DateTimeOffset.Now.ToUnixTimeSeconds() Timestamp = DateTimeOffset.Now.ToUnixTimeSeconds()
}); });
} }
[NetEvent(MessageId.EnterGameRequest)] [NetEvent(MessageId.EnterGameRequest)]
public RpcResult OnEnterGameRequest() public async Task<ResponseMessage> OnEnterGameRequest(EnterGameRequest request, ILogger<LoginController> logger, EventSystem eventSystem)
{ {
return Response(MessageId.EnterGameResponse, new EnterGameResponse()) logger.LogInformation("Enter Game Request:\n{req}", request);
.AddPostEvent(GameEventType.EnterGame)
.AddPostEvent(GameEventType.PushDataDone);
}
[GameEvent(GameEventType.PushDataDone)] await eventSystem.Emit(GameEventType.EnterGame);
public async Task OnPushDataDone()
{
await Session.Push(MessageId.PushDataCompleteNotify, new PushDataCompleteNotify()); await Session.Push(MessageId.PushDataCompleteNotify, new PushDataCompleteNotify());
return Response(MessageId.EnterGameResponse, new EnterGameResponse());
} }
[NetEvent(MessageId.HeartbeatRequest)] [NetEvent(MessageId.HeartbeatRequest)]
public RpcResult OnHeartbeatRequest() => Response(MessageId.HeartbeatResponse, new HeartbeatResponse()); public ResponseMessage OnHeartbeatRequest() => Response(MessageId.HeartbeatResponse, new HeartbeatResponse());
} }

View file

@ -1,5 +1,6 @@
using GameServer.Controllers.Attributes; using GameServer.Controllers.Attributes;
using GameServer.Network; using GameServer.Network;
using GameServer.Network.Messages;
using Protocol; using Protocol;
namespace GameServer.Controllers; namespace GameServer.Controllers;
@ -11,5 +12,5 @@ internal class LordGymController : Controller
} }
[NetEvent(MessageId.LordGymInfoRequest)] [NetEvent(MessageId.LordGymInfoRequest)]
public RpcResult OnLordGymInfoRequest() => Response(MessageId.LordGymInfoResponse, new LordGymInfoResponse()); public ResponseMessage OnLordGymInfoRequest() => Response(MessageId.LordGymInfoResponse, new LordGymInfoResponse());
} }

View file

@ -1,6 +1,7 @@
using GameServer.Controllers.Attributes; using GameServer.Controllers.Attributes;
using GameServer.Models; using GameServer.Models;
using GameServer.Network; using GameServer.Network;
using GameServer.Network.Messages;
using GameServer.Systems.Event; using GameServer.Systems.Event;
using Protocol; using Protocol;
@ -21,81 +22,52 @@ internal class PlayerInfoController : Controller
{ {
RandomSeed = 1337, RandomSeed = 1337,
Id = player.Id, Id = player.Id,
Birthday = player.BirthDay, Birthday = 0,
Attributes = { player.Attributes }, Attributes =
RoleShowList =
{ {
new RoleShowEntry new PlayerAttr
{ {
Level = 1, Key = (int)PlayerAttrKey.Name,
RoleId = 1501 // Rover ValueType = (int)PlayerAttrType.String,
} StringValue = player.Name
}, },
CurCardId = 80060000, new PlayerAttr
CardUnlockList =
{ {
new CardShowEntry Key = (int)PlayerAttrKey.Level,
ValueType = (int)PlayerAttrType.Int32,
Int32Value = 10
},
new PlayerAttr
{ {
CardId = 80060000, Key = (int)PlayerAttrKey.HeadPhoto,
IsRead = true ValueType = (int)PlayerAttrType.Int32,
Int32Value = 1601
} }
} }
}; };
for (int i = 0; i < player.Characters.Length; i++)
{
basicInfo.RoleShowList.Add(new RoleShowEntry
{
Level = 1,
RoleId = player.Characters[i]
});
}
await Session.Push(MessageId.BasicInfoNotify, basicInfo); await Session.Push(MessageId.BasicInfoNotify, basicInfo);
} }
[NetEvent(MessageId.ChangeHeadPhotoRequest)]
public RpcResult OnChangeHeadPhotoRequest(ChangeHeadPhotoRequest request, ModelManager modelManager)
{
modelManager.Player.SetAttribute(PlayerAttrKey.HeadPhoto, request.HeadPhotoId);
return Response(MessageId.ChangeHeadPhotoResponse, new ChangeHeadPhotoResponse
{
HeadPhotoId = request.HeadPhotoId
});
}
[NetEvent(MessageId.BirthdayInitRequest)]
public RpcResult OnBirthdayInitRequest(BirthdayInitRequest request, ModelManager modelManager)
{
modelManager.Player.BirthDay = request.Birthday;
return Response(MessageId.BirthdayInitResponse, new BirthdayInitResponse());
}
[NetEvent(MessageId.ModifySignatureRequest)]
public RpcResult OnModifySignatureRequest(ModifySignatureRequest request, ModelManager modelManager)
{
modelManager.Player.SetAttribute(PlayerAttrKey.Sign, request.Signature);
return Response(MessageId.ModifySignatureResponse, new ModifySignatureResponse
{
Signature = request.Signature
});
}
[NetEvent(MessageId.ModifyNameRequest)]
public RpcResult OnModifyNameRequest(ModifyNameRequest request, ModelManager modelManager)
{
modelManager.Player.SetAttribute(PlayerAttrKey.Name, request.Name);
return Response(MessageId.ModifyNameResponse, new ModifyNameResponse
{
Name = request.Name
});
}
[NetEvent(MessageId.PlayerBasicInfoGetRequest)] [NetEvent(MessageId.PlayerBasicInfoGetRequest)]
public RpcResult OnPlayerBasicInfoGetRequest() public ResponseMessage OnPlayerBasicInfoGetRequest()
{ {
return Response(MessageId.PlayerBasicInfoGetResponse, new PlayerBasicInfoGetResponse return Response(MessageId.PlayerBasicInfoGetResponse, new PlayerBasicInfoGetResponse
{ {
Info = new PlayerDetails Info = new PlayerDetails
{ {
Name = "Yangyang", Name = "Taoqi",
Signature = "discord.gg/reversedrooms", Signature = "discord.gg/reversedrooms",
HeadId = 1402, HeadId = 1601,
PlayerId = 1338, PlayerId = 1338,
IsOnline = true, IsOnline = true,
LastOfflineTime = -1, LastOfflineTime = -1,

View file

@ -1,21 +0,0 @@
using GameServer.Network.Messages;
using GameServer.Systems.Event;
namespace GameServer.Controllers.Result;
internal class RpcResult
{
public ResponseMessage Response { get; }
public List<GameEventType> PostEvents { get; }
public RpcResult(ResponseMessage response)
{
Response = response;
PostEvents = [];
}
public RpcResult AddPostEvent(GameEventType type)
{
PostEvents.Add(type);
return this;
}
}

View file

@ -1,5 +1,6 @@
using GameServer.Controllers.Attributes; using GameServer.Controllers.Attributes;
using GameServer.Network; using GameServer.Network;
using GameServer.Network.Messages;
using Protocol; using Protocol;
namespace GameServer.Controllers; namespace GameServer.Controllers;
@ -11,5 +12,5 @@ internal class RoguelikeController : Controller
} }
[NetEvent(MessageId.RoguelikeSeasonDataRequest)] [NetEvent(MessageId.RoguelikeSeasonDataRequest)]
public RpcResult OnRoguelikeSeasonDataRequest() => Response(MessageId.RoguelikeSeasonDataResponse, new RoguelikeSeasonDataResponse()); public ResponseMessage OnRoguelikeSeasonDataRequest() => Response(MessageId.RoguelikeSeasonDataResponse, new RoguelikeSeasonDataResponse());
} }

View file

@ -1,63 +1,42 @@
using Core.Config; using Core.Config;
using GameServer.Controllers.Attributes; using GameServer.Controllers.Attributes;
using GameServer.Extensions.Logic;
using GameServer.Models; using GameServer.Models;
using GameServer.Network; using GameServer.Network;
using GameServer.Network.Messages;
using GameServer.Systems.Event; using GameServer.Systems.Event;
using GameServer.Systems.Notify;
using Protocol; using Protocol;
namespace GameServer.Controllers; namespace GameServer.Controllers;
internal class RoleController : Controller internal class RoleController : Controller
{ {
private readonly ModelManager _modelManager; public RoleController(PlayerSession session) : base(session)
private readonly IGameActionListener _listener;
public RoleController(PlayerSession session, ModelManager modelManager, IGameActionListener listener) : base(session)
{ {
_modelManager = modelManager; // RoleController.
_listener = listener;
}
public void ApplyWeaponPropertiesToRole(int roleId, WeaponConfig weaponConfiguration)
{
roleInfo? role = _modelManager.Roles.GetRoleById(roleId) ?? throw new ArgumentException($"Role with id {roleId} doesn't exist");
role.ApplyWeaponProperties(weaponConfiguration);
_ = _listener.OnRolePropertiesUpdated(roleId, role.BaseProp, role.AddProp);
}
[GameEvent(GameEventType.DebugUnlockAllRoles)]
public void UnlockAllRoles(ConfigManager configManager)
{
foreach (RoleInfoConfig roleConfig in configManager.Enumerate<RoleInfoConfig>())
{
roleInfo role = _modelManager.Roles.Create(roleConfig.Id);
role.BaseProp.AddRange(CreateBasePropList(configManager.GetConfig<BasePropertyConfig>(roleConfig.Id)));
WeaponItem weapon = _modelManager.Inventory.AddNewWeapon(roleConfig.InitWeaponItemId);
weapon.RoleId = role.RoleId;
role.ApplyWeaponProperties(configManager.GetConfig<WeaponConfig>(weapon.Id)!);
}
} }
[GameEvent(GameEventType.EnterGame)] [GameEvent(GameEventType.EnterGame)]
public async Task OnEnterGame(ModelManager modelManager) public async Task OnEnterGame(ModelManager modelManager, ConfigManager configManager)
{ {
PlayerModel player = modelManager.Player;
await Session.Push(MessageId.PbGetRoleListNotify, new PbGetRoleListNotify await Session.Push(MessageId.PbGetRoleListNotify, new PbGetRoleListNotify
{ {
RoleList = RoleList =
{ {
modelManager.Roles.Roles configManager.GetCollection(ConfigType.RoleInfo)
.Enumerate<RoleInfoConfig>()
.Select(config => new roleInfo
{
RoleId = config.Id,
Level = 1
})
} }
}); });
} }
[NetEvent(MessageId.SwitchRoleRequest)] [NetEvent(MessageId.SwitchRoleRequest)]
public async Task<RpcResult> OnSwitchRoleRequest(SwitchRoleRequest request, CreatureController creatureController) public ResponseMessage OnSwitchRoleRequest(SwitchRoleRequest request)
{ {
await creatureController.SwitchPlayerEntity(request.RoleId);
return Response(MessageId.SwitchRoleResponse, new SwitchRoleResponse return Response(MessageId.SwitchRoleResponse, new SwitchRoleResponse
{ {
RoleId = request.RoleId RoleId = request.RoleId
@ -65,180 +44,5 @@ internal class RoleController : Controller
} }
[NetEvent(MessageId.RoleFavorListRequest)] [NetEvent(MessageId.RoleFavorListRequest)]
public RpcResult OnRoleFavorListRequest() => Response(MessageId.RoleFavorListResponse, new RoleFavorListResponse()); public ResponseMessage OnRoleFavorListRequest() => Response(MessageId.RoleFavorListResponse, new RoleFavorListResponse());
[NetEvent(MessageId.ResonantChainUnlockRequest)]
public RpcResult OnResonantChainUnlockRequest(ResonantChainUnlockRequest request, ModelManager modelManager, ConfigManager configManager)
{
roleInfo? role = modelManager.Roles.Roles.Find(r => r.RoleId == request.RoleId)!;
if (role != null)
{
RoleInfoConfig roleConfig = configManager.GetConfig<RoleInfoConfig>(request.RoleId)!;
int resonantChainGroupId = roleConfig.ResonantChainGroupId;
// Todo: add buff by _resonantChainGroupId
int curr = role.ResonantChainGroupIndex;
int next = Math.Min(curr + 1, 6);
role.ResonantChainGroupIndex = next;
return Response(MessageId.ResonantChainUnlockResponse, new ResonantChainUnlockResponse
{
RoleId = request.RoleId,
ResonantChainGroupIndex = next
});
}
return Response(MessageId.ResonantChainUnlockResponse, new ResonantChainUnlockResponse
{
ErrCode = (int)ErrorCode.ErrRoleResonNotActive
});
}
private static List<ArrayIntInt> CreateBasePropList(BasePropertyConfig? config)
{
List<ArrayIntInt> baseProp = [];
if (config == null) return baseProp;
baseProp.Add(new() { Key = (int)EAttributeType.Lv, Value = config.Lv });
baseProp.Add(new() { Key = (int)EAttributeType.LifeMax, Value = config.LifeMax });
baseProp.Add(new() { Key = (int)EAttributeType.Life, Value = config.Life });
baseProp.Add(new() { Key = (int)EAttributeType.Sheild, Value = config.Sheild });
baseProp.Add(new() { Key = (int)EAttributeType.SheildDamageChange, Value = config.SheildDamageChange });
baseProp.Add(new() { Key = (int)EAttributeType.SheildDamageReduce, Value = config.SheildDamageReduce });
baseProp.Add(new() { Key = (int)EAttributeType.Atk, Value = config.Atk });
baseProp.Add(new() { Key = (int)EAttributeType.Crit, Value = config.Crit });
baseProp.Add(new() { Key = (int)EAttributeType.CritDamage, Value = config.CritDamage });
baseProp.Add(new() { Key = (int)EAttributeType.Def, Value = config.Def });
baseProp.Add(new() { Key = (int)EAttributeType.EnergyEfficiency, Value = config.EnergyEfficiency });
baseProp.Add(new() { Key = (int)EAttributeType.CdReduse, Value = config.CdReduse });
baseProp.Add(new() { Key = (int)EAttributeType.ReactionEfficiency, Value = config.ReactionEfficiency });
baseProp.Add(new() { Key = (int)EAttributeType.DamageChangeNormalSkill, Value = config.DamageChangeNormalSkill });
baseProp.Add(new() { Key = (int)EAttributeType.DamageChange, Value = config.DamageChange });
baseProp.Add(new() { Key = (int)EAttributeType.DamageReduce, Value = config.DamageReduce });
baseProp.Add(new() { Key = (int)EAttributeType.DamageChangeAuto, Value = config.DamageChangeAuto });
baseProp.Add(new() { Key = (int)EAttributeType.DamageChangeCast, Value = config.DamageChangeCast });
baseProp.Add(new() { Key = (int)EAttributeType.DamageChangeUltra, Value = config.DamageChangeUltra });
baseProp.Add(new() { Key = (int)EAttributeType.DamageChangeQte, Value = config.DamageChangeQte });
baseProp.Add(new() { Key = (int)EAttributeType.DamageChangePhys, Value = config.DamageChangePhys });
baseProp.Add(new() { Key = (int)EAttributeType.DamageChangeElement1, Value = config.DamageChangeElement1 });
baseProp.Add(new() { Key = (int)EAttributeType.DamageChangeElement2, Value = config.DamageChangeElement2 });
baseProp.Add(new() { Key = (int)EAttributeType.DamageChangeElement3, Value = config.DamageChangeElement3 });
baseProp.Add(new() { Key = (int)EAttributeType.DamageChangeElement4, Value = config.DamageChangeElement4 });
baseProp.Add(new() { Key = (int)EAttributeType.DamageChangeElement5, Value = config.DamageChangeElement5 });
baseProp.Add(new() { Key = (int)EAttributeType.DamageChangeElement6, Value = config.DamageChangeElement6 });
baseProp.Add(new() { Key = (int)EAttributeType.DamageResistancePhys, Value = config.DamageResistancePhys });
baseProp.Add(new() { Key = (int)EAttributeType.DamageResistanceElement1, Value = config.DamageResistanceElement1 });
baseProp.Add(new() { Key = (int)EAttributeType.DamageResistanceElement2, Value = config.DamageResistanceElement2 });
baseProp.Add(new() { Key = (int)EAttributeType.DamageResistanceElement3, Value = config.DamageResistanceElement3 });
baseProp.Add(new() { Key = (int)EAttributeType.DamageResistanceElement4, Value = config.DamageResistanceElement4 });
baseProp.Add(new() { Key = (int)EAttributeType.DamageResistanceElement5, Value = config.DamageResistanceElement5 });
baseProp.Add(new() { Key = (int)EAttributeType.DamageResistanceElement6, Value = config.DamageResistanceElement6 });
baseProp.Add(new() { Key = (int)EAttributeType.HealChange, Value = config.HealChange });
baseProp.Add(new() { Key = (int)EAttributeType.HealedChange, Value = config.HealedChange });
baseProp.Add(new() { Key = (int)EAttributeType.DamageReducePhys, Value = config.DamageReducePhys });
baseProp.Add(new() { Key = (int)EAttributeType.DamageReduceElement1, Value = config.DamageReduceElement1 });
baseProp.Add(new() { Key = (int)EAttributeType.DamageReduceElement2, Value = config.DamageReduceElement2 });
baseProp.Add(new() { Key = (int)EAttributeType.DamageReduceElement3, Value = config.DamageReduceElement3 });
baseProp.Add(new() { Key = (int)EAttributeType.DamageReduceElement4, Value = config.DamageReduceElement4 });
baseProp.Add(new() { Key = (int)EAttributeType.DamageReduceElement5, Value = config.DamageReduceElement5 });
baseProp.Add(new() { Key = (int)EAttributeType.DamageReduceElement6, Value = config.DamageReduceElement6 });
baseProp.Add(new() { Key = (int)EAttributeType.ReactionChange1, Value = config.ReactionChange1 });
baseProp.Add(new() { Key = (int)EAttributeType.ReactionChange2, Value = config.ReactionChange2 });
baseProp.Add(new() { Key = (int)EAttributeType.ReactionChange3, Value = config.ReactionChange3 });
baseProp.Add(new() { Key = (int)EAttributeType.ReactionChange4, Value = config.ReactionChange4 });
baseProp.Add(new() { Key = (int)EAttributeType.ReactionChange5, Value = config.ReactionChange5 });
baseProp.Add(new() { Key = (int)EAttributeType.ReactionChange6, Value = config.ReactionChange6 });
baseProp.Add(new() { Key = (int)EAttributeType.ReactionChange7, Value = config.ReactionChange7 });
baseProp.Add(new() { Key = (int)EAttributeType.ReactionChange8, Value = config.ReactionChange8 });
baseProp.Add(new() { Key = (int)EAttributeType.ReactionChange9, Value = config.ReactionChange9 });
baseProp.Add(new() { Key = (int)EAttributeType.ReactionChange10, Value = config.ReactionChange10 });
baseProp.Add(new() { Key = (int)EAttributeType.ReactionChange11, Value = config.ReactionChange11 });
baseProp.Add(new() { Key = (int)EAttributeType.ReactionChange12, Value = config.ReactionChange12 });
baseProp.Add(new() { Key = (int)EAttributeType.ReactionChange13, Value = config.ReactionChange13 });
baseProp.Add(new() { Key = (int)EAttributeType.ReactionChange14, Value = config.ReactionChange14 });
baseProp.Add(new() { Key = (int)EAttributeType.ReactionChange15, Value = config.ReactionChange15 });
baseProp.Add(new() { Key = (int)EAttributeType.EnergyMax, Value = config.EnergyMax });
baseProp.Add(new() { Key = (int)EAttributeType.Energy, Value = config.Energy });
baseProp.Add(new() { Key = (int)EAttributeType.SpecialEnergy1Max, Value = config.SpecialEnergy1Max });
baseProp.Add(new() { Key = (int)EAttributeType.SpecialEnergy1, Value = config.SpecialEnergy1 });
baseProp.Add(new() { Key = (int)EAttributeType.SpecialEnergy2Max, Value = config.SpecialEnergy2Max });
baseProp.Add(new() { Key = (int)EAttributeType.SpecialEnergy2, Value = config.SpecialEnergy2 });
baseProp.Add(new() { Key = (int)EAttributeType.SpecialEnergy3Max, Value = config.SpecialEnergy3Max });
baseProp.Add(new() { Key = (int)EAttributeType.SpecialEnergy3, Value = config.SpecialEnergy3 });
baseProp.Add(new() { Key = (int)EAttributeType.SpecialEnergy4Max, Value = config.SpecialEnergy4Max });
baseProp.Add(new() { Key = (int)EAttributeType.SpecialEnergy4, Value = config.SpecialEnergy4 });
baseProp.Add(new() { Key = (int)EAttributeType.StrengthMax, Value = config.StrengthMax });
baseProp.Add(new() { Key = (int)EAttributeType.Strength, Value = config.Strength });
baseProp.Add(new() { Key = (int)EAttributeType.StrengthRecover, Value = config.StrengthRecover });
baseProp.Add(new() { Key = (int)EAttributeType.StrengthPunishTime, Value = config.StrengthPunishTime });
baseProp.Add(new() { Key = (int)EAttributeType.StrengthRun, Value = config.StrengthRun });
baseProp.Add(new() { Key = (int)EAttributeType.StrengthSwim, Value = config.StrengthSwim });
baseProp.Add(new() { Key = (int)EAttributeType.StrengthFastSwim, Value = config.StrengthFastSwim });
baseProp.Add(new() { Key = (int)EAttributeType.StrengthClimb, Value = config.StrengthClimb });
baseProp.Add(new() { Key = (int)EAttributeType.StrengthFastClimb, Value = config.StrengthFastClimb });
baseProp.Add(new() { Key = (int)EAttributeType.HardnessMax, Value = config.HardnessMax });
baseProp.Add(new() { Key = (int)EAttributeType.Hardness, Value = config.Hardness });
baseProp.Add(new() { Key = (int)EAttributeType.HardnessRecover, Value = config.HardnessRecover });
baseProp.Add(new() { Key = (int)EAttributeType.HardnessPunishTime, Value = config.HardnessPunishTime });
baseProp.Add(new() { Key = (int)EAttributeType.HardnessChange, Value = config.HardnessChange });
baseProp.Add(new() { Key = (int)EAttributeType.HardnessReduce, Value = config.HardnessReduce });
baseProp.Add(new() { Key = (int)EAttributeType.RageMax, Value = config.RageMax });
baseProp.Add(new() { Key = (int)EAttributeType.Rage, Value = config.Rage });
baseProp.Add(new() { Key = (int)EAttributeType.RageRecover, Value = config.RageRecover });
baseProp.Add(new() { Key = (int)EAttributeType.RagePunishTime, Value = config.RagePunishTime });
baseProp.Add(new() { Key = (int)EAttributeType.RageChange, Value = config.RageChange });
baseProp.Add(new() { Key = (int)EAttributeType.RageReduce, Value = config.RageReduce });
baseProp.Add(new() { Key = (int)EAttributeType.ToughMax, Value = config.ToughMax });
baseProp.Add(new() { Key = (int)EAttributeType.Tough, Value = config.Tough });
baseProp.Add(new() { Key = (int)EAttributeType.ToughRecover, Value = config.ToughRecover });
baseProp.Add(new() { Key = (int)EAttributeType.ToughChange, Value = config.ToughChange });
baseProp.Add(new() { Key = (int)EAttributeType.ToughReduce, Value = config.ToughReduce });
baseProp.Add(new() { Key = (int)EAttributeType.ToughRecoverDelayTime, Value = config.ToughRecoverDelayTime });
baseProp.Add(new() { Key = (int)EAttributeType.ElementPower1, Value = config.ElementPower1 });
baseProp.Add(new() { Key = (int)EAttributeType.ElementPower2, Value = config.ElementPower2 });
baseProp.Add(new() { Key = (int)EAttributeType.ElementPower3, Value = config.ElementPower3 });
baseProp.Add(new() { Key = (int)EAttributeType.ElementPower4, Value = config.ElementPower4 });
baseProp.Add(new() { Key = (int)EAttributeType.ElementPower5, Value = config.ElementPower5 });
baseProp.Add(new() { Key = (int)EAttributeType.ElementPower6, Value = config.ElementPower6 });
baseProp.Add(new() { Key = (int)EAttributeType.SpecialDamageChange, Value = config.SpecialDamageChange });
baseProp.Add(new() { Key = (int)EAttributeType.StrengthFastClimbCost, Value = config.StrengthFastClimbCost });
baseProp.Add(new() { Key = (int)EAttributeType.ElementPropertyType, Value = config.ElementPropertyType });
baseProp.Add(new() { Key = (int)EAttributeType.WeakTime, Value = config.WeakTime });
baseProp.Add(new() { Key = (int)EAttributeType.IgnoreDefRate, Value = config.IgnoreDefRate });
baseProp.Add(new() { Key = (int)EAttributeType.IgnoreDamageResistancePhys, Value = config.IgnoreDamageResistancePhys });
baseProp.Add(new() { Key = (int)EAttributeType.IgnoreDamageResistanceElement1, Value = config.IgnoreDamageResistanceElement1 });
baseProp.Add(new() { Key = (int)EAttributeType.IgnoreDamageResistanceElement2, Value = config.IgnoreDamageResistanceElement2 });
baseProp.Add(new() { Key = (int)EAttributeType.IgnoreDamageResistanceElement3, Value = config.IgnoreDamageResistanceElement3 });
baseProp.Add(new() { Key = (int)EAttributeType.IgnoreDamageResistanceElement4, Value = config.IgnoreDamageResistanceElement4 });
baseProp.Add(new() { Key = (int)EAttributeType.IgnoreDamageResistanceElement5, Value = config.IgnoreDamageResistanceElement5 });
baseProp.Add(new() { Key = (int)EAttributeType.IgnoreDamageResistanceElement6, Value = config.IgnoreDamageResistanceElement6 });
baseProp.Add(new() { Key = (int)EAttributeType.SkillToughRatio, Value = config.SkillToughRatio });
baseProp.Add(new() { Key = (int)EAttributeType.StrengthClimbJump, Value = config.StrengthClimbJump });
baseProp.Add(new() { Key = (int)EAttributeType.StrengthGliding, Value = config.StrengthGliding });
baseProp.Add(new() { Key = (int)EAttributeType.Mass, Value = config.Mass });
baseProp.Add(new() { Key = (int)EAttributeType.BrakingFrictionFactor, Value = config.BrakingFrictionFactor });
baseProp.Add(new() { Key = (int)EAttributeType.GravityScale, Value = config.GravityScale });
baseProp.Add(new() { Key = (int)EAttributeType.SpeedRatio, Value = config.SpeedRatio });
baseProp.Add(new() { Key = (int)EAttributeType.DamageChangePhantom, Value = config.DamageChangePhantom });
baseProp.Add(new() { Key = (int)EAttributeType.AutoAttackSpeed, Value = config.AutoAttackSpeed });
baseProp.Add(new() { Key = (int)EAttributeType.CastAttackSpeed, Value = config.CastAttackSpeed });
baseProp.Add(new() { Key = (int)EAttributeType.StatusBuildUp1Max, Value = config.StatusBuildUp1Max });
baseProp.Add(new() { Key = (int)EAttributeType.StatusBuildUp1, Value = config.StatusBuildUp1 });
baseProp.Add(new() { Key = (int)EAttributeType.StatusBuildUp2Max, Value = config.StatusBuildUp2Max });
baseProp.Add(new() { Key = (int)EAttributeType.StatusBuildUp2, Value = config.StatusBuildUp2 });
baseProp.Add(new() { Key = (int)EAttributeType.StatusBuildUp3Max, Value = config.StatusBuildUp3Max });
baseProp.Add(new() { Key = (int)EAttributeType.StatusBuildUp3, Value = config.StatusBuildUp3 });
baseProp.Add(new() { Key = (int)EAttributeType.StatusBuildUp4Max, Value = config.StatusBuildUp4Max });
baseProp.Add(new() { Key = (int)EAttributeType.StatusBuildUp4, Value = config.StatusBuildUp4 });
baseProp.Add(new() { Key = (int)EAttributeType.StatusBuildUp5Max, Value = config.StatusBuildUp5Max });
baseProp.Add(new() { Key = (int)EAttributeType.StatusBuildUp5, Value = config.StatusBuildUp5 });
baseProp.Add(new() { Key = (int)EAttributeType.ParalysisTimeMax, Value = config.ParalysisTimeMax });
baseProp.Add(new() { Key = (int)EAttributeType.ParalysisTime, Value = config.ParalysisTime });
baseProp.Add(new() { Key = (int)EAttributeType.ParalysisTimeRecover, Value = config.ParalysisTimeRecover });
return baseProp;
}
} }

View file

@ -1,5 +1,7 @@
using GameServer.Controllers.Attributes; using GameServer.Controllers.Attributes;
using GameServer.Models;
using GameServer.Network; using GameServer.Network;
using GameServer.Network.Messages;
using GameServer.Systems.Entity; using GameServer.Systems.Entity;
using GameServer.Systems.Entity.Component; using GameServer.Systems.Entity.Component;
using GameServer.Systems.Event; using GameServer.Systems.Event;
@ -18,7 +20,7 @@ internal class RouletteController : Controller
{ {
await Session.Push(MessageId.ExploreToolAllNotify, new ExploreToolAllNotify await Session.Push(MessageId.ExploreToolAllNotify, new ExploreToolAllNotify
{ {
SkillList = { 3001, 3002, 1005, 1006, 1001, 1004, 1003, 1007, 1009 }, SkillList = { 1001, 1004, 1003 },
ExploreSkill = 1001 ExploreSkill = 1001
}); });
@ -32,14 +34,14 @@ internal class RouletteController : Controller
}, },
new ExploreSkillRoulette new ExploreSkillRoulette
{ {
SkillIds = {10002, 10004, 0, 0, 0, 0, 0, 0}, SkillIds = {1001, 1004, 1003, 0, 0, 0, 0, 0},
} }
} }
}); });
} }
[NetEvent(MessageId.VisionExploreSkillSetRequest)] [NetEvent(MessageId.VisionExploreSkillSetRequest)]
public async Task<RpcResult> OnVisionExploreSkillSetRequest(VisionExploreSkillSetRequest request, CreatureController creatureController, EventSystem eventSystem) public async Task<ResponseMessage> OnVisionExploreSkillSetRequest(VisionExploreSkillSetRequest request, CreatureController creatureController, EventSystem eventSystem)
{ {
PlayerEntity? playerEntity = creatureController.GetPlayerEntity(); PlayerEntity? playerEntity = creatureController.GetPlayerEntity();
if (playerEntity == null) return Response(MessageId.VisionExploreSkillSetResponse, new VisionExploreSkillSetResponse { ErrCode = (int)ErrorCode.PlayerNotInAnyScene }); if (playerEntity == null) return Response(MessageId.VisionExploreSkillSetResponse, new VisionExploreSkillSetResponse { ErrCode = (int)ErrorCode.PlayerNotInAnyScene });

View file

@ -1,5 +1,6 @@
using GameServer.Controllers.Attributes; using GameServer.Controllers.Attributes;
using GameServer.Network; using GameServer.Network;
using GameServer.Network.Messages;
using Protocol; using Protocol;
namespace GameServer.Controllers; namespace GameServer.Controllers;
@ -11,5 +12,5 @@ internal class ShopController : Controller
} }
[NetEvent(MessageId.PayShopInfoRequest)] [NetEvent(MessageId.PayShopInfoRequest)]
public RpcResult OnPayShopInfoRequest() => Response(MessageId.PayShopInfoResponse, new PayShopInfoResponse()); public ResponseMessage OnPayShopInfoRequest() => Response(MessageId.PayShopInfoResponse, new PayShopInfoResponse());
} }

View file

@ -1,5 +1,6 @@
using GameServer.Controllers.Attributes; using GameServer.Controllers.Attributes;
using GameServer.Network; using GameServer.Network;
using GameServer.Network.Messages;
using Protocol; using Protocol;
namespace GameServer.Controllers; namespace GameServer.Controllers;
@ -11,8 +12,5 @@ internal class TeleportController : Controller
} }
[NetEvent(MessageId.TeleportFinishRequest)] [NetEvent(MessageId.TeleportFinishRequest)]
public RpcResult OnTeleportFinishRequest() => Response(MessageId.TeleportFinishResponse, new TeleportFinishResponse()); public ResponseMessage OnTeleportFinishRequest() => Response(MessageId.TeleportFinishResponse, new TeleportFinishResponse());
[NetEvent(MessageId.TeleportDataRequest)]
public RpcResult OnTeleportDataRequest() => Response(MessageId.TeleportDataResponse, new TeleportDataResponse());
} }

View file

@ -1,5 +1,6 @@
using GameServer.Controllers.Attributes; using GameServer.Controllers.Attributes;
using GameServer.Network; using GameServer.Network;
using GameServer.Network.Messages;
using Protocol; using Protocol;
namespace GameServer.Controllers; namespace GameServer.Controllers;
@ -11,8 +12,8 @@ internal class TowerController : Controller
} }
[NetEvent(MessageId.TowerChallengeRequest)] [NetEvent(MessageId.TowerChallengeRequest)]
public RpcResult OnTowerChallengeRequest() => Response(MessageId.TowerChallengeResponse, new TowerChallengeResponse()); public ResponseMessage OnTowerChallengeRequest() => Response(MessageId.TowerChallengeResponse, new TowerChallengeResponse());
[NetEvent(MessageId.CycleTowerChallengeRequest)] [NetEvent(MessageId.CycleTowerChallengeRequest)]
public RpcResult OnCycleTowerChallengeRequest() => Response(MessageId.CycleTowerChallengeResponse, new CycleTowerChallengeResponse()); public ResponseMessage OnCycleTowerChallengeRequest() => Response(MessageId.CycleTowerChallengeResponse, new CycleTowerChallengeResponse());
} }

View file

@ -1,5 +1,6 @@
using GameServer.Controllers.Attributes; using GameServer.Controllers.Attributes;
using GameServer.Network; using GameServer.Network;
using GameServer.Network.Messages;
using Protocol; using Protocol;
namespace GameServer.Controllers; namespace GameServer.Controllers;
@ -11,7 +12,7 @@ internal class TutorialController : Controller
} }
[NetEvent(MessageId.TutorialInfoRequest)] [NetEvent(MessageId.TutorialInfoRequest)]
public RpcResult OnTutorialInfoRequest() public ResponseMessage OnTutorialInfoRequest()
{ {
int[] tutorials = [30001, 30002, 30003, 30004, 30005, 30006, 30007, 30011, 30012, 30008, 30009, 30010, 30013, 30014, 30015, 30016, 30017, 30018, 30019, 30020, 30021, 30022, 30023, 30024, 40001, 30025, 30026, 30027, 30028, 30029, 30030, 30031, 30032, 30033, 30034, 30035, 30036, 50001, 50002, 50003, 50004, 50005, 50006, 50007, 50008, 50009, 50010, 50011, 33001, 34017, 34018, 32001, 32002, 32003, 32004, 32005, 32006, 32007, 32008, 32009, 32010, 32011, 32012, 32013, 32014, 32015, 32016, 32017, 32018, 32019, 32020, 32021, 33002, 33003, 33004, 33005, 34001, 34002, 34003, 34004, 34005, 34006, 34007, 34008, 34009, 34010, 34011, 34012, 34013, 34014, 34015, 34016, 34019, 34020, 34021, 34022, 34023, 34024, 34025, 34027, 34028, 34029, 34030, 34031, 34032, 34033]; int[] tutorials = [30001, 30002, 30003, 30004, 30005, 30006, 30007, 30011, 30012, 30008, 30009, 30010, 30013, 30014, 30015, 30016, 30017, 30018, 30019, 30020, 30021, 30022, 30023, 30024, 40001, 30025, 30026, 30027, 30028, 30029, 30030, 30031, 30032, 30033, 30034, 30035, 30036, 50001, 50002, 50003, 50004, 50005, 50006, 50007, 50008, 50009, 50010, 50011, 33001, 34017, 34018, 32001, 32002, 32003, 32004, 32005, 32006, 32007, 32008, 32009, 32010, 32011, 32012, 32013, 32014, 32015, 32016, 32017, 32018, 32019, 32020, 32021, 33002, 33003, 33004, 33005, 34001, 34002, 34003, 34004, 34005, 34006, 34007, 34008, 34009, 34010, 34011, 34012, 34013, 34014, 34015, 34016, 34019, 34020, 34021, 34022, 34023, 34024, 34025, 34027, 34028, 34029, 34030, 34031, 34032, 34033];
TutorialInfoResponse rsp = new(); TutorialInfoResponse rsp = new();
@ -29,7 +30,7 @@ internal class TutorialController : Controller
} }
[NetEvent(MessageId.GetDetectionLabelInfoRequest)] [NetEvent(MessageId.GetDetectionLabelInfoRequest)]
public RpcResult OnGetDetectionLabelInfoRequest() public ResponseMessage OnGetDetectionLabelInfoRequest()
{ {
int[] guides = [0, 1, 2, 3, 14, 15, 16, 4, 21, 22, 7, 5, 18, 6, 61, 8, 9, 10, 11, 12, 13, 17, 19]; int[] guides = [0, 1, 2, 3, 14, 15, 16, 4, 21, 22, 7, 5, 18, 6, 61, 8, 9, 10, 11, 12, 13, 17, 19];
int[] detectionTexts = [1, 2, 3, 4, 5, 6, 7, 0, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 21, 22, 61]; int[] detectionTexts = [1, 2, 3, 4, 5, 6, 7, 0, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 21, 22, 61];
@ -42,7 +43,7 @@ internal class TutorialController : Controller
} }
[NetEvent(MessageId.GuideInfoRequest)] [NetEvent(MessageId.GuideInfoRequest)]
public RpcResult OnGuideInfoRequest() => Response(MessageId.GuideInfoResponse, new GuideInfoResponse() public ResponseMessage OnGuideInfoRequest() => Response(MessageId.GuideInfoResponse, new GuideInfoResponse()
{ {
GuideGroupFinishList = { 60001, 60002, 60003, 60004, 60005, 60006, 60007, 60008, 60009, 60010, 60011, 60012, 60013, 60014, 60015, 60016, 60017, 60018, 60019, 60020, 60021, 60101, 60102, 60103, 62002, 62004, 62005, 62006, 62007, 62009, 62010, 62011, 62012, 62013, 62014, 62015, 62016, 62017, 62022, 62027, 62028, 62029, 62030, 62031, 62032, 62033, 62034, 62036, 65001, 67001, 67002, 67003, 67004, 67005, 67006, 67007, 67008, 67009, 67010, 67011, 67012, 67013, 67014, 67015, 67016, 67017, 67018, 67019, 67022, 62001, 62008, 62018, 62019, 62020, 62021, 62023, 62024, 62025, 62026, 62035, 65002, 65003, 65004, 65005 } GuideGroupFinishList = { 60001, 60002, 60003, 60004, 60005, 60006, 60007, 60008, 60009, 60010, 60011, 60012, 60013, 60014, 60015, 60016, 60017, 60018, 60019, 60020, 60021, 60101, 60102, 60103, 62002, 62004, 62005, 62006, 62007, 62009, 62010, 62011, 62012, 62013, 62014, 62015, 62016, 62017, 62022, 62027, 62028, 62029, 62030, 62031, 62032, 62033, 62034, 62036, 65001, 67001, 67002, 67003, 67004, 67005, 67006, 67007, 67008, 67009, 67010, 67011, 67012, 67013, 67014, 67015, 67016, 67017, 67018, 67019, 67022, 62001, 62008, 62018, 62019, 62020, 62021, 62023, 62024, 62025, 62026, 62035, 65002, 65003, 65004, 65005 }
}); });

View file

@ -1,5 +1,6 @@
using GameServer.Controllers.Attributes; using GameServer.Controllers.Attributes;
using GameServer.Network; using GameServer.Network;
using GameServer.Network.Messages;
using GameServer.Systems.Event; using GameServer.Systems.Event;
using Protocol; using Protocol;
@ -18,14 +19,14 @@ internal class WorldController : Controller
} }
[NetEvent(MessageId.EntityOnLandedRequest)] [NetEvent(MessageId.EntityOnLandedRequest)]
public RpcResult OnEntityOnLandedRequest() => Response(MessageId.EntityOnLandedResponse, new EntityOnLandedResponse()); public ResponseMessage OnEntityOnLandedRequest() => Response(MessageId.EntityOnLandedResponse, new EntityOnLandedResponse());
[NetEvent(MessageId.PlayerMotionRequest)] [NetEvent(MessageId.PlayerMotionRequest)]
public RpcResult OnPlayerMotionRequest() => Response(MessageId.PlayerMotionResponse, new PlayerMotionResponse()); public ResponseMessage OnPlayerMotionRequest() => Response(MessageId.PlayerMotionResponse, new PlayerMotionResponse());
[NetEvent(MessageId.EntityLoadCompleteRequest)] [NetEvent(MessageId.EntityLoadCompleteRequest)]
public RpcResult OnEntityLoadCompleteRequest() => Response(MessageId.EntityLoadCompleteResponse, new EntityLoadCompleteResponse()); public ResponseMessage OnEntityLoadCompleteRequest() => Response(MessageId.EntityLoadCompleteResponse, new EntityLoadCompleteResponse());
[NetEvent(MessageId.UpdateSceneDateRequest)] [NetEvent(MessageId.UpdateSceneDateRequest)]
public RpcResult OnUpdateSceneDateRequest() => Response(MessageId.UpdateSceneDateResponse, new UpdateSceneDateResponse()); public ResponseMessage OnUpdateSceneDateRequest() => Response(MessageId.UpdateSceneDateResponse, new UpdateSceneDateResponse());
} }

View file

@ -1,7 +1,9 @@
using GameServer.Controllers.Attributes; using GameServer.Controllers.Attributes;
using GameServer.Network; using GameServer.Network;
using GameServer.Network.Messages;
using GameServer.Settings; using GameServer.Settings;
using GameServer.Systems.Entity; using GameServer.Systems.Entity;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Protocol; using Protocol;
@ -14,20 +16,14 @@ internal class WorldMapController : Controller
} }
[NetEvent(MessageId.MapTraceInfoRequest)] [NetEvent(MessageId.MapTraceInfoRequest)]
public RpcResult OnMapTraceInfoRequest() => Response(MessageId.MapTraceInfoResponse, new MapTraceInfoResponse() public ResponseMessage OnMapTraceInfoRequest() => Response(MessageId.MapTraceInfoResponse, new MapTraceInfoResponse()
{ {
// Don't. // Don't.
//MarkIdList = { 1, 2, 3, 1000, 1001, 1002, 1003, 1004, 1005, 1007, 1008, 1009, 3000, 3002, 3003, 3005, 3010, 3011, 3012, 4020, 4021, 4022, 4023, 5001, 5002, 5003, 5004, 5005, 5006, 5007, 5021, 5022, 5023, 5025, 5026, 5027, 5028, 5029, 5030, 5031, 380000, 380002, 380003, 380004, 380006, 380007, 380015, 301203, 380013, 380014, 301204, 300201, 300202, 300203, 300301, 300302, 300303, 300304, 300306, 300309, 300310, 300311, 300312, 300313, 300401, 300402, 300403, 300404, 300405, 300406, 300407, 300408, 300410, 300413, 300501, 300502, 300506, 300507, 300508, 300509, 300510, 300511, 300601, 300603, 300604, 300605, 300606, 300607, 300608, 300701, 300703, 300704, 300707, 300708, 300711, 300712, 300713, 300901, 300902, 300911, 300912, 300914, 300915, 300918, 301001, 301003, 301004, 301005, 301006, 301007, 301008, 301009, 301010, 301012, 301013, 301014, 301015, 10000, 10001, 10002, 10003, 10005, 10006, 300801, 301201, 300412, 3015, 3016, 3017, 300411 } //MarkIdList = { 1, 2, 3, 1000, 1001, 1002, 1003, 1004, 1005, 1007, 1008, 1009, 3000, 3002, 3003, 3005, 3010, 3011, 3012, 4020, 4021, 4022, 4023, 5001, 5002, 5003, 5004, 5005, 5006, 5007, 5021, 5022, 5023, 5025, 5026, 5027, 5028, 5029, 5030, 5031, 380000, 380002, 380003, 380004, 380006, 380007, 380015, 301203, 380013, 380014, 301204, 300201, 300202, 300203, 300301, 300302, 300303, 300304, 300306, 300309, 300310, 300311, 300312, 300313, 300401, 300402, 300403, 300404, 300405, 300406, 300407, 300408, 300410, 300413, 300501, 300502, 300506, 300507, 300508, 300509, 300510, 300511, 300601, 300603, 300604, 300605, 300606, 300607, 300608, 300701, 300703, 300704, 300707, 300708, 300711, 300712, 300713, 300901, 300902, 300911, 300912, 300914, 300915, 300918, 301001, 301003, 301004, 301005, 301006, 301007, 301008, 301009, 301010, 301012, 301013, 301014, 301015, 10000, 10001, 10002, 10003, 10005, 10006, 300801, 301201, 300412, 3015, 3016, 3017, 300411 }
}); });
[NetEvent(MessageId.MapUnlockFieldInfoRequest)]
public RpcResult OnMapUnlockFieldInfoRequest() => Response(MessageId.MapUnlockFieldInfoResponse, new MapUnlockFieldInfoResponse
{
FieldId = { Enumerable.Range(1, 12) }
});
[NetEvent(MessageId.MapMarkRequest)] [NetEvent(MessageId.MapMarkRequest)]
public async Task<RpcResult> OnMapMarkRequest(MapMarkRequest request, IOptions<GameplayFeatureSettings> gameplayFeatures, CreatureController creatureController) public async Task<ResponseMessage> OnMapMarkRequest(MapMarkRequest request, IOptions<GameplayFeatureSettings> gameplayFeatures, CreatureController creatureController)
{ {
if (gameplayFeatures.Value.TeleportByMapMark) if (gameplayFeatures.Value.TeleportByMapMark)
{ {

View file

@ -1,13 +0,0 @@
using Protocol;
namespace GameServer.Extensions.Logic;
internal static class MathExtensions
{
public static float GetDistance(this Vector self, Vector other)
{
float x = self.X - other.X;
float y = self.Y - other.Y;
return (float)Math.Sqrt(x * x + y * y);
}
}

View file

@ -1,39 +0,0 @@
using Core.Config;
using Protocol;
namespace GameServer.Extensions.Logic;
internal static class RoleInfoExtensions
{
public static IEnumerable<GameplayAttributeData> GetAttributeList(this roleInfo role)
{
return role.BaseProp.Select(prop => new GameplayAttributeData
{
AttributeType = prop.Key,
BaseValue = prop.Value,
CurrentValue = prop.Value + ((role.AddProp.SingleOrDefault(p => p.Key == prop.Key)?.Value) ?? 0),
});
}
public static void ApplyWeaponProperties(this roleInfo role, WeaponConfig weaponConf)
{
role.AddProp.Clear();
if (weaponConf.FirstPropId != null)
{
role.AddProp.Add(new ArrayIntInt
{
Key = weaponConf.FirstPropId.Id,
Value = (int)weaponConf.FirstPropId.Value
});
}
if (weaponConf.SecondPropId != null)
{
role.AddProp.Add(new ArrayIntInt
{
Key = weaponConf.SecondPropId.Id,
Value = (int)weaponConf.SecondPropId.Value
});
}
}
}

View file

@ -1,4 +1,5 @@
using Protocol; using Google.Protobuf;
using Protocol;
namespace GameServer.Models.Chat; namespace GameServer.Models.Chat;
internal class ChatRoom internal class ChatRoom

View file

@ -10,7 +10,7 @@ internal class FormationModel
public void Set(int[] roleIds) public void Set(int[] roleIds)
{ {
for (int i = 0; i < roleIds.Length; i++) for (int i = 0; i < RoleIds.Length; i++)
{ {
RoleIds[i] = roleIds[i]; RoleIds[i] = roleIds[i];
} }

View file

@ -1,55 +0,0 @@
using Protocol;
namespace GameServer.Models;
internal class InventoryModel
{
private int _itemIncrId;
public List<NormalItem> ItemList { get; } = [];
public List<WeaponItem> WeaponList { get; } = [];
public WeaponItem? GetEquippedWeapon(int roleId) => WeaponList.SingleOrDefault(weapon => weapon.RoleId == roleId);
public WeaponItem? GetWeaponById(int incrId) => WeaponList.SingleOrDefault(weapon => weapon.IncrId == incrId);
public int GetItemCount(int itemId) => ItemList.SingleOrDefault(item => item.Id == itemId)?.Count ?? 0;
public bool TryUseItem(int itemId, int amount)
{
int currentAmount = GetItemCount(itemId);
if (amount > currentAmount) return false;
AddItem(itemId, -amount);
return true;
}
public void AddItem(int itemId, int amount)
{
NormalItem? item = ItemList.SingleOrDefault(item => item.Id == itemId);
if (item != null)
{
item.Count += amount;
return;
}
ItemList.Add(new NormalItem
{
Id = itemId,
Count = amount
});
}
public WeaponItem AddNewWeapon(int weaponId)
{
WeaponItem weapon = new()
{
Id = weaponId,
IncrId = ++_itemIncrId,
WeaponLevel = 1,
WeaponResonLevel = 1
};
WeaponList.Add(weapon);
return weapon;
}
}

View file

@ -1,5 +1,4 @@
using Core.Config; using GameServer.Controllers.Attributes;
using GameServer.Controllers.Attributes;
using GameServer.Settings; using GameServer.Settings;
using GameServer.Systems.Event; using GameServer.Systems.Event;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
@ -8,15 +7,13 @@ namespace GameServer.Models;
internal class ModelManager internal class ModelManager
{ {
private readonly IOptions<PlayerStartingValues> _playerStartingValues; private readonly IOptions<PlayerStartingValues> _playerStartingValues;
private readonly ConfigManager _configManager;
private PlayerModel? _playerModel; private PlayerModel? _playerModel;
private CreatureModel? _creatureModel; private CreatureModel? _creatureModel;
public ModelManager(IOptions<PlayerStartingValues> playerStartingValues, ConfigManager configManager) public ModelManager(IOptions<PlayerStartingValues> playerStartingValues)
{ {
_playerStartingValues = playerStartingValues; _playerStartingValues = playerStartingValues;
_configManager = configManager;
} }
[GameEvent(GameEventType.Login)] [GameEvent(GameEventType.Login)]
@ -32,8 +29,6 @@ internal class ModelManager
public CreatureModel Creature => _creatureModel ?? throw new InvalidOperationException($"Trying to access {nameof(CreatureModel)} instance before initialization!"); public CreatureModel Creature => _creatureModel ?? throw new InvalidOperationException($"Trying to access {nameof(CreatureModel)} instance before initialization!");
public RoleModel Roles { get; } = new();
public FormationModel Formation { get; } = new(); public FormationModel Formation { get; } = new();
public InventoryModel Inventory { get; } = new();
public ChatModel Chat { get; } = new(); public ChatModel Chat { get; } = new();
} }

View file

@ -1,103 +1,25 @@
using GameServer.Settings; using GameServer.Settings;
using Protocol;
namespace GameServer.Models; namespace GameServer.Models;
internal class PlayerModel internal class PlayerModel
{ {
private const int MaxPlayerLevel = 80;
public List<PlayerAttr> Attributes { get; } = [];
public int Id { get; private set; } public int Id { get; private set; }
public int BirthDay { get; set; } public string Name { get; private set; }
public int[] Characters { get; private set; } public int[] Characters { get; private set; }
public Vector Position { get; private set; }
public string Name => GetStringAttribute(PlayerAttrKey.Name);
public PlayerModel() public PlayerModel()
{ {
Name = string.Empty;
Characters = []; Characters = [];
Position = new Vector();
}
public void SetAttribute(PlayerAttrKey key, int value)
{
SetAttribute(key, PlayerAttrType.Int32, value, null);
}
public void SetAttribute(PlayerAttrKey key, string value)
{
SetAttribute(key, PlayerAttrType.String, 0, value);
}
public int GetIntAttribute(PlayerAttrKey key)
{
return GetAttributeOfType(key, PlayerAttrType.Int32)?.Int32Value ?? 0;
}
public string GetStringAttribute(PlayerAttrKey key)
{
return GetAttributeOfType(key, PlayerAttrType.String)?.StringValue ?? string.Empty;
}
private void SetAttribute(PlayerAttrKey key, PlayerAttrType type, int intValue, string? stringValue)
{
PlayerAttr? attr = GetAttributeOfType(key, type);
if (attr == null)
{
attr = new PlayerAttr
{
Key = (int)key,
ValueType = (int)type,
};
Attributes.Add(attr);
}
switch (type)
{
case PlayerAttrType.Int32:
attr.Int32Value = intValue; break;
case PlayerAttrType.String:
attr.StringValue = stringValue; break;
}
}
private PlayerAttr? GetAttributeOfType(PlayerAttrKey key, PlayerAttrType type)
{
PlayerAttr? attr = Attributes.SingleOrDefault(attr => attr.Key == (int)key);
if (attr != null)
{
if (attr.ValueType != (int)type)
throw new ArgumentException($"PlayerAttr type mismatch! Key: {key}, type: {(PlayerAttrType)attr.ValueType}, argument type: {type}");
}
return attr;
}
public void LevelUp()
{
int level = GetIntAttribute(PlayerAttrKey.Level);
if (level == MaxPlayerLevel) return;
SetAttribute(PlayerAttrKey.Level, level + 1);
} }
public static PlayerModel CreateDefaultPlayer(PlayerStartingValues startingValues) public static PlayerModel CreateDefaultPlayer(PlayerStartingValues startingValues)
{ {
PlayerModel playerModel = new() return new PlayerModel
{ {
Id = 1337, Id = 1337,
Characters = startingValues.Characters, Name = startingValues.Name,
Position = startingValues.Position.Clone() Characters = startingValues.Characters
}; };
playerModel.SetAttribute(PlayerAttrKey.Name, startingValues.Name);
playerModel.SetAttribute(PlayerAttrKey.Level, startingValues.PlayerLevel);
playerModel.SetAttribute(PlayerAttrKey.HeadPhoto, startingValues.HeadPhoto);
playerModel.SetAttribute(PlayerAttrKey.HeadFrame, startingValues.HeadFrame);
return playerModel;
} }
} }

View file

@ -1,24 +0,0 @@
using Protocol;
namespace GameServer.Models;
internal class RoleModel
{
public List<roleInfo> Roles { get; } = [];
public roleInfo Create(int id)
{
roleInfo info = new()
{
RoleId = id,
Level = 1,
};
Roles.Add(info);
return info;
}
public roleInfo? GetRoleById(int roleId)
{
return Roles.SingleOrDefault(role => role.RoleId == roleId);
}
}

View file

@ -8,7 +8,6 @@ internal class KcpConnection : IConnection
{ {
private readonly byte[] _recvBuffer; private readonly byte[] _recvBuffer;
private readonly KcpConversation _conv; private readonly KcpConversation _conv;
private readonly ManualResetEvent _sendEvent;
private uint _upStreamSeqNo; private uint _upStreamSeqNo;
private uint _downStreamSeqNo; private uint _downStreamSeqNo;
@ -16,7 +15,6 @@ internal class KcpConnection : IConnection
{ {
_conv = conv; _conv = conv;
_recvBuffer = GC.AllocateUninitializedArray<byte>(8192); _recvBuffer = GC.AllocateUninitializedArray<byte>(8192);
_sendEvent = new ManualResetEvent(true);
} }
public bool Active => !_conv.TransportClosed; public bool Active => !_conv.TransportClosed;
@ -53,16 +51,7 @@ internal class KcpConnection : IConnection
MessageManager.EncodeMessage(memory[BaseMessage.LengthFieldSize..], message); MessageManager.EncodeMessage(memory[BaseMessage.LengthFieldSize..], message);
if (_conv == null) throw new InvalidOperationException("Trying to send message when conv is null"); if (_conv == null) throw new InvalidOperationException("Trying to send message when conv is null");
if (!_sendEvent.WaitOne(0))
{
await Task.Yield();
_ = _sendEvent.WaitOne();
}
_sendEvent.Reset();
await _conv.SendAsync(memoryOwner.Memory[..networkSize]); await _conv.SendAsync(memoryOwner.Memory[..networkSize]);
_sendEvent.Set();
} }
private uint NextUpStreamSeqNo() private uint NextUpStreamSeqNo()

View file

@ -4,7 +4,7 @@ using Protocol;
namespace GameServer.Network.Messages; namespace GameServer.Network.Messages;
internal delegate Task PushHandler(IServiceProvider serviceProvider, ReadOnlySpan<byte> data); internal delegate Task PushHandler(IServiceProvider serviceProvider, ReadOnlySpan<byte> data);
internal delegate Task<RpcResult> RpcHandler(IServiceProvider serviceProvider, ReadOnlySpan<byte> data); internal delegate Task<ResponseMessage> RpcHandler(IServiceProvider serviceProvider, ReadOnlySpan<byte> data);
internal class MessageManager internal class MessageManager
{ {
private readonly EventHandlerFactory _handlerFactory; private readonly EventHandlerFactory _handlerFactory;
@ -16,7 +16,7 @@ internal class MessageManager
_serviceProvider = serviceProvider; _serviceProvider = serviceProvider;
} }
public async Task<RpcResult?> ExecuteRpc(MessageId messageId, ReadOnlyMemory<byte> data) public async Task<ResponseMessage?> ExecuteRpc(MessageId messageId, ReadOnlyMemory<byte> data)
{ {
RpcHandler? handler = _handlerFactory.GetRpcHandler(messageId); RpcHandler? handler = _handlerFactory.GetRpcHandler(messageId);
if (handler != null) if (handler != null)

View file

@ -1,5 +1,4 @@
using GameServer.Network.Messages; using GameServer.Network.Messages;
using GameServer.Systems.Event;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
namespace GameServer.Network.Rpc; namespace GameServer.Network.Rpc;
@ -8,33 +7,26 @@ internal class RpcManager
private readonly IRpcEndPoint _endPoint; private readonly IRpcEndPoint _endPoint;
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly MessageManager _messageManager; private readonly MessageManager _messageManager;
private readonly EventSystem _eventSystem;
public RpcManager(MessageManager messageManager, IRpcEndPoint endPoint, ILogger<RpcManager> logger, EventSystem eventSystem) public RpcManager(MessageManager messageManager, IRpcEndPoint endPoint, ILogger<RpcManager> logger)
{ {
_endPoint = endPoint; _endPoint = endPoint;
_logger = logger; _logger = logger;
_messageManager = messageManager; _messageManager = messageManager;
_eventSystem = eventSystem;
} }
public async Task Execute(RequestMessage request) public async Task Execute(RequestMessage request)
{ {
RpcResult? result = await _messageManager.ExecuteRpc(request.MessageId, request.Payload); ResponseMessage? response = await _messageManager.ExecuteRpc(request.MessageId, request.Payload);
if (result == null) if (response == null)
{ {
_logger.LogWarning("Rpc was not handled properly (message: {msg_id}, id: {rpc_id})", request.MessageId, request.RpcID); _logger.LogWarning("Rpc was not handled properly (message: {msg_id}, id: {rpc_id})", request.MessageId, request.RpcID);
return; return;
} }
result.Response.RpcID = request.RpcID; response.RpcID = request.RpcID;
await _endPoint.SendRpcResult(result.Response); await _endPoint.SendRpcResult(response);
foreach (GameEventType postEvent in result.PostEvents) _logger.LogInformation("Rpc with id {rpc_id} was handled, return message: {msg_id}", request.RpcID, response.MessageId);
{
await _eventSystem.Emit(postEvent);
}
_logger.LogInformation("Rpc with id {rpc_id} was handled, return message: {msg_id}", request.RpcID, result.Response.MessageId);
} }
} }

View file

@ -1,7 +1,6 @@
using Core.Config; using Core.Config;
using Core.Extensions; using Core.Extensions;
using GameServer.Controllers.ChatCommands; using GameServer.Controllers.ChatCommands;
using GameServer.Controllers.Combat;
using GameServer.Controllers.Factory; using GameServer.Controllers.Factory;
using GameServer.Controllers.Manager; using GameServer.Controllers.Manager;
using GameServer.Extensions; using GameServer.Extensions;
@ -13,7 +12,6 @@ using GameServer.Network.Rpc;
using GameServer.Settings; using GameServer.Settings;
using GameServer.Systems.Entity; using GameServer.Systems.Entity;
using GameServer.Systems.Event; using GameServer.Systems.Event;
using GameServer.Systems.Notify;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
@ -26,7 +24,7 @@ internal static class Program
private static async Task Main(string[] args) private static async Task Main(string[] args)
{ {
Console.Title = "Wuthering Waves | Game Server"; Console.Title = "Wuthering Waves | Game Server";
Console.WriteLine(" __ __ __ .__ .__ __ __ \r\n/ \\ / \\__ ___/ |_| |__ ___________|__| ____ ____ / \\ / \\_____ ___ __ ____ ______\r\n\\ \\/\\/ / | \\ __\\ | \\_/ __ \\_ __ \\ |/ \\ / ___\\ \\ \\/\\/ /\\__ \\\\ \\/ // __ \\ / ___/\r\n \\ /| | /| | | Y \\ ___/| | \\/ | | \\/ /_/ > \\ / / __ \\\\ /\\ ___/ \\___ \\ \r\n \\__/\\ / |____/ |__| |___| /\\___ >__| |__|___| /\\___ / \\__/\\ / (____ /\\_/ \\___ >____ >\r\n \\/ \\/ \\/ \\//_____/ \\/ \\/ \\/ \\/ \r\n\r\n\t\t\t\t\t\t\t\t\t\t\t\tGame Server\n"); Console.WriteLine(" __ __ __ .__ .__ __ __ \r\n/ \\ / \\__ ___/ |_| |__ ___________|__| ____ ____ / \\ / \\_____ ___ __ ____ ______\r\n\\ \\/\\/ / | \\ __\\ | \\_/ __ \\_ __ \\ |/ \\ / ___\\ \\ \\/\\/ /\\__ \\\\ \\/ // __ \\ / ___/\r\n \\ /| | /| | | Y \\ ___/| | \\/ | | \\/ /_/ > \\ / / __ \\\\ /\\ ___/ \\___ \\ \r\n \\__/\\ / |____/ |__| |___| /\\___ >__| |__|___| /\\___ / \\__/\\ / (____ /\\_/ \\___ >____ >\r\n \\/ \\/ \\/ \\//_____/ \\/ \\/ \\/ \\/ \n");
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args); HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Logging.AddConsole(); builder.Logging.AddConsole();
@ -40,10 +38,8 @@ internal static class Program
.AddScoped<MessageManager>().AddSingleton<EventHandlerFactory>() .AddScoped<MessageManager>().AddSingleton<EventHandlerFactory>()
.AddScoped<RpcManager>().AddScoped<IRpcEndPoint, RpcSessionEndPoint>() .AddScoped<RpcManager>().AddScoped<IRpcEndPoint, RpcSessionEndPoint>()
.AddSingleton<SessionManager>() .AddSingleton<SessionManager>()
.AddScoped<EventSystem>().AddScoped<EntitySystem>().AddScoped<IGameActionListener, NotifySystem>() .AddScoped<EventSystem>().AddScoped<EntitySystem>().AddScoped<EntityFactory>()
.AddScoped<EntityFactory>() .AddScoped<ModelManager>().AddScoped<ControllerManager>().AddScoped<ChatCommandManager>()
.AddScoped<ModelManager>().AddScoped<ControllerManager>()
.AddScoped<CombatManager>().AddScoped<ChatCommandManager>()
.AddHostedService<WWGameServer>(); .AddHostedService<WWGameServer>();
IHost host = builder.Build(); IHost host = builder.Build();

View file

@ -2,5 +2,4 @@
internal class GameplayFeatureSettings internal class GameplayFeatureSettings
{ {
public bool TeleportByMapMark { get; set; } public bool TeleportByMapMark { get; set; }
public bool UnlimitedEnergy { get; set; }
} }

View file

@ -1,12 +1,6 @@
using Protocol; namespace GameServer.Settings;
namespace GameServer.Settings;
internal class PlayerStartingValues internal class PlayerStartingValues
{ {
public required string Name { get; set; } public required string Name { get; set; }
public required int PlayerLevel { get; set; }
public required int HeadPhoto { get; set; }
public required int HeadFrame { get; set; }
public required int[] Characters { get; set; } public required int[] Characters { get; set; }
public required Vector Position { get; set; }
} }

View file

@ -12,14 +12,6 @@ internal class EntityAttributeComponent : EntityComponentBase
_gameplayAttributes = []; _gameplayAttributes = [];
} }
public void SetAll(IEnumerable<GameplayAttributeData> attributes)
{
foreach (GameplayAttributeData attr in attributes)
{
SetAttribute((EAttributeType)attr.AttributeType, attr.CurrentValue, attr.BaseValue);
}
}
public void SetAttribute(EAttributeType type, int currentValue, int baseValue) public void SetAttribute(EAttributeType type, int currentValue, int baseValue)
{ {
if (!_gameplayAttributes.TryGetValue(type, out GameplayAttributeData? attribute)) if (!_gameplayAttributes.TryGetValue(type, out GameplayAttributeData? attribute))
@ -45,7 +37,6 @@ internal class EntityAttributeComponent : EntityComponentBase
} }
attribute.CurrentValue = currentValue; attribute.CurrentValue = currentValue;
attribute.BaseValue = currentValue;
} }
public int GetAttribute(EAttributeType type) public int GetAttribute(EAttributeType type)

View file

@ -1,5 +1,4 @@
using System.Diagnostics.CodeAnalysis; using Protocol;
using Protocol;
namespace GameServer.Systems.Entity.Component; namespace GameServer.Systems.Entity.Component;
internal class EntityComponentSystem internal class EntityComponentSystem
@ -26,7 +25,7 @@ internal class EntityComponentSystem
return (_components.Single(component => component is TEntityComponent) as TEntityComponent)!; return (_components.Single(component => component is TEntityComponent) as TEntityComponent)!;
} }
public bool TryGet<TEntityComponent>([NotNullWhen(true)] out TEntityComponent? component) where TEntityComponent : EntityComponentBase public bool TryGet<TEntityComponent>(out TEntityComponent? component) where TEntityComponent : EntityComponentBase
{ {
return (component = _components.SingleOrDefault(component => component is TEntityComponent) as TEntityComponent) != null; return (component = _components.SingleOrDefault(component => component is TEntityComponent) as TEntityComponent) != null;
} }

View file

@ -4,8 +4,6 @@ namespace GameServer.Systems.Entity.Component;
internal class EntityConcomitantsComponent : EntityComponentBase internal class EntityConcomitantsComponent : EntityComponentBase
{ {
public List<long> CustomEntityIds { get; } public List<long> CustomEntityIds { get; }
public long PhantomRoleEntityId { get; set; }
public long VisionEntityId { get; set; }
public EntityConcomitantsComponent() public EntityConcomitantsComponent()
{ {
@ -21,10 +19,6 @@ internal class EntityConcomitantsComponent : EntityComponentBase
EntityComponentPb pb = new() EntityComponentPb pb = new()
{ {
ConcomitantsComponentPb = new() ConcomitantsComponentPb = new()
{
PhantomRoleEid = PhantomRoleEntityId,
VisionEntityId = VisionEntityId
}
}; };
pb.ConcomitantsComponentPb.CustomEntityIds.AddRange(CustomEntityIds); pb.ConcomitantsComponentPb.CustomEntityIds.AddRange(CustomEntityIds);

View file

@ -1,20 +0,0 @@
using Protocol;
namespace GameServer.Systems.Entity.Component;
internal class EntityFightBuffComponent : EntityComponentBase
{
public List<FightBuffInformation> BuffInfoList { get; } = [];
public override EntityComponentType Type => EntityComponentType.FightBuff;
public override EntityComponentPb Pb => new()
{
FightBuffComponent = new()
{
FightBuffInfos =
{
BuffInfoList
}
}
};
}

View file

@ -4,7 +4,6 @@ namespace GameServer.Systems.Entity.Component;
internal class EntityFsmComponent : EntityComponentBase internal class EntityFsmComponent : EntityComponentBase
{ {
public List<DFsm> Fsms { get; } = []; public List<DFsm> Fsms { get; } = [];
public int CommonHashCode { get; set; }
public override EntityComponentType Type => EntityComponentType.EntityFsm; public override EntityComponentType Type => EntityComponentType.EntityFsm;
@ -15,8 +14,7 @@ internal class EntityFsmComponent : EntityComponentBase
Fsms = Fsms =
{ {
Fsms Fsms
}, }
CommonHashCode = CommonHashCode
}, },
}; };
} }

View file

@ -1,22 +0,0 @@
using Protocol;
namespace GameServer.Systems.Entity.Component;
internal class EntityLogicStateComponent : EntityComponentBase
{
public List<int> States { get; set; }
public EntityLogicStateComponent()
{
States = [];
}
public override EntityComponentType Type => EntityComponentType.LogicState;
public override EntityComponentPb Pb => new()
{
LogicStateComponentPb = new()
{
States = { States }
}
};
}

View file

@ -1,25 +0,0 @@
using Protocol;
namespace GameServer.Systems.Entity.Component;
internal class EntitySummonerComponent : EntityComponentBase
{
public int SummonConfigId { get; set; }
public ESummonType SummonType { get; set; }
public long SummonerId { get; set; }
public int PlayerId { get; set; }
public int SummonSkillId { get; set; }
public override EntityComponentType Type => EntityComponentType.Summoner;
public override EntityComponentPb Pb => new()
{
SummonerComponent = new()
{
SummonCfgId = SummonConfigId,
Type = (int)SummonType,
SummonerId = SummonerId,
PlayerId = PlayerId,
SummonSkillId = SummonSkillId,
}
};
}

View file

@ -1,6 +1,5 @@
using Core.Config; using Core.Config;
using GameServer.Systems.Entity.Component; using GameServer.Systems.Entity.Component;
using GameServer.Systems.Notify;
using Protocol; using Protocol;
namespace GameServer.Systems.Entity; namespace GameServer.Systems.Entity;
@ -13,15 +12,10 @@ internal abstract class EntityBase
public Rotator Rot { get; set; } public Rotator Rot { get; set; }
public bool Active { get; set; } public bool Active { get; set; }
public int DynamicId { get; protected set; }
public EntityState State { get; protected set; } public EntityState State { get; protected set; }
public bool IsConcomitant => ComponentSystem.TryGet<EntitySummonerComponent>(out _); public EntityBase(long id)
protected IGameActionListener ActionListener { get; }
public EntityBase(long id, IGameActionListener listener)
{ {
Id = id; Id = id;
@ -29,15 +23,11 @@ internal abstract class EntityBase
Rot = new Rotator(); Rot = new Rotator();
ComponentSystem = new EntityComponentSystem(); ComponentSystem = new EntityComponentSystem();
ActionListener = listener;
} }
public virtual void OnCreate() public virtual void OnCreate()
{ {
State = EntityState.Born; State = EntityState.Born;
_ = ComponentSystem.Create<EntityLogicStateComponent>();
_ = ComponentSystem.Create<EntityFightBuffComponent>();
} }
public virtual void Activate() public virtual void Activate()
@ -45,24 +35,6 @@ internal abstract class EntityBase
// Activate. // Activate.
} }
public void ChangeEquipment(int weaponId)
{
if (ComponentSystem.TryGet(out EntityEquipComponent? equipComponent))
{
equipComponent.WeaponId = weaponId;
_ = ActionListener.OnEntityEquipmentChanged(Id, equipComponent.Pb.EquipComponent);
}
}
public void ChangeGameplayAttributes(IEnumerable<GameplayAttributeData> attributes)
{
if (ComponentSystem.TryGet(out EntityAttributeComponent? attrComponent))
{
attrComponent.SetAll(attributes);
_ = ActionListener.OnEntityAttributesChanged(Id, attrComponent.Pb.AttributeComponent.GameAttributes);
}
}
public virtual LivingStatus LivingStatus => LivingStatus.Alive; public virtual LivingStatus LivingStatus => LivingStatus.Alive;
public virtual bool IsVisible => true; public virtual bool IsVisible => true;

View file

@ -1,40 +1,12 @@
using Microsoft.Extensions.DependencyInjection; namespace GameServer.Systems.Entity;
namespace GameServer.Systems.Entity;
internal class EntityFactory internal class EntityFactory
{ {
private static readonly ObjectFactory<PlayerEntity> s_createPlayerEntity;
private static readonly ObjectFactory<MonsterEntity> s_createMonsterEntity;
private long _entityIdCounter; private long _entityIdCounter;
private readonly IServiceProvider _serviceProvider;
static EntityFactory()
{
s_createPlayerEntity = ActivatorUtilities.CreateFactory<PlayerEntity>([typeof(long), typeof(int), typeof(int)]);
s_createMonsterEntity = ActivatorUtilities.CreateFactory<MonsterEntity>([typeof(long), typeof(int)]);
}
public EntityFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public PlayerEntity CreatePlayer(int characterConfigId, int playerId) public PlayerEntity CreatePlayer(int characterConfigId, int playerId)
{ => new(NextId(), characterConfigId, playerId);
PlayerEntity entity = s_createPlayerEntity(_serviceProvider, [NextId(), characterConfigId, playerId]);
entity.OnCreate();
return entity; public MonsterEntity CreateMonster(int levelEntityId) => new(NextId(), levelEntityId);
}
public MonsterEntity CreateMonster(int levelEntityId)
{
MonsterEntity monsterEntity = s_createMonsterEntity(_serviceProvider, [NextId(), levelEntityId]);
monsterEntity.OnCreate();
return monsterEntity;
}
private long NextId() => Interlocked.Increment(ref _entityIdCounter); private long NextId() => Interlocked.Increment(ref _entityIdCounter);
} }

View file

@ -1,19 +1,13 @@
using GameServer.Systems.Notify; using Protocol;
using Protocol;
namespace GameServer.Systems.Entity; namespace GameServer.Systems.Entity;
internal class EntitySystem internal class EntitySystem
{ {
private readonly List<EntityBase> _entities; private readonly List<EntityBase> _entities;
private readonly List<int> _dynamicEntityIds;
private readonly IGameActionListener _listener; public EntitySystem()
public EntitySystem(IGameActionListener listener)
{ {
_entities = []; _entities = [];
_dynamicEntityIds = [];
_listener = listener;
} }
public IEnumerable<EntityBase> EnumerateEntities() public IEnumerable<EntityBase> EnumerateEntities()
@ -21,36 +15,18 @@ internal class EntitySystem
return _entities; return _entities;
} }
public void Add(IEnumerable<EntityBase> entities) public void Create(EntityBase entity)
{
foreach (EntityBase entity in entities)
{ {
if (_entities.Any(e => e.Id == entity.Id)) if (_entities.Any(e => e.Id == entity.Id))
throw new InvalidOperationException($"EntitySystem::Create - entity with id {entity.Id} already exists"); throw new InvalidOperationException($"EntitySystem::Create - entity with id {entity.Id} already exists");
entity.OnCreate();
_entities.Add(entity); _entities.Add(entity);
if (entity.DynamicId != 0)
_dynamicEntityIds.Add(entity.DynamicId);
} }
_ = _listener.OnEntitiesAdded(entities); public void Destroy(EntityBase entity)
}
public bool HasDynamicEntity(int dynamicId)
{
return _dynamicEntityIds.Contains(dynamicId);
}
public void Destroy(IEnumerable<EntityBase> entities)
{
foreach (EntityBase entity in entities)
{ {
_ = _entities.Remove(entity); _ = _entities.Remove(entity);
_ = _dynamicEntityIds.Remove(entity.DynamicId);
}
_ = _listener.OnEntitiesRemoved(entities);
} }
public void Activate(EntityBase entity) public void Activate(EntityBase entity)

View file

@ -1,14 +1,12 @@
using GameServer.Systems.Entity.Component; using GameServer.Systems.Entity.Component;
using GameServer.Systems.Notify;
using Protocol; using Protocol;
namespace GameServer.Systems.Entity; namespace GameServer.Systems.Entity;
internal class MonsterEntity : EntityBase internal class MonsterEntity : EntityBase
{ {
public MonsterEntity(long id, int configId, IGameActionListener listener) : base(id, listener) public MonsterEntity(long id, int configId) : base(id)
{ {
ConfigId = configId; ConfigId = configId;
DynamicId = configId;
} }
public int ConfigId { get; } public int ConfigId { get; }
@ -34,20 +32,17 @@ internal class MonsterEntity : EntityBase
fsm.Fsms.Add(new DFsm fsm.Fsms.Add(new DFsm
{ {
FsmId = 10007, // Main State Machine FsmId = 10007, // Main State Machine
CurrentState = 10013 // Battle Branching CurrentState = 10013, // Battle Branching
Status = 1, // ??
Flag = (int)EFsmStateFlag.Confirmed
}); });
fsm.Fsms.Add(new DFsm fsm.Fsms.Add(new DFsm
{ {
FsmId = 10007, // Main State Machine FsmId = 10007, // Main State Machine
CurrentState = 10015 // Moving Combat CurrentState = 10015, // Moving Combat
}); Status = 1, // ??
Flag = (int)EFsmStateFlag.Confirmed
// Some monsters need weapon
fsm.Fsms.Add(new DFsm
{
FsmId = 100,
CurrentState = 9 // [9 - Empty hand, 10 - Crowbar, 11 - flamethrower, 12 - chainsaw, 13 - electric blade, 14 - sniper rifle]
}); });
} }

View file

@ -1,11 +1,10 @@
using GameServer.Systems.Entity.Component; using GameServer.Systems.Entity.Component;
using GameServer.Systems.Notify;
using Protocol; using Protocol;
namespace GameServer.Systems.Entity; namespace GameServer.Systems.Entity;
internal class PlayerEntity : EntityBase internal class PlayerEntity : EntityBase
{ {
public PlayerEntity(long id, int configId, int playerId, IGameActionListener listener) : base(id, listener) public PlayerEntity(long id, int configId, int playerId) : base(id)
{ {
ConfigId = configId; ConfigId = configId;
PlayerId = playerId; PlayerId = playerId;
@ -38,37 +37,15 @@ internal class PlayerEntity : EntityBase
{ {
base.OnCreate(); base.OnCreate();
// Should be created immediately
EntityConcomitantsComponent concomitantsComponent = ComponentSystem.Create<EntityConcomitantsComponent>();
concomitantsComponent.CustomEntityIds.Add(Id);
EntityVisionSkillComponent visionSkillComponent = ComponentSystem.Create<EntityVisionSkillComponent>(); EntityVisionSkillComponent visionSkillComponent = ComponentSystem.Create<EntityVisionSkillComponent>();
visionSkillComponent.SetExploreTool(1001); visionSkillComponent.SetExploreTool(1001);
_ = ComponentSystem.Create<EntityEquipComponent>(); _ = ComponentSystem.Create<EntityEquipComponent>();
_ = ComponentSystem.Create<EntityAttributeComponent>(); _ = ComponentSystem.Create<EntityAttributeComponent>();
// TODO: temporary solution to enable glider and wall run, should implement proper buff management.
EntityFightBuffComponent fightBuffComponent = ComponentSystem.Get<EntityFightBuffComponent>();
fightBuffComponent.BuffInfoList.Add(new FightBuffInformation
{
BuffId = 3004,
EntityId = Id,
InstigatorId = Id,
IsActive = true,
Duration = -1,
LeftDuration = -1,
Level = 1,
StackCount = 1
});
fightBuffComponent.BuffInfoList.Add(new FightBuffInformation
{
BuffId = 3003,
EntityId = Id,
InstigatorId = Id,
IsActive = true,
Duration = -1,
LeftDuration = -1,
Level = 1,
StackCount = 1
});
} }
public override void Activate() public override void Activate()
@ -79,7 +56,7 @@ internal class PlayerEntity : EntityBase
public override EEntityType Type => EEntityType.Player; public override EEntityType Type => EEntityType.Player;
public override EntityConfigType ConfigType => EntityConfigType.Character; public override EntityConfigType ConfigType => EntityConfigType.Character;
public override bool IsVisible => IsCurrentRole || IsConcomitant; public override bool IsVisible => IsCurrentRole;
public override EntityPb Pb public override EntityPb Pb
{ {

View file

@ -3,14 +3,8 @@ internal enum GameEventType
{ {
Login = 1, Login = 1,
EnterGame, EnterGame,
PushDataDone,
// Actions // Actions
PlayerPositionChanged,
FormationUpdated, FormationUpdated,
VisionSkillChanged, VisionSkillChanged
// Debug
DebugUnlockAllRoles,
DebugUnlockAllItems
} }

View file

@ -1,14 +0,0 @@
using GameServer.Systems.Entity;
using Protocol;
namespace GameServer.Systems.Notify;
internal interface IGameActionListener
{
Task OnJoinedScene(SceneInformation sceneInformation, TransitionType transitionType);
Task OnEntitiesAdded(IEnumerable<EntityBase> entities);
Task OnEntitiesRemoved(IEnumerable<EntityBase> entities);
Task OnPlayerFightRoleInfoUpdated(int playerId, IEnumerable<FightRoleInformation> fightRoles);
Task OnRolePropertiesUpdated(int roleId, IEnumerable<ArrayIntInt> baseProp, IEnumerable<ArrayIntInt> addProp);
Task OnEntityEquipmentChanged(long entityId, EquipComponentPb componentPb);
Task OnEntityAttributesChanged(long entityId, IEnumerable<GameplayAttributeData> attributes);
}

View file

@ -1,97 +0,0 @@
using GameServer.Models;
using GameServer.Network;
using GameServer.Systems.Entity;
using Protocol;
namespace GameServer.Systems.Notify;
internal class NotifySystem : IGameActionListener
{
private readonly PlayerSession _session;
private readonly ModelManager _modelManager;
public NotifySystem(PlayerSession session, ModelManager modelManager)
{
_session = session;
_modelManager = modelManager;
}
public Task OnJoinedScene(SceneInformation sceneInformation, TransitionType transitionType)
{
return _session.Push(MessageId.JoinSceneNotify, new JoinSceneNotify
{
SceneInfo = sceneInformation,
TransitionOption = new TransitionOptionPb
{
TransitionType = (int)transitionType
}
});
}
public Task OnEntitiesAdded(IEnumerable<EntityBase> entities)
{
if (_modelManager.Creature.LoadingWorld) return Task.CompletedTask;
return _session.Push(MessageId.EntityAddNotify, new EntityAddNotify
{
IsAdd = true,
EntityPbs = { entities.Select(e => e.Pb) }
});
}
public Task OnEntitiesRemoved(IEnumerable<EntityBase> entities)
{
if (_modelManager.Creature.LoadingWorld) return Task.CompletedTask;
return _session.Push(MessageId.EntityRemoveNotify, new EntityRemoveNotify
{
IsRemove = true,
RemoveInfos =
{
entities.Select(e => new EntityRemoveInfo
{
EntityId = e.Id,
Type = (int)ERemoveEntityType.RemoveTypeNormal
})
}
});
}
public Task OnPlayerFightRoleInfoUpdated(int playerId, IEnumerable<FightRoleInformation> fightRoles)
{
return _session.Push(MessageId.UpdatePlayerAllFightRoleNotify, new UpdatePlayerAllFightRoleNotify
{
PlayerId = playerId,
FightRoleInfos = { fightRoles }
});
}
public Task OnRolePropertiesUpdated(int roleId, IEnumerable<ArrayIntInt> baseProp, IEnumerable<ArrayIntInt> addProp)
{
if (_modelManager.Creature.LoadingWorld) return Task.CompletedTask;
return _session.Push(MessageId.PbRolePropsNotify, new PbRolePropsNotify
{
RoleId = roleId,
BaseProp = { baseProp },
AddProp = { addProp }
});
}
public Task OnEntityEquipmentChanged(long entityId, EquipComponentPb componentPb)
{
return _session.Push(MessageId.EntityEquipChangeNotify, new EntityEquipChangeNotify
{
EntityId = entityId,
EquipComponent = componentPb
});
}
public Task OnEntityAttributesChanged(long entityId, IEnumerable<GameplayAttributeData> attributes)
{
return _session.Push(MessageId.AttributeChangedNotify, new AttributeChangedNotify
{
Id = entityId,
Attributes = { attributes }
});
}
}

View file

@ -1,18 +1,9 @@
{ {
"StartingValues": { "StartingValues": {
"Name": "ReversedRooms", "Name": "ReversedRooms",
"PlayerLevel": 8, "Characters": [ 1601, 1302, 1203 ]
"HeadPhoto": 1402,
"HeadFrame": 80060009,
"Characters": [ 1402, 1302, 1203 ],
"Position": {
"X": -45000,
"Y": 67800,
"Z": 2600
}
}, },
"Features": { "Features": {
"TeleportByMapMark": true, "TeleportByMapMark": true
"UnlimitedEnergy": false
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 199 KiB

After

Width:  |  Height:  |  Size: 205 KiB

View file

@ -795,8 +795,6 @@ public enum MessageId
NewBieCourseRewardResponse = 12153, NewBieCourseRewardResponse = 12153,
NewJourneyRequest = 12214, NewJourneyRequest = 12214,
NewJourneyResponse = 12215, NewJourneyResponse = 12215,
ClientCurrentRoleReportRequest = 12217,
ClientCurrentRoleReportResponse = 12218,
NormalItemAddNotify = 5268, NormalItemAddNotify = 5268,
NormalItemRemoveNotify = 5269, NormalItemRemoveNotify = 5269,
NormalItemRequest = 5265, NormalItemRequest = 5265,

View file

@ -1573,17 +1573,6 @@ message ClientBasicInfoRequest { // MessageId: 5165
message ClientBasicInfoResponse { // MessageId: 3017 message ClientBasicInfoResponse { // MessageId: 3017
} }
message ClientCurrentRoleReportRequest { // MessageId: 12217
int32 player_id = 1;
int32 current_role_id = 2;
int64 current_entity_id = 3;
}
message ClientCurrentRoleReportResponse { // MessageId: 12218
int32 player_id = 1;
int64 current_entity_id = 2;
}
message ClientDataComponentPb { message ClientDataComponentPb {
bool is_static_init = 1; bool is_static_init = 1;
int64 owner_id = 2; int64 owner_id = 2;
@ -1615,7 +1604,6 @@ message CombatMaxCaseMessageResponse { // MessageId: 11987
message CombatNotifyData { message CombatNotifyData {
CombatCommon combat_common = 1; CombatCommon combat_common = 1;
oneof message {
CreateBulletNotify create_bullet_notify = 2; CreateBulletNotify create_bullet_notify = 2;
DestroyBulletNotify destroy_bullet_notify = 3; DestroyBulletNotify destroy_bullet_notify = 3;
DamageExecuteNotify damage_execute_notify = 4; DamageExecuteNotify damage_execute_notify = 4;
@ -1674,11 +1662,9 @@ message CombatNotifyData {
RemoveBuffByIdS2cRequestNotify remove_buff_by_id_s2c_request_notify = 59; RemoveBuffByIdS2cRequestNotify remove_buff_by_id_s2c_request_notify = 59;
FormationBuffRemoveByIdS2cRequestNotify formation_buff_remove_by_id_s2c_request_notify = 60; FormationBuffRemoveByIdS2cRequestNotify formation_buff_remove_by_id_s2c_request_notify = 60;
} }
}
message CombatPushData { message CombatPushData {
CombatCommon combat_common = 1; CombatCommon combat_common = 1;
oneof message {
FormationBuffApplyS2cResponsePush formation_buff_apply_s2c_response_push = 2; FormationBuffApplyS2cResponsePush formation_buff_apply_s2c_response_push = 2;
FormationBuffRemoveS2cResponsePush formation_buff_remove_s2c_response_push = 3; FormationBuffRemoveS2cResponsePush formation_buff_remove_s2c_response_push = 3;
ApplyBuffS2cResponsePush apply_buff_s2c_response_push = 4; ApplyBuffS2cResponsePush apply_buff_s2c_response_push = 4;
@ -1686,14 +1672,11 @@ message CombatPushData {
RemoveBuffByIdS2cResponsePush remove_buff_by_id_s2c_response_push = 6; RemoveBuffByIdS2cResponsePush remove_buff_by_id_s2c_response_push = 6;
FormationBuffRemoveByIdS2cResponsePush formation_buff_remove_by_id_s2c_response_push = 7; FormationBuffRemoveByIdS2cResponsePush formation_buff_remove_by_id_s2c_response_push = 7;
} }
}
message CombatReceiveData { message CombatReceiveData {
oneof message {
CombatNotifyData combat_notify_data = 2; CombatNotifyData combat_notify_data = 2;
CombatResponseData combat_response_data = 3; CombatResponseData combat_response_data = 3;
} }
}
message CombatReceivePackNotify { // MessageId: 1332 message CombatReceivePackNotify { // MessageId: 1332
repeated CombatReceiveData data = 1; repeated CombatReceiveData data = 1;
@ -1702,7 +1685,6 @@ message CombatReceivePackNotify { // MessageId: 1332
message CombatRequestData { message CombatRequestData {
CombatCommon combat_common = 1; CombatCommon combat_common = 1;
int32 request_id = 2; int32 request_id = 2;
oneof message {
CreateBulletRequest create_bullet_request = 3; CreateBulletRequest create_bullet_request = 3;
DestroyBulletRequest destroy_bullet_request = 4; DestroyBulletRequest destroy_bullet_request = 4;
DamageExecuteRequest damage_execute_request = 5; DamageExecuteRequest damage_execute_request = 5;
@ -1763,14 +1745,12 @@ message CombatRequestData {
DrownEndTeleportRequest drown_end_teleport_request = 60; DrownEndTeleportRequest drown_end_teleport_request = 60;
MonsterDrownRequest monster_drown_request = 61; MonsterDrownRequest monster_drown_request = 61;
CombatMaxCaseMessageRequest combat_max_case_message_request = 62; CombatMaxCaseMessageRequest combat_max_case_message_request = 62;
}
CombatContext context = 100; CombatContext context = 100;
} }
message CombatResponseData { message CombatResponseData {
CombatCommon combat_common = 1; CombatCommon combat_common = 1;
int32 request_id = 2; int32 request_id = 2;
oneof message {
CreateBulletResponse create_bullet_response = 3; CreateBulletResponse create_bullet_response = 3;
DestroyBulletResponse destroy_bullet_response = 4; DestroyBulletResponse destroy_bullet_response = 4;
DamageExecuteResponse damage_execute_response = 5; DamageExecuteResponse damage_execute_response = 5;
@ -1831,7 +1811,6 @@ message CombatResponseData {
DrownEndTeleportResponse drown_end_teleport_response = 60; DrownEndTeleportResponse drown_end_teleport_response = 60;
MonsterDrownResponse monster_drown_response = 61; MonsterDrownResponse monster_drown_response = 61;
} }
}
message CombatSendData { message CombatSendData {
CombatPushData push = 2; CombatPushData push = 2;
@ -2644,7 +2623,6 @@ message EntityActiveRequest { // MessageId: 1541
message EntityActiveResponse { // MessageId: 1542 message EntityActiveResponse { // MessageId: 1542
int32 error_code = 1; int32 error_code = 1;
repeated EntityComponentPb component_pbs = 2; repeated EntityComponentPb component_pbs = 2;
bool is_visible = 3;
} }
message EntityAddBubbleNotify { // MessageId: 12203 message EntityAddBubbleNotify { // MessageId: 12203
@ -7912,7 +7890,6 @@ message SeasonData {
int64 end_time = 3; int64 end_time = 3;
repeated RoguelikeToken roguelike_token_list = 4; repeated RoguelikeToken roguelike_token_list = 4;
repeated SeasonReward season_reward_list = 5; repeated SeasonReward season_reward_list = 5;
int32 token_item_count = 6;
} }
message SeasonReward { message SeasonReward {
@ -10944,7 +10921,6 @@ enum ErrorCode {
ERROR_CODE_ERR_ENTITY_PATROL_COMPONENT_NOT_EXIST = 600088; ERROR_CODE_ERR_ENTITY_PATROL_COMPONENT_NOT_EXIST = 600088;
ERROR_CODE_ERR_INTERACT_IS_NOT_PARTICIPANT = 600089; ERROR_CODE_ERR_INTERACT_IS_NOT_PARTICIPANT = 600089;
ERROR_CODE_ERR_VISION_ENTITY_INTERACT_FAIL = 600090; ERROR_CODE_ERR_VISION_ENTITY_INTERACT_FAIL = 600090;
ERROR_CODE_ERR_MAX_DROP_TIMES = 600091;
ERROR_CODE_ERR_SCENE_WORLD_NOT_EXIST = 700000; ERROR_CODE_ERR_SCENE_WORLD_NOT_EXIST = 700000;
ERROR_CODE_ERR_PLAYER_NOT_IN_SCENE = 700001; ERROR_CODE_ERR_PLAYER_NOT_IN_SCENE = 700001;
ERROR_CODE_ERR_DROP_ENTITY_NOT_EXIST = 700002; ERROR_CODE_ERR_DROP_ENTITY_NOT_EXIST = 700002;
@ -11311,7 +11287,6 @@ enum ErrorCode {
ERROR_CODE_ERR_ITEM_POS_INVAILD = 900058; ERROR_CODE_ERR_ITEM_POS_INVAILD = 900058;
ERROR_CODE_ERR_ITEM_ID_INVAILD = 900059; ERROR_CODE_ERR_ITEM_ID_INVAILD = 900059;
ERROR_CODE_ERR_ROULETTE_FUNC_ID_INVAILD = 900060; ERROR_CODE_ERR_ROULETTE_FUNC_ID_INVAILD = 900060;
ERROR_CODE_ERR_STATE_IS_RUNNING = 900061;
ERROR_CODE_ERR_BUFF_ITEM_CONFIG = 1000000; ERROR_CODE_ERR_BUFF_ITEM_CONFIG = 1000000;
ERROR_CODE_ERR_BUFF_ITEM_NOT_SHARE = 1000001; ERROR_CODE_ERR_BUFF_ITEM_NOT_SHARE = 1000001;
ERROR_CODE_ERR_BUFF_ITEM_SHARE_ROLE_ID = 1000002; ERROR_CODE_ERR_BUFF_ITEM_SHARE_ROLE_ID = 1000002;
@ -11770,9 +11745,6 @@ enum ErrorCode {
ERROR_CODE_ERR_EXPLORE_SKILL_PULL_GIANT_NOT_EXIST = 1800027; ERROR_CODE_ERR_EXPLORE_SKILL_PULL_GIANT_NOT_EXIST = 1800027;
ERROR_CODE_ERR_HTTP_RPC_PARAM = 1800028; ERROR_CODE_ERR_HTTP_RPC_PARAM = 1800028;
ERROR_CODE_ERR_PLAYER_NOT_IN_GAME_NODE = 1800029; ERROR_CODE_ERR_PLAYER_NOT_IN_GAME_NODE = 1800029;
ERROR_CODE_ERR_APPLY_JOIN_PLAYER_CUR_ROLE_IS_DEAD = 1800030;
ERROR_CODE_ERR_PLAYER_CUR_ROLE_IS_DEAD_NO_JOIN = 1800031;
ERROR_CODE_ERR_PLAYER_CUR_ROLE_IS_DEAD = 1800032;
ERROR_CODE_ERR_CALABASH_LEVEL_REQUEST = 1900000; ERROR_CODE_ERR_CALABASH_LEVEL_REQUEST = 1900000;
ERROR_CODE_ERR_CALABASH_LEVEL_REWARD_DONE = 1900001; ERROR_CODE_ERR_CALABASH_LEVEL_REWARD_DONE = 1900001;
ERROR_CODE_ERR_CALABASH_LEVEL_CONFIG = 1900002; ERROR_CODE_ERR_CALABASH_LEVEL_CONFIG = 1900002;
@ -11811,7 +11783,6 @@ enum ErrorCode {
ERROR_CODE_ERR_NEW_BIE_COURSE_CONFIG = 1900035; ERROR_CODE_ERR_NEW_BIE_COURSE_CONFIG = 1900035;
ERROR_CODE_ERR_NEW_BIE_COURSE_REWARD_HAD = 1900036; ERROR_CODE_ERR_NEW_BIE_COURSE_REWARD_HAD = 1900036;
ERROR_CODE_ERR_NEW_BIE_COURSE_LEVEL = 1900037; ERROR_CODE_ERR_NEW_BIE_COURSE_LEVEL = 1900037;
ERROR_CODE_ERR_DETECTION_TARGET_SILENCE = 1900038;
ERROR_CODE_ERR_DO_COMMON_REWARD_CONFIG_ERROR = 2000000; ERROR_CODE_ERR_DO_COMMON_REWARD_CONFIG_ERROR = 2000000;
ERROR_CODE_INST_PLAY_NOT_SETTLE = 2000001; ERROR_CODE_INST_PLAY_NOT_SETTLE = 2000001;
ERROR_CODE_INST_PLAY_NOT_FINISH_EXECUTE = 2000002; ERROR_CODE_INST_PLAY_NOT_FINISH_EXECUTE = 2000002;
@ -12309,7 +12280,6 @@ enum WorldTeamLeaveReason {
WORLD_TEAM_LEAVE_REASON_BE_KICK = 1; WORLD_TEAM_LEAVE_REASON_BE_KICK = 1;
WORLD_TEAM_LEAVE_REASON_DISSOLVE = 2; WORLD_TEAM_LEAVE_REASON_DISSOLVE = 2;
WORLD_TEAM_LEAVE_REASON_LOGOUT = 3; WORLD_TEAM_LEAVE_REASON_LOGOUT = 3;
WORLD_TEAM_LEAVE_REASON_TO_OWN_BIG_WORLD = 4;
} }
enum WorldTeamPlayerChangeType { enum WorldTeamPlayerChangeType {

View file

@ -1,13 +1,12 @@
# WutheringWaves # WutheringWaves
Wuthering Waves server emulator (0.9.0) Wuthering Waves server emulator (0.8.2)
## How to run ## How to run
- Compile and run SDKServer and GameServer using dotnet8 (Visual Studio 2022 recommended) - Compile and run SDKServer and GameServer using dotnet8 (Visual Studio 2022 recommended)
## Connecting ## Connecting
- Get game client from somewhere. For example using official launcher (you can find it in our discord) - Download [Game Client](https://nogatekeep.ing/assets/ww/0.8.2/ww.7z), it's **pre-patched** and redirects http requests to `127.0.0.1:5500`
- [Download and extract patch](https://nogatekeep.ing/assets/ww/0.9.0/WuWa-0.9-patch.zip) to the game folder, it will redirect all http requests to `127.0.0.1:5500`
- Run game and connect to the server - Run game and connect to the server
## Need help? ## Need help?

View file

@ -4,10 +4,10 @@ namespace SDKServer.Handlers;
internal static class HotPatchHandler internal static class HotPatchHandler
{ {
public static string OnConfigRequest() => "{\r\n \"PackageVersion\": \"0.9.0\",\r\n \"LauncherVersion\": \"0.9.0\",\r\n \"ResourceVersion\": \"0.9.3\",\r\n \"LauncherIndexSha1\": {},\r\n \"ResourceIndexSha1\": {\r\n \"0.9.1\": \"F9E8CE07677A58BE26B8D1A193712167A5AD7D6E\",\r\n \"0.9.2\": \"2ACEAED17AC801D6860C61E4AFB4F9E8FB07EC71\",\r\n \"0.9.3\": \"6627F17FAA25267DFFB6875F845DF4CFA2DE67EA\"\r\n },\r\n \"ChangeList\": \"1162610\",\r\n \"CompatibleChangeLists\": [],\r\n \"Versions\": [\r\n {\r\n \"Name\": \"en\",\r\n \"Version\": \"0.9.3\",\r\n \"IndexSha1\": {\r\n \"0.9.1\": \"80083122F01DEFAE73F24F41F1B9D4F87B72B1BF\",\r\n \"0.9.2\": \"1C41F2D5DF38027153F16C777B9FAD3F27578E17\",\r\n \"0.9.3\": \"7A611990E039B3D7AD1EA505E1E9F544D310E9B8\"\r\n }\r\n },\r\n {\r\n \"Name\": \"ja\",\r\n \"Version\": \"0.9.3\",\r\n \"IndexSha1\": {\r\n \"0.9.1\": \"DBA7744B8994E20BB85D993DF9D2A214A3C09460\",\r\n \"0.9.2\": \"C22680FDAAEB25787B83800DDD1CB6C5AC66D285\",\r\n \"0.9.3\": \"8CACF6381D82BA3B577DF804DA2599ADDD8A5AE8\"\r\n }\r\n },\r\n {\r\n \"Name\": \"ko\",\r\n \"Version\": \"0.9.3\",\r\n \"IndexSha1\": {\r\n \"0.9.1\": \"DCA10D3FA125185A7F5F919FDD580474497912C6\",\r\n \"0.9.2\": \"1FEF3B7B05A1D5C8A346E03868976217B4C49E59\",\r\n \"0.9.3\": \"89631EAA41697A4ABFE785A53273FB50745114C9\"\r\n }\r\n },\r\n {\r\n \"Name\": \"zh\",\r\n \"Version\": \"0.9.3\",\r\n \"IndexSha1\": {\r\n \"0.9.1\": \"20CCECCEBBB910C14BE3CF111037F15287CB46E7\",\r\n \"0.9.2\": \"A176E35CFB6DB0C1CDE8B1B1EC141BD9479CFE59\",\r\n \"0.9.3\": \"66E3A0365D324E303A56F85E347F05EBBEA56645\"\r\n }\r\n }\r\n ]\r\n}"; public static string OnConfigRequest() => "N2wiD0yJQntN+Kv98DJOLWvjpgvdTa3/KRA9Rf288hPWxbPgAOzkf/mSfCXKMOFldB3zoIftzB7NIGkF+slYu1MoBcFyxkhx+lRW9oDsuqKVS32cgEyuopKuN71QdjPII82UGXGd4M5mBilVEkTaRKBZVypka5CB79x5Rs2iiPTxOk1zdOUi5F6uUD0cjQod/KM+7TtaiUsSNS+FVBldLPWJOdcQWomUw+q5cCLBJqhxYUJg/hQAt8rRRHyDj2H+0RAdMt1WS5qbYb+QkVCvZlT4UWUyaes3p3xsyyr0HpiqzHXf5iLjaxSv5iKNrLUpLMexn2c3bf+TG7Kca/QYwbJYz4TeYk8zuV7A1ccC4fgSSxwC50xChiOuPwyi7NWkP7Z2FEyqtBWpgoWo6+uFn+f1PaalaZt9e2JZXvmZjcY5pQwGfbXSHAGu3yopAScBvsX1nQzrRgi8LFN/2XTMaoYjfZp+FiNiVMFCK7IlcfjeL1Shd5FrwcKnEGPeu6dVBvrZnKWaK81lzZnZc0Yce95rZMa7o8ccQBTWXE/S/ZXV10ctCO6KYa1/+l+zhvAfPt3WcU7OvcOh24kg/WSYOZFg9nFaLpMzSCTqZPhi7OE1LU5o0uLfk8kFJtJFj7CVG0YiD/dZhWhA0HW6WZmbE/DESkUMagfVPanZCZpweBBnmmRnJZr+LMm5btmgmZZ8/pwGk/JbvpwRaSvP1Cw/hIVq6m/EJ+j+oHr/EscxoVa2f9pGB20TOS7ggTPiwkvfWxX04CXCQ6VgQ8dFNZB4tO6LiNsCfSARDz0VNjqdpdRpON0W2KjfhKlX4IlhsQj9Cnet4Dk/knWe/vO2e2/JGw4JGXzJmguhT9EQE81IaGoKkcOBjED5odgONH37TyNK86piMBHYHRy/ZhpKOHbMhNh5Vv2mv94kzLMD6elXnRiL888tcc3hgi2fmZR6DVKvbiN2SIXRABQy6YNtKQVjMBzJEGART29AyD4r89L85T4jbheTiyXiDIX4H0eGGfqLsCJnSocV7GLm2ZJrKY/ebsg50fadj3AlxnU2Hqkxyn3Xdmf5ilM9lQ8xurrtsbGSSn6cQ/56X8Vm5gJa/4bFyMvuSl4ygKuAq6Ae8S7faeRUPkmObPOBdU841OmMWrjf8IeXzt+jkK00VglUC8y+ZhvX33ZYNXGjAACwZF11GCS3plkhI7zwtOlLNavtO94INQQGulQ/fG+mu4BAh19xtMiZpUXIumleO0ehq5LHiE/UYMZizvONyvPbCnqmkvEI8f9kgkODPkPBfQjqQ7qeGpU7BdbKEv83BTr5SyG6m80Fq0BDVdX5BwkGdk28YeJdbjUhUH0/fmSr7ODw6YYpE3x8TaDpOq+taNZu40KZ6USeNqEofSZPHC4e1+SwSpjldOoQTdH7BBaQ6hN0plJkm+4HL7KbWAQOX82W7H3Ks/GoMeHmokTo9T2JUTi+dzNpuaOjxlxyiuoDkiZ+0cOcLIbKk5Df0cphrkq2GrvCJ5g4FGvLvcPrs8tdA15D89i8Ygrh6ERy6beiwTCEtK5sqWM11URUrCCTRi3JRprzq+R+ghOPVGK1svfpUbzAyWZK6ugt3OYdg0Ze3WKFnvLqRAhWu6ouy+iHrT8D1qVna+6IZ3OCZbDpTlszQTA+5YNY9iO2O9seOJvbUOep5T04RETWFEr0vunp3M0FAH9OtaUN9ePmshqk3h1wC0oftx+8d5QvyJ/EkrXi4LA1huKDGtbf2P8RK2oH7wXKZaMZKYl2IGtc1lzIebtzkkqY/6ygl4K8mhFUf1g4vXSvA17mjdcemrptVCxB5EAnjiyBbjhVtoSE4RAmN7ysA95MeF104cf4AFUS2V3c4h7RTRb0HRIOfWhPc/UP6UZnXYx+ALCKyfSDXZ7v9Ctxfqnd/WwxKg233tcPBOgOVP72wSYiXt3HtHve5/NqBrz3PW7KJLoA5wTG43iURlkhvgIXJV6PK6BbCXgusT0ZHOtKUYIbhomZ1Wa+2VmCcljQdfN/qH7C1nS6Icr+OGHqoA4XBoj3OMZ1wQrP+9BwWhp9dxsLlT8lNQny8f9IIzvxZNyDNK7WOfRAHuO1x0Wf8aqA11SM8BL99m90PuLzMXK7zZgqKxJVF1Ry640/JMr8vaK01aKGwMEQXaUt/so94Z/FXm8uwZJ9Rw7ZIviyzdPmq7JXNa8W2kkeEEdekBKdCOD+Q63F0pzFoqvkrqram17GJHbGN/0DXoYrQGkJjuo7ZiwdJGagtuFah7Fut+bWvfmy5CnK6/6VKmLaWxPqjXZrCPru05KoKaMEPtJNElGIGkYmohX4fbwwwe0LvwZBrST+45+KzcApMOIqj2iSo+m5iwEMwpMIdJoor6Tsx7gdhS3ekeK9Ad7hZBFLNSYxL+sirfBfMHVYIDCLRrDwkssT0Qzd8wUTZG88TkyKxLWKMNAqwkab5lvEc5Vk3gjFLyQXbxKk8zhx9pBa9fWIcVJeQpVhJXayqWYBTsLCXZ42aWRehX9M6tuR9j8cyXHNQI6NXDB5WA05P5qKV8VauoVoLIWZlmVoH/bfiiPxTHTFdj08jpwPWtDKPYG6XRt3/DgF+e9TcIxsDT/Tci885fA6SP4e46yML5F4e4bUMusTkjBkMBuqrSzAZyIuj1Xady3xFW35EanmzAH0jOoz2Qycgv5BpFmjmHytw1nOxAC/gOja8UwzIxgFmB55QGQKikI8u9hNCAJEMkz1yozOucWR7rUbtj9YvXXTAfn/p3Ea517/FnxjVMvpUwJssldhApzEdN+eyNbs806+ucaJvevmM5IP7/xDFgAf/wx1zorLQHT6N5rDqqvRnDr7inwcLyQSjcS+DU47UEnyvTzoZ6jBwrJWJ22a8O4jwnVmqMqmsfjrcprJ/HjTwIbnKzN1fIIIZQuC0V2E5IyxcPdYMJPBBGQM6jd583pYU5Zg6bjdNy5K7w==";
public static string OnKeyListRequest() => "{\r\n \"Hash\": \"da39a3ee5e6b4b0d3255bfef95601890afd80709\",\r\n \"Random\": \"CtBIsHPiwhwOqqBYxj\",\r\n \"Key\": \"EYA/aRYz0h2W77M07J2AHTftgGQiIcFQFpgGsdsm65Ee8YqP6uI86fIG4EWftUr7B2vLbh/U62yi21e4CeGIpr+HppDDmpprS/QTmZYQ0OX9q/KB06+4ihmwzSim1iTedixejDPQ8BP90iH7CI6Se/+BhfslZh3MxDmzzl8W9bw=\"\r\n}"; public static string OnKeyListRequest() => "dJf580+dhY42au4yMyAS8bT83C9lOj2Igaw6GHLdgMgu45ugRZGzR2HUowgKaW/qQMY2v1+DubYu4hOeINFYWRbKpZUoKO+FHvPeeBAt00gqLBeHEnChvUSOPpAeJJp8ryfahbqy+LQ5d+2W/UOP83XZEVUIYPWleXbWUVMXLCCznOg76nWywXdHe9/Yukff8Di99tDt3NiSTdQPEtmk/c4vgXay+QTcFW8mwHgEhVh6vb9jQOMwvG4cmmjnigedTqW7Q4jm6GbgSWdb/tesmg70Jrjj4aHn6PI9jMSBSwk3tClBx8/Qwz1Ji+gyt/7XwvFmf+MZ8MyAH1DuIKrsomr7IfsMboKlr3T0EEIwVsb6idrbYaphGhefSemA/v2D";
public static FileContentHttpResult OnPakDataRequest() public static FileContentHttpResult OnPakDataRequest()
=> TypedResults.File([]); => TypedResults.File(Convert.FromHexString("446144334C5075782F544D35586C5A623669315A6A66774A32536265514843762B43567567764F41596B737A596874397164455861454B51626376474F664E544B536335754135444867385A674263356C4245654D6C374C43392F64326565473755796E754E59655753446C48624F544430785338514D39577165306F45706D5541353879377856304B38445970706D47683338386F51744C7A307472314C7743667A416D2F69536D70633D0A"));
} }

View file

@ -10,12 +10,6 @@ public record BaseConfigModel
[JsonPropertyName("SecondaryUrl")] [JsonPropertyName("SecondaryUrl")]
public required CdnUrlEntry[] SecondaryUrl { get; set; } public required CdnUrlEntry[] SecondaryUrl { get; set; }
[JsonPropertyName("SpeedRatio")]
public int SpeedRatio { get; set; }
[JsonPropertyName("PriceRatio")]
public int PriceRatio { get; set; }
[JsonPropertyName("GmOpen")] [JsonPropertyName("GmOpen")]
public bool GmOpen { get; set; } public bool GmOpen { get; set; }

View file

@ -7,22 +7,19 @@ internal static class Program
{ {
private static async Task Main(string[] args) private static async Task Main(string[] args)
{ {
Console.Title = "Wuthering Waves | SDK Server"; var builder = WebApplication.CreateBuilder(args);
Console.WriteLine(" __ __ __ .__ .__ __ __ \r\n/ \\ / \\__ ___/ |_| |__ ___________|__| ____ ____ / \\ / \\_____ ___ __ ____ ______\r\n\\ \\/\\/ / | \\ __\\ | \\_/ __ \\_ __ \\ |/ \\ / ___\\ \\ \\/\\/ /\\__ \\\\ \\/ // __ \\ / ___/\r\n \\ /| | /| | | Y \\ ___/| | \\/ | | \\/ /_/ > \\ / / __ \\\\ /\\ ___/ \\___ \\ \r\n \\__/\\ / |____/ |__| |___| /\\___ >__| |__|___| /\\___ / \\__/\\ / (____ /\\_/ \\___ >____ >\r\n \\/ \\/ \\/ \\//_____/ \\/ \\/ \\/ \\/ \r\n\r\n\t\t\t\t\t\t\t\t\t\t\t\tSDK Server\n");
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseUrls("http://*:5500"); builder.WebHost.UseUrls("http://*:5500");
builder.Logging.AddSimpleConsole(); builder.Logging.AddSimpleConsole();
WebApplication app = builder.Build(); var app = builder.Build();
app.UseMiddleware<NotFoundMiddleware>(); app.UseMiddleware<NotFoundMiddleware>();
app.MapGet("/api/login", LoginHandler.Login); app.MapGet("/api/login", LoginHandler.Login);
app.MapGet("/index.json", ConfigHandler.GetBaseConfig); app.MapGet("/config/index.json", ConfigHandler.GetBaseConfig);
app.MapGet("/dev/client/mtZyW6ZYIu1pE0TCHUbXcM1oU8vx4hnb/Windows/KeyList_0.9.0.json", HotPatchHandler.OnKeyListRequest); app.MapGet("/dev/client/7cyFLmtLJlUauZ1hM8DsL5Sj7cXxSNQD/Windows/KeyList_0.8.0.json", HotPatchHandler.OnKeyListRequest);
app.MapGet("/dev/client/mtZyW6ZYIu1pE0TCHUbXcM1oU8vx4hnb/Windows/config.json", HotPatchHandler.OnConfigRequest); app.MapGet("/dev/client/7cyFLmtLJlUauZ1hM8DsL5Sj7cXxSNQD/Windows/config.json", HotPatchHandler.OnConfigRequest);
app.MapGet("/dev/client/mtZyW6ZYIu1pE0TCHUbXcM1oU8vx4hnb/Windows/client_key/0.9.0/CtBIsHPiwhwOqqBYxj/PakData", HotPatchHandler.OnPakDataRequest); app.MapGet("/dev/client/7cyFLmtLJlUauZ1hM8DsL5Sj7cXxSNQD/Windows/client_key/0.8.0/xFrH845q3t8Pgy5eB2/PakData", HotPatchHandler.OnPakDataRequest);
await app.RunAsync(); await app.RunAsync();
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 199 KiB

After

Width:  |  Height:  |  Size: 205 KiB

View file

@ -1,52 +0,0 @@
using Google.Protobuf;
using Protocol;
namespace TrafficAnalyzer;
internal static class Program
{
private const int StdInSize = 65535;
private const string ProtoAssembly = "Protocol";
private const string ProtoNamespace = "Protocol";
private const string MessageParserProperty = "Parser";
private static readonly DumpOptions s_objectDumperOpts = new() { DumpStyle = DumpStyle.CSharp, IndentSize = 4, IndentChar = ' ', IgnoreDefaultValues = true };
private static void Main(string[] args)
{
Console.SetIn(new StreamReader(Console.OpenStandardInput(StdInSize), Console.InputEncoding, false, StdInSize));
List<Tuple<int, byte[]>> inList = [];
string? idInput;
string? payloadInput;
while (!string.IsNullOrEmpty(idInput = Console.ReadLine()) && (payloadInput = Console.ReadLine()) != null)
{
int messageId = int.Parse(idInput);
byte[] payload = Convert.FromHexString(payloadInput);
inList.Add(Tuple.Create(messageId, payload));
}
foreach ((int messageId, byte[] payload) in inList)
{
string messageName = ((MessageId)messageId).ToString();
Type? type = Type.GetType($"{ProtoNamespace}.{messageName},{ProtoAssembly}");
if (type is null)
{
Console.WriteLine($"Message with id {messageName} wasn't found in proto definition.");
continue;
}
MessageParser parser = (MessageParser)type.GetProperty(MessageParserProperty)!.GetValue(null)!;
IMessage message = parser.ParseFrom(payload);
string outputInitializer = ObjectDumper.Dump(message, s_objectDumperOpts);
Console.WriteLine($"Message: {messageName}");
Console.WriteLine(outputInitializer);
}
}
}

View file

@ -1,18 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ObjectDumper.NET" Version="4.1.15" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Protocol\Protocol.csproj" />
</ItemGroup>
</Project>

View file

@ -16,9 +16,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KcpSharp", "KcpSharp\KcpSha
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Protocol", "Protocol\Protocol.csproj", "{9900A88C-7818-4335-84F7-1538ECC8B338}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Protocol", "Protocol\Protocol.csproj", "{9900A88C-7818-4335-84F7-1538ECC8B338}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Core", "Core\Core.csproj", "{C025BDED-6DC7-493D-8D10-05DCCB3072F3}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core", "Core\Core.csproj", "{C025BDED-6DC7-493D-8D10-05DCCB3072F3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TrafficAnalyzer", "TrafficAnalyzer\TrafficAnalyzer.csproj", "{7DA57BA1-215F-4DD8-86A9-CAC62908A6F3}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -46,10 +44,6 @@ Global
{C025BDED-6DC7-493D-8D10-05DCCB3072F3}.Debug|Any CPU.Build.0 = Debug|Any CPU {C025BDED-6DC7-493D-8D10-05DCCB3072F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C025BDED-6DC7-493D-8D10-05DCCB3072F3}.Release|Any CPU.ActiveCfg = Release|Any CPU {C025BDED-6DC7-493D-8D10-05DCCB3072F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C025BDED-6DC7-493D-8D10-05DCCB3072F3}.Release|Any CPU.Build.0 = Release|Any CPU {C025BDED-6DC7-493D-8D10-05DCCB3072F3}.Release|Any CPU.Build.0 = Release|Any CPU
{7DA57BA1-215F-4DD8-86A9-CAC62908A6F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7DA57BA1-215F-4DD8-86A9-CAC62908A6F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7DA57BA1-215F-4DD8-86A9-CAC62908A6F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7DA57BA1-215F-4DD8-86A9-CAC62908A6F3}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE