diff --git a/UdpHosts/GameServer/Controllers/Character/BaseController.cs b/UdpHosts/GameServer/Controllers/Character/BaseController.cs index e78df937..342bee1f 100644 --- a/UdpHosts/GameServer/Controllers/Character/BaseController.cs +++ b/UdpHosts/GameServer/Controllers/Character/BaseController.cs @@ -183,9 +183,36 @@ public void VehicleCalldownRequest(INetworkClient client, IPlayer player, ulong } var character = player.CharacterEntity; - var position = character.Position; - var entityMan = client.AssignedShard.EntityMan; - entityMan.SpawnVehicle(vehicleCalldownRequest.VehicleID, position, Quaternion.Identity, character); + var abilities = client.AssignedShard.Abilities; + abilities.HandleVehicleCalldownRequest(character.EntityId, vehicleCalldownRequest); + } + + [MessageID((byte)Commands.DeployableCalldownRequest)] + public void DeployableCalldownRequest(INetworkClient client, IPlayer player, ulong entityId, GamePacket packet) + { + var deployableCalldownRequest = packet.Unpack(); + if (deployableCalldownRequest == null) + { + return; + } + + var character = player.CharacterEntity; + var abilities = client.AssignedShard.Abilities; + abilities.HandleDeployableCalldownRequest(character.EntityId, deployableCalldownRequest); + } + + [MessageID((byte)Commands.ResourceNodeBeaconCalldownRequest)] + public void ResourceNodeBeaconCalldownRequest(INetworkClient client, IPlayer player, ulong entityId, GamePacket packet) + { + var thumperCalldownRequest = packet.Unpack(); + if (thumperCalldownRequest == null) + { + return; + } + + var character = player.CharacterEntity; + var abilities = client.AssignedShard.Abilities; + abilities.HandleResourceNodeBeaconCalldownRequest(character.EntityId, thumperCalldownRequest); } [MessageID((byte)Commands.SetEffectsFlag)] diff --git a/UdpHosts/GameServer/Controllers/Character/CombatController.cs b/UdpHosts/GameServer/Controllers/Character/CombatController.cs index bb792ed0..f51d8c54 100644 --- a/UdpHosts/GameServer/Controllers/Character/CombatController.cs +++ b/UdpHosts/GameServer/Controllers/Character/CombatController.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using AeroMessages.GSS.V66.Character; using AeroMessages.GSS.V66.Character.Command; @@ -117,6 +118,53 @@ public void CancelReload(INetworkClient client, IPlayer player, ulong entityId, player.CharacterEntity.SetWeaponReloadCancelled(query.Time); } + [MessageID((byte)Commands.ActivateConsumable)] + public void ActivateConsumable(INetworkClient client, IPlayer player, ulong entityId, GamePacket packet) + { + var query = packet.Unpack(); + Console.WriteLine($"ActivateConsumable {query.ItemSdbId}"); + if (query == null) + { + return; + } + + var abilityModule = SDBInterface.GetAbilityModule(query.ItemSdbId); + if (abilityModule == null) + { + return; + } + + uint abilityId = abilityModule.AbilityChainId; + if (abilityId != 0) + { + var character = player.CharacterEntity; + var activationTime = query.Time; + if (character.IsPlayerControlled) + { + var message = new AbilityActivated + { + ActivatedAbilityId = abilityId, + ActivatedTime = activationTime, + AbilityCooldownsData = new AbilityCooldownsData + { + ActiveCooldowns_Group1 = Array.Empty(), + ActiveCooldowns_Group2 = Array.Empty(), + Unk = 0, + GlobalCooldown_Activated_Time = activationTime, + GlobalCooldown_ReadyAgain_Time = activationTime + 300, + } + }; + Console.WriteLine($"ActivateAbility {message.ActivatedAbilityId} at {message.ActivatedTime}"); + character.Player.NetChannels[ChannelType.ReliableGss].SendIAero(message, character.EntityId); + } + + var initiator = character as IAptitudeTarget; + var shard = player.CharacterEntity.Shard; + var targets = new HashSet(); + shard.Abilities.HandleActivateAbility(shard, initiator, abilityId, activationTime, targets); + } + } + [MessageID((byte)Commands.ActivateAbility)] public void ActivateAbility(INetworkClient client, IPlayer player, ulong entityId, GamePacket packet) { diff --git a/UdpHosts/GameServer/Data/CharacterInventory.cs b/UdpHosts/GameServer/Data/CharacterInventory.cs new file mode 100644 index 00000000..088a3c8d --- /dev/null +++ b/UdpHosts/GameServer/Data/CharacterInventory.cs @@ -0,0 +1,270 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using AeroMessages.GSS.V66.Character.Event; +using GameServer.Data.SDB; +using GameServer.Entities.Character; +using GameServer.Enums; + +namespace GameServer.Data; + +public class CharacterInventory +{ + public bool EnablePartialUpdates = false; + + private Dictionary _items; // By guid + private Dictionary _resources; // By typeid + private Dictionary _loadouts; // By loadoutid + + private IShard _shard; + private INetworkClient _player; + private CharacterEntity _character; + + public CharacterInventory(IShard shard, INetworkClient player, CharacterEntity character) + { + _shard = shard; + _player = player; + _character = character; + _items = new(); + _resources = new(); + _loadouts = new(); + + foreach(var loadout in HardcodedCharacterData.GetTempAvailableLoadouts()) + { + _loadouts.Add(loadout.FrameLoadoutId, loadout); + } + } + + public void CreateItem(uint sdbId) + { + ulong guid = _shard.GetNextGuid((byte)GuidService.AdditionalTypes.Item); + Item item = new Item() + { + SdbId = sdbId, + GUID = guid, + SubInventory = GetInventoryTypeByItemTypeId(sdbId), + Durability = 1000, + DynamicFlags = 0, + TimestampEpoch = (uint)DateTimeOffset.UtcNow.ToUnixTimeSeconds(), + Modules = Array.Empty(), + Unk1 = 0, + Unk3 = 0, + Unk4 = 0, + Unk5 = 0, + Unk6 = Array.Empty(), + Unk7 = 0, + }; + + _items.Add(guid, item); + SendItemUpdate(guid); + } + + public void AddResource(uint sdbId, uint quantity) + { + if (!_resources.ContainsKey(sdbId)) + { + Resource resource = new Resource() + { + Quantity = 0, + SdbId = sdbId, + SubInventory = GetInventoryTypeByItemTypeId(sdbId), + TextKey = string.Empty, + Unk2 = 0, + }; + + _resources.Add(sdbId, resource); + } + + var res = _resources[sdbId]; + res.Quantity += quantity; + _resources[sdbId] = res; + SendResourceUpdate(sdbId); + } + + public bool ConsumeResource(uint sdbId, uint cost) + { + if (!_resources.ContainsKey(sdbId)) + { + return false; + } + + var res = _resources[sdbId]; + if (res.Quantity < cost) + { + return false; + } + else + { + res.Quantity -= cost; + + if (res.Quantity > 0) + { + _resources[sdbId] = res; + } + else + { + _resources.Remove(sdbId); + } + + SendResourceUpdate(sdbId); + return true; + } + } + + public void SendFullInventory() + { + if (_items.Count > 255) + { + throw new NotImplementedException("Too many items in inventory, CharacterInventory.SendFullInventory has to be updated"); + } + + if (_resources.Count > 255) + { + throw new NotImplementedException("Too many resources in inventory, CharacterInventory.SendFullInventory has to be updated"); + } + + if (_loadouts.Count > 255) + { + throw new NotImplementedException("Too many loadouts in inventory, CharacterInventory.SendFullInventory has to be updated"); + } + + var update = new InventoryUpdate() + { + ClearExistingData = 1, + ItemsPart1Length = (byte)_items.Count, + ItemsPart1 = _items.Values.ToArray(), + ItemsPart2Length = 0, + ItemsPart2 = Array.Empty(), + ItemsPart3Length = 0, + ItemsPart3 = Array.Empty(), + Resources = _resources.Values.ToArray(), + Loadouts = _loadouts.Values.ToArray(), + Unk = 1, + SecondItems = Array.Empty(), + SecondResources = Array.Empty() + }; + _player.NetChannels[ChannelType.ReliableGss].SendIAero(update, _character.EntityId); + } + + public void SendItemUpdate(ulong guid) + { + if (!EnablePartialUpdates) + { + return; + } + + var item = _items[guid]; + var update = new InventoryUpdate() + { + ClearExistingData = 0, + ItemsPart1Length = 1, + ItemsPart1 = + [ + item + ], + ItemsPart2Length = 0, + ItemsPart2 = Array.Empty(), + ItemsPart3Length = 0, + ItemsPart3 = Array.Empty(), + Resources = Array.Empty(), + Loadouts = Array.Empty(), + Unk = 1, + SecondItems = Array.Empty(), + SecondResources = Array.Empty() + }; + + _player.NetChannels[ChannelType.ReliableGss].SendIAero(update, _character.EntityId); + } + + public void SendResourceUpdate(uint sdbId) + { + if (!EnablePartialUpdates) + { + return; + } + + var resource = _resources[sdbId]; + var update = new InventoryUpdate() + { + ClearExistingData = 0, + ItemsPart1Length = 0, + ItemsPart1 = Array.Empty(), + ItemsPart2Length = 0, + ItemsPart2 = Array.Empty(), + ItemsPart3Length = 0, + ItemsPart3 = Array.Empty(), + Resources = + [ + resource + ], + Loadouts = Array.Empty(), + Unk = 1, + SecondItems = Array.Empty(), + SecondResources = Array.Empty() + }; + + _player.NetChannels[ChannelType.ReliableGss].SendIAero(update, _character.EntityId); + } + + private byte GetInventoryTypeByItemTypeId(uint sdbId) + { + var itemInfo = SDBInterface.GetRootItem(sdbId); + if (itemInfo != null) + { + return GetInventoryTypeByItemType(itemInfo.Type); + } + else + { + return (byte)InventoryType.Bag; + } + } + + private byte GetInventoryTypeByItemType(byte itemType) + { + var result = InventoryType.Bag; + switch ((ItemType)itemType) + { + case ItemType.TinkerTools: + result = InventoryType.Bag; + break; + case ItemType.ItemModule: + result = InventoryType.Bag; + break; + case ItemType.PaletteModule: + result = InventoryType.Bag; + break; + case ItemType.CraftingStation: + result = InventoryType.Bag; + break; + case ItemType.ResourceItem: + result = InventoryType.Bag; + break; + case ItemType.LockBoxKey: + result = InventoryType.Bag; + break; + case ItemType.Basic: // NOTE: There are some basic type items and resources that go into cache + result = InventoryType.Bag; + break; + case ItemType.Consumable: + result = InventoryType.Cache; + break; + case ItemType.AbilityModule: + result = InventoryType.Gear; + break; + case ItemType.FrameModule: + result = InventoryType.Gear; + break; + case ItemType.Weapon: + result = InventoryType.Gear; + break; + case ItemType.Chassis: + result = InventoryType.Gear; + break; + default: + Console.WriteLine($"Unknown InventoryType for ItemType {(ItemType)itemType}, defaulting to {result}"); + break; + } + + return (byte)result; + } +} \ No newline at end of file diff --git a/UdpHosts/GameServer/Data/HardcodedCharacterData.cs b/UdpHosts/GameServer/Data/HardcodedCharacterData.cs index a226598b..71a4dfb0 100644 --- a/UdpHosts/GameServer/Data/HardcodedCharacterData.cs +++ b/UdpHosts/GameServer/Data/HardcodedCharacterData.cs @@ -74,6 +74,405 @@ public static class HardcodedCharacterData { 247, 77733 }, // BattleLab Trainee }; + public static uint[] FallbackInventoryItems = + [ + 151, + 33800, + 56728, + 56811, + 75257, + 75772, + 75773, + 75774, + 75775, + 75820, + 76132, + 76133, + 76164, + 76331, + 76332, + 76333, + 76334, + 76335, + 76336, + 76337, + 76338, + 76958, + 76999, + 77018, + 77019, + 77066, + 77067, + 77068, + 77087, + 77340, + 77367, + 77402, + 77496, + 77504, + 77510, + 77523, + 81352, + 81361, + 81362, + 81423, + 81457, + 81490, + 82337, + 82360, + 84820, + 85228, + 85511, + 85555, + 85958, + 86400, + 87058, + 87483, + 87542, + 87779, + 87848, + 87899, + 90519, + 90623, + 96464, + 96487, + 96578, + 96946, + 98188, + 99093, + 101940, + 101995, + 102046, + 102427, + 103986, + 104170, + 104353, + 105495, + 105810, + 105920, + 105981, + 106103, + 106785, + 107730, + 107784, + 110768, + 113514, + 113520, + 113552, + 113556, + 113687, + 113712, + 113718, + 113742, + 113810, + 113838, + 113853, + 113858, + 113873, + 113931, + 113972, + 113996, + 114008, + 114026, + 114044, + 114050, + 114068, + 114074, + 114088, + 114094, + 114112, + 114142, + 114160, + 114166, + 114226, + 114260, + 114316, + 114320, + 118133, + 118733, + 120125, + 124132, + 124140, + 124142, + 124651, + 124665, + 124671, + 125435, + 125445, + 125483, + 125631, + 125636, + 125683, + 125725, + 125845, + 126127, + 126165, + 126309, + 126413, + 126500, + 126529, + 126534, + 126539, + 126575, + 126896, + 127030, + 127040, + 127097, + 127134, + 127144, + 127223, + 127270, + 127306, + 127626, + 127636, + 127770, + 127812, + 127864, + 127874, + 127953, + 128000, + 128036, + 128356, + 128361, + 128500, + 128552, + 128557, + 128604, + 128688, + 128689, + 128730, + 128766, + 128958, + 128990, + 129010, + 129020, + 129056, + 129061, + 129202, + 129242, + 129312, + 129396, + 129458, + 129604, + 129993, + 130000, + 130370, + 130419, + 130436, + 130595, + 130596, + 130597, + 130598, + 130599, + 130600, + 130602, + 130606, + 131708, + 132068, + 132110, + 132442, + 132620, + 134616, + 136056, + 136514, + 136576, + 136660, + 136722, + 137212, + 138462, + 138795, + 139124, + 139125, + 139303, + 139665, + 139736, + 139807, + 139875, + 139922, + 140705, + 140755, + 140757, + 141873, + 141906, + 141929, + 142078, + 142119, + 142132, + 143123, + 143125, + 143131, + 143132, + 143133, + 143134, + 143195, + 143211, + 143212, + 143250, + 143330, + 143333, + 143368, + 143372, + 143380, + 143437, + 143670, + ]; + + public static (uint, uint)[] FallbackInventoryResourcesShort = + [ + (10, 3531909), + (56, 11), + (30101, 98780), + (30298, 1268), + (30412, 4), + (32755, 21), + (34107, 5824641), + ]; + + public static (uint, uint)[] FallbackInventoryResources = + [ + (10, 3531909), + (56, 11), + (30101, 98780), + (30298, 1268), + (30412, 4), + (32755, 21), + (34107, 5824641), + (54003, 4467), + (56835, 76), + (75425, 460), + (76947, 10), + (76978, 1), + (76979, 1), + (76984, 56), + (76985, 60), + (76986, 30), + (77014, 10), + (77015, 8), + (77132, 3330), + (77205, 315), + (77343, 14), + (77344, 1), + (77345, 6), + (77346, 14), + (77403, 7), + (77404, 6), + (77428, 334), + (77429, 330), + (77430, 3), + (77606, 3), + (77607, 2), + (77643, 16), + (77682, 1), + (77860, 2), + (78032, 2), + (80274, 2), + (81487, 1), + (82577, 547), + (82595, 108), + (82596, 128), + (82597, 15), + (82598, 174), + (82604, 20), + (82624, 45), + (82737, 1), + (85412, 1), + (85415, 1), + (85416, 1), + (85422, 2), + (85454, 1), + (85535, 21), + (85679, 7), + (85792, 1), + (85824, 5), + (86004, 1), + (86013, 2), + (86154, 9123363), + (86360, 1), + (86401, 9), + (86498, 2), + (86526, 1), + (86621, 11814), + (86628, 7), + (86667, 4978), + (86668, 1560), + (86669, 1487), + (86672, 239), + (86673, 608), + (86679, 1344), + (86681, 13), + (86682, 1), + (86683, 702), + (86696, 12), + (86699, 5), + (86703, 10750), + (86709, 903), + (86711, 429), + (86713, 2140), + (95083, 9), + (95084, 33), + (95085, 17), + (95086, 2), + (95087, 7), + (95088, 35), + (95089, 9), + (95093, 6), + (95094, 5), + (95095, 3), + (95096, 5), + (95097, 26), + (95098, 22), + (95099, 20), + (116563, 36), + (117036, 5), + (117702, 9), + (118147, 5), + (118355, 54), + (120498, 43), + (120622, 1), + (120974, 14), + (121093, 6), + (121377, 1), + (122951, 15), + (122953, 1), + (122954, 1), + (123027, 19), + (123052, 21), + (123217, 1), + (123353, 2), + (123384, 1), + (123400, 1), + (123404, 1), + (123426, 1), + (124249, 2814), + (124250, 3323), + (124251, 5296), + (124334, 10), + (124565, 11), + (124624, 14), + (124626, 29), + (124652, 1), + (124653, 5), + (124654, 1), + (136476, 2), + (138302, 30), + (138334, 3), + (138694, 2), + (138695, 7), + (138754, 1), + (138755, 1), + (139683, 5651), + (139960, 5), + (139961, 12), + (140057, 100), + (140737, 1), + (140743, 2), + (142144, 13087), + (142185, 1), + (142268, 18), + (143124, 2), + (143677, 60), + ]; + public static uint LookupTempAvailableLoadoutId(uint chassisId) => TempAvailableLoadouts .Where((pair) => pair.Value == chassisId) .Select((pair) => pair.Key) diff --git a/UdpHosts/GameServer/Enums/InventoryType.cs b/UdpHosts/GameServer/Enums/InventoryType.cs new file mode 100644 index 00000000..5bfe3cb8 --- /dev/null +++ b/UdpHosts/GameServer/Enums/InventoryType.cs @@ -0,0 +1,15 @@ +using System.Diagnostics.CodeAnalysis; + +namespace GameServer.Enums; + +[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1602:EnumerationItemsMustBeDocumented", Justification = "TODO")] +public enum InventoryType : byte +{ + Unknown = 0, + Bag = 1, + Cache = 2, + Crafting = 3, + Gear = 4, + Mail = 5, + TempResources = 6 +} diff --git a/UdpHosts/GameServer/Enums/ItemDynamicFlags.cs b/UdpHosts/GameServer/Enums/ItemDynamicFlags.cs new file mode 100644 index 00000000..8e3a4872 --- /dev/null +++ b/UdpHosts/GameServer/Enums/ItemDynamicFlags.cs @@ -0,0 +1,13 @@ +using System; +using System.Diagnostics.CodeAnalysis; + +namespace GameServer.Enums; + +[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1602:EnumerationItemsMustBeDocumented", Justification = "TODO")] +[Flags] +public enum ItemDynamicFlags : uint +{ + IsBound = 0x01, + Unk_0x02 = 0x02, // is_new? + IsEquipped = 0x04 +} diff --git a/UdpHosts/GameServer/Enums/ItemFlags.cs b/UdpHosts/GameServer/Enums/ItemFlags.cs new file mode 100644 index 00000000..6c41782f --- /dev/null +++ b/UdpHosts/GameServer/Enums/ItemFlags.cs @@ -0,0 +1,28 @@ +using System; +using System.Diagnostics.CodeAnalysis; + +namespace GameServer.Enums; + +[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1602:EnumerationItemsMustBeDocumented", Justification = "TODO")] +[Flags] +public enum ItemFlags : uint +{ + IsTradable = 0x01, + IsMailable = 0x02, + Hidden = 0x04, + Unk_0x08 = 0x08, // ? + Resource = 0x10, + Nopersist = 0x20, + Cached = 0x40, + IsPermanent = 0x80, + Unk_0x100 = 0x100, // maybe "is_consumable" or "is_deletable" + Unk_0x200 = 0x200, // Crystite (sdb_id 10) is the only item with this set + Unk_0x400 = 0x400, // maybe developer only or something + Unk_0x800 = 0x800, // maybe deprecated / unobtainable or broken + Unk_0x1000 = 0x1000, // maybe "is_stackable" + Unlimited = 0x2000, + IsSalvageable = 0x4000, + IsFancyNamed = 0x8000, + IsPvp = 0x10000, + Unk_0x20000 = 0x20000 // mostly pvp/regulation gear +} diff --git a/UdpHosts/GameServer/Enums/ItemType.cs b/UdpHosts/GameServer/Enums/ItemType.cs new file mode 100644 index 00000000..939aeb74 --- /dev/null +++ b/UdpHosts/GameServer/Enums/ItemType.cs @@ -0,0 +1,33 @@ +using System.Diagnostics.CodeAnalysis; + +namespace GameServer.Enums; + +[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1602:EnumerationItemsMustBeDocumented", Justification = "TODO")] +public enum ItemType : byte +{ + Basic = 0, + Weapon = 1, + Chassis = 2, + Unk_3 = 3, + AbilityModule = 4, + FireModule = 5, + ScopeModule = 6, + Consumable = 7, + Unk_8 = 8, + Powerup = 9, + FrameModule = 10, + WeaponModule = 11, + Blueprint = 12, + ResourceItem = 13, + CraftingStation = 14, + PaletteModule = 15, + Unk_16 = 16, + CraftingComponent = 17, + CraftingSubcomponent = 18, + PerkModule = 19, + GearUpgrade = 20, + ItemModule = 21, + LockBoxKey = 22, + TinkerTools = 23, + FabricationRecipe = 24 +} diff --git a/UdpHosts/GameServer/GUIDService.cs b/UdpHosts/GameServer/GUIDService.cs new file mode 100644 index 00000000..c8f817cc --- /dev/null +++ b/UdpHosts/GameServer/GUIDService.cs @@ -0,0 +1,37 @@ +using System.Threading.Tasks; + +namespace GameServer.Data; + +public static class GuidService +{ + private const byte MainServerId = 31; + private static uint MainCounter = 0; + + public enum AdditionalTypes : byte + { + Instance = 0xFB, + Army = 0xFC, + Item = 0xFD, + Character = 0xFE, + } + + public static ulong GetNext(uint time, Enums.GSS.Controllers type = Enums.GSS.Controllers.Generic) + { + return GetNext(time, (byte)type); + } + + public static ulong GetNext(uint time, byte type = (byte)Enums.GSS.Controllers.Generic) + { + return new Core.Data.EntityGuid(MainServerId, time, MainCounter++, type).Full; + } + + public static ulong GetNext(IShard shard, Enums.GSS.Controllers type = Enums.GSS.Controllers.Generic) + { + return GetNext(shard, (byte)type); + } + + public static ulong GetNext(IShard shard, byte type = (byte)Enums.GSS.Controllers.Generic) + { + return new Core.Data.EntityGuid(MainServerId, shard.CurrentTime, MainCounter++, type).Full; + } +} \ No newline at end of file diff --git a/UdpHosts/GameServer/GameServerModule.cs b/UdpHosts/GameServer/GameServerModule.cs index 58611171..9c7c13d2 100644 --- a/UdpHosts/GameServer/GameServerModule.cs +++ b/UdpHosts/GameServer/GameServerModule.cs @@ -11,6 +11,7 @@ protected override void Load(ContainerBuilder builder) { RegisterTypes(builder); RegisterInstances(builder); + base.Load(builder); } @@ -24,28 +25,31 @@ private static void RegisterTypes(ContainerBuilder builder) private static void RegisterInstances(ContainerBuilder builder) { builder.Register(ctx => - { - var loggerConfig = new LoggerConfiguration() - .ReadFrom.AppSettings() - .WriteTo.Console(theme: SerilogTheme.Custom); + { + var loggerConfig = new LoggerConfiguration() + .ReadFrom.AppSettings() + .WriteTo.Console(theme: SerilogTheme.Custom); + + var settings = ctx.Resolve(); - var settings = ctx.Resolve(); + if (settings.LogLevel.HasValue) + { + loggerConfig = loggerConfig.MinimumLevel.Is(settings.LogLevel.Value); + } - if (settings.LogLevel.HasValue) - { - loggerConfig = loggerConfig.MinimumLevel.Is(settings.LogLevel.Value); - } + return loggerConfig.CreateLogger(); + }) + .As().SingleInstance(); - return loggerConfig.CreateLogger(); - }).As().SingleInstance(); builder.Register(ctx => - { - var settings = ctx.Resolve(); + { + var settings = ctx.Resolve(); - StaticDB sdb = new StaticDB(); - sdb.Read(settings.StaticDBPath); + StaticDB sdb = new StaticDB(); + sdb.Read(settings.StaticDBPath); - return sdb; - }).As().SingleInstance(); + return sdb; + }) + .As().SingleInstance(); } } \ No newline at end of file diff --git a/UdpHosts/GameServer/IShard.cs b/UdpHosts/GameServer/IShard.cs index 80a2a3c7..a08cc38d 100644 --- a/UdpHosts/GameServer/IShard.cs +++ b/UdpHosts/GameServer/IShard.cs @@ -27,6 +27,7 @@ public interface IShard : IPacketSender ushort CurrentShortTime => unchecked((ushort)CurrentTime); IDictionary> EntityRefMap { get; } + ulong GetNextGuid(byte type); void Run(CancellationToken ct); bool Tick(double deltaTime, ulong currentTime, CancellationToken ct); void NetworkTick(double deltaTime, ulong currentTime, CancellationToken ct); diff --git a/UdpHosts/GameServer/NetworkPlayer.cs b/UdpHosts/GameServer/NetworkPlayer.cs index f0c29623..8c4e6d74 100644 --- a/UdpHosts/GameServer/NetworkPlayer.cs +++ b/UdpHosts/GameServer/NetworkPlayer.cs @@ -38,6 +38,7 @@ public NetworkPlayer(IPEndPoint endPoint, uint socketId, ILogger logger) public uint RequestedClientTime { get; set; } public bool FirstUpdateRequested { get; set; } public ulong SteamUserId { get; set; } + public CharacterInventory Inventory { get; set; } public void Init(IShard shard) { @@ -99,6 +100,20 @@ public async void Login(ulong characterId) CharacterEntity.SetPosition(pointOfInterestPosition); CharacterEntity.SetSpawnPose(); + // Inventory + Inventory = new CharacterInventory(AssignedShard, this, CharacterEntity); + + foreach(uint item in HardcodedCharacterData.FallbackInventoryItems) + { + Inventory.CreateItem(item); + } + + foreach ((uint resource, uint quantity) in HardcodedCharacterData.FallbackInventoryResources) + { + Console.WriteLine($"Add resource {resource} quant {quantity}"); + Inventory.AddResource(resource, quantity); + } + EnterZone(DataUtils.GetZone(zone)); } @@ -174,192 +189,8 @@ public void Respawn() NetChannels[ChannelType.ReliableGss].SendIAeroChanges(combatController, CharacterEntity.EntityId); // InventoryUpdate - // What are you doing here? - var inventoryUpdate = new InventoryUpdate - { - ClearExistingData = 1, - ItemsPart1Length = 4, - ItemsPart1 = new Item[] - { - new() - { - Unk1 = 0, - SdbId = 76331, - GUID = 744961712419132925ul, - SubInventory = 4, - TimestampEpoch = 0x22BEA256, - DynamicFlags = 0, - Durability = 0, - Unk3 = 0, - Unk4 = 0, - Unk5 = 1, - Unk6 = Array.Empty(), - Unk7 = 0, - Modules = Array.Empty() - }, - new() - { - Unk1 = 0, - SdbId = 76331, - GUID = 9181641073530142461ul, - SubInventory = 4, - TimestampEpoch = 0x964C1352, - DynamicFlags = 0, - Durability = 0, - Unk3 = 0, - Unk4 = 0, - Unk5 = 1, - Unk6 = Array.Empty(), - Unk7 = 0, - Modules = Array.Empty() - }, - new() - { - Unk1 = 0, - SdbId = 81423, // Glider - GUID = 9203082006052811773ul, - SubInventory = 2, - TimestampEpoch = 0x518973AE, - DynamicFlags = 0, - Durability = 0, - Unk3 = 0, - Unk4 = 0, - Unk5 = 1, - Unk6 = Array.Empty(), - Unk7 = 0, - Modules = Array.Empty() - }, - new() - { - Unk1 = 0, - SdbId = 77087, // LGV - GUID = 9168405683759816701ul, - SubInventory = 2, - TimestampEpoch = 0x582A0A04, - DynamicFlags = 0, - Durability = 0, - Unk3 = 0, - Unk4 = 0, - Unk5 = 1, - Unk6 = Array.Empty(), - Unk7 = 0, - Modules = Array.Empty() - } - }, - ItemsPart2Length = 0, - ItemsPart2 = Array.Empty(), - ItemsPart3Length = 0, - ItemsPart3 = Array.Empty(), - Resources = new Resource[] - { - new() - { - SdbId = 10, // Crystite - Quantity = 10000, - SubInventory = 1, - TextKey = string.Empty, - Unk2 = 0, - }, - new() - { - SdbId = 30101, // Credits - Quantity = 10000, - SubInventory = 1, - TextKey = string.Empty, - Unk2 = 0, - } - }, - Loadouts = HardcodedCharacterData.GetTempAvailableLoadouts(), - /* - new Loadout[] - { - new() - { - FrameLoadoutId = 184538131, - Unk = 1535539622, - LoadoutName = "ODM \"Mammoth\"", - LoadoutType = "battleframe", - ChassisID = 76331, - LoadoutConfigs = new LoadoutConfig[] - { - new() - { - ConfigID = 0, - ConfigName = "pve", - Items = Array.Empty(), - Visuals = new LoadoutConfig_Visual[] - { - new() - { - ItemSdbId = 10000, - VisualType = LoadoutConfig_Visual.LoadoutVisualType.Decal, - Data1 = 0, - Data2 = 4294967295, - Transform = new[] - { - 0.052F, 0.020F, 0.000F, 0.007F, -0.020F, -0.052F, 0.018F, -0.048F, 0.021F, 0.108F, -0.105F, 1.495F - } - }, - new() - { - ItemSdbId = 81423, - VisualType = LoadoutConfig_Visual.LoadoutVisualType.Glider, - Data1 = 0, - Data2 = 0, - Transform = Array.Empty() - }, - new() - { - ItemSdbId = 77087, - VisualType = LoadoutConfig_Visual.LoadoutVisualType.Vehicle, - Data1 = 0, - Data2 = 0, - Transform = Array.Empty() - }, - new() - { - ItemSdbId = 85163, - VisualType = LoadoutConfig_Visual.LoadoutVisualType.Palette, - Data1 = 0, - Data2 = 0, - Transform = Array.Empty() - }, - new() - { - ItemSdbId = 10022, - VisualType = LoadoutConfig_Visual.LoadoutVisualType.Pattern, - Data1 = 1, - Data2 = 0, - Transform = new[] { 0.000F, 13572.00F, 0.000F, 1963.000F } - } - }, - Perks = new uint[] { 85817, 85818, 85956, 85976, 86067, 86137, 86139, 118819, 124247, 140713 }, - Unk1 = 1464475061, // Did I... mess up the bandwidth? :thinking: - PerkBandwidth = 0, - PerkRespecLockRemainingSeconds = 0, - HaveExtraData = 0 - }, - new() - { - ConfigID = 1, - ConfigName = "pvp", - Items = Array.Empty(), - Visuals = Array.Empty(), - Perks = Array.Empty(), - Unk1 = 0, - PerkBandwidth = 0, - PerkRespecLockRemainingSeconds = 0, - HaveExtraData = 0 - } - } - } - }, - */ - Unk = 1, - SecondItems = Array.Empty(), - SecondResources = Array.Empty() - }; - NetChannels[ChannelType.ReliableGss].SendIAero(inventoryUpdate, CharacterEntity.EntityId); + Inventory.SendFullInventory(); + Inventory.EnablePartialUpdates = true; CharacterEntity.Alive = true; // Accept MovementInputs only after Respawn } diff --git a/UdpHosts/GameServer/Shard.cs b/UdpHosts/GameServer/Shard.cs index 8c5ec17b..814c73e6 100644 --- a/UdpHosts/GameServer/Shard.cs +++ b/UdpHosts/GameServer/Shard.cs @@ -6,6 +6,7 @@ using System.Threading; using System.Threading.Tasks; using GameServer.Aptitude; +using GameServer.Data; using GameServer.Entities; using Shared.Common; using Shared.Udp; @@ -126,6 +127,11 @@ public ushort AssignNewRefId(IEntity entity, Enums.GSS.Controllers controller) return unchecked(_lastEntityRefId++); } + public ulong GetNextGuid(byte type = (byte)Enums.GSS.Controllers.Generic) + { + return GuidService.GetNext(this, type); + } + protected virtual bool ShouldNetworkTick(double deltaTime, ulong currentTime) { return deltaTime >= NetworkTickRate; diff --git a/UdpHosts/GameServer/StaticDB/Loaders/ISDBLoader.cs b/UdpHosts/GameServer/StaticDB/Loaders/ISDBLoader.cs index 13383811..de404aa3 100644 --- a/UdpHosts/GameServer/StaticDB/Loaders/ISDBLoader.cs +++ b/UdpHosts/GameServer/StaticDB/Loaders/ISDBLoader.cs @@ -78,6 +78,8 @@ public interface ISDBLoader Dictionary LoadDeployableCalldownCommandDef(); Dictionary LoadFireProjectileCommandDef(); Dictionary LoadResourceNodeBeaconCalldownCommandDef(); + Dictionary LoadAttemptToCalldownVehicleCommandDef(); + Dictionary LoadVehicleCalldownCommandDef(); Dictionary LoadRegisterClientProximityCommandDef(); Dictionary LoadCombatFlagsCommandDef(); Dictionary LoadApplyFreezeCommandDef(); diff --git a/UdpHosts/GameServer/StaticDB/Loaders/StaticDBLoader.cs b/UdpHosts/GameServer/StaticDB/Loaders/StaticDBLoader.cs index 0ebc172f..8742f9a2 100644 --- a/UdpHosts/GameServer/StaticDB/Loaders/StaticDBLoader.cs +++ b/UdpHosts/GameServer/StaticDB/Loaders/StaticDBLoader.cs @@ -266,6 +266,12 @@ public Dictionary LoadDeployableCalldownComm .ToDictionary(row => row.Id); } + public Dictionary LoadVehicleCalldownCommandDef() + { + return LoadStaticDB("aptfs::VehicleCalldownCommandDef") + .ToDictionary(row => row.Id); + } + public Dictionary LoadFireProjectileCommandDef() { return LoadStaticDB("aptfs::FireProjectileCommandDef") @@ -278,6 +284,12 @@ public Dictionary LoadResourceNodeBe .ToDictionary(row => row.Id); } + public Dictionary LoadAttemptToCalldownVehicleCommandDef() + { + return LoadStaticDB("aptfs::AttemptToCalldownVehicleCommandDef") + .ToDictionary(row => row.Id); + } + public Dictionary LoadRegisterClientProximityCommandDef() { return LoadStaticDB("aptfs::RegisterClientProximityCommandDef") diff --git a/UdpHosts/GameServer/StaticDB/Records/dbitems/AbilityModule.cs b/UdpHosts/GameServer/StaticDB/Records/dbitems/AbilityModule.cs index 833fff78..9c7d4837 100644 --- a/UdpHosts/GameServer/StaticDB/Records/dbitems/AbilityModule.cs +++ b/UdpHosts/GameServer/StaticDB/Records/dbitems/AbilityModule.cs @@ -3,6 +3,10 @@ public record class AbilityModule { public uint InitialCooldownSec { get; set; } public uint ModuleType { get; set; } + + /// + /// AbilityChainId is the same thing as an AbilityId (Or maybe we misunderstand some terminology, but the point is still the same. This is not a chain id, look it up in apt::Ability to find the chain.) + /// public uint AbilityChainId { get; set; } public uint Id { get; set; } public byte ActivatableInPvp { get; set; } diff --git a/UdpHosts/GameServer/StaticDB/SDBInterface.cs b/UdpHosts/GameServer/StaticDB/SDBInterface.cs index 331faea3..5e524fdc 100644 --- a/UdpHosts/GameServer/StaticDB/SDBInterface.cs +++ b/UdpHosts/GameServer/StaticDB/SDBInterface.cs @@ -80,8 +80,10 @@ public class SDBInterface private static Dictionary ForcePushCommandDef; private static Dictionary ApplyImpulseCommandDef; private static Dictionary DeployableCalldownCommandDef; + private static Dictionary VehicleCalldownCommandDef; private static Dictionary FireProjectileCommandDef; private static Dictionary ResourceNodeBeaconCalldownCommandDef; + private static Dictionary AttemptToCalldownVehicleCommandDef; private static Dictionary RegisterClientProximityCommandDef; private static Dictionary CombatFlagsCommandDef; private static Dictionary ApplyFreezeCommandDef; @@ -221,6 +223,8 @@ public static void Init(StaticDB instance) DeployableCalldownCommandDef = loader.LoadDeployableCalldownCommandDef(); FireProjectileCommandDef = loader.LoadFireProjectileCommandDef(); ResourceNodeBeaconCalldownCommandDef = loader.LoadResourceNodeBeaconCalldownCommandDef(); + AttemptToCalldownVehicleCommandDef = loader.LoadAttemptToCalldownVehicleCommandDef(); + VehicleCalldownCommandDef = loader.LoadVehicleCalldownCommandDef(); RegisterClientProximityCommandDef = loader.LoadRegisterClientProximityCommandDef(); CombatFlagsCommandDef = loader.LoadCombatFlagsCommandDef(); ApplyFreezeCommandDef = loader.LoadApplyFreezeCommandDef(); @@ -317,6 +321,7 @@ public static Dictionary GetItemAttributeRange(uint item public static WarpaintPalette GetWarpaintPalette(uint id) => WarpaintPalettes.GetValueOrDefault(id); // dbitems + public static RootItem GetRootItem(uint id) => RootItem.GetValueOrDefault(id); public static AbilityModule GetAbilityModule(uint id) => AbilityModule.GetValueOrDefault(id); public static Battleframe GetBattleframe(uint id) => Battleframe.GetValueOrDefault(id); @@ -369,8 +374,10 @@ public static Dictionary GetItemAttributeRange(uint item public static ForcePushCommandDef GetForcePushCommandDef(uint id) => ForcePushCommandDef.GetValueOrDefault(id); public static ApplyImpulseCommandDef GetApplyImpulseCommandDef(uint id) => ApplyImpulseCommandDef.GetValueOrDefault(id); public static DeployableCalldownCommandDef GetDeployableCalldownCommandDef(uint id) => DeployableCalldownCommandDef.GetValueOrDefault(id); + public static VehicleCalldownCommandDef GetVehicleCalldownCommandDef(uint id) => VehicleCalldownCommandDef.GetValueOrDefault(id); public static FireProjectileCommandDef GetFireProjectileCommandDef(uint id) => FireProjectileCommandDef.GetValueOrDefault(id); public static ResourceNodeBeaconCalldownCommandDef GetResourceNodeBeaconCalldownCommandDef(uint id) => ResourceNodeBeaconCalldownCommandDef.GetValueOrDefault(id); + public static AttemptToCalldownVehicleCommandDef GetAttemptToCalldownVehicleCommandDef(uint id) => AttemptToCalldownVehicleCommandDef.GetValueOrDefault(id); public static RegisterClientProximityCommandDef GetRegisterClientProximityCommandDef(uint id) => RegisterClientProximityCommandDef.GetValueOrDefault(id); public static CombatFlagsCommandDef GetCombatFlagsCommandDef(uint id) => CombatFlagsCommandDef.GetValueOrDefault(id); public static ApplyFreezeCommandDef GetApplyFreezeCommandDef(uint id) => ApplyFreezeCommandDef.GetValueOrDefault(id); diff --git a/UdpHosts/GameServer/Systems/Admin/Commands/SpectateServerCommand.cs b/UdpHosts/GameServer/Systems/Admin/Commands/SpectateServerCommand.cs index 6a8623c2..b4f16ee7 100644 --- a/UdpHosts/GameServer/Systems/Admin/Commands/SpectateServerCommand.cs +++ b/UdpHosts/GameServer/Systems/Admin/Commands/SpectateServerCommand.cs @@ -1,6 +1,7 @@ namespace GameServer.Admin; -[ServerCommand("Toggle (hacky) spectator mode", "spectate", "flycam")] +// TODO: Not functioning as intended atm +//[ServerCommand("Toggle (hacky) spectator mode", "spectate", "flycam")] public class SpectateServerCommand : ServerCommand { public override void Execute(string[] parameters, ServerCommandContext context) diff --git a/UdpHosts/GameServer/Systems/Aptitude/AbilitySystem.cs b/UdpHosts/GameServer/Systems/Aptitude/AbilitySystem.cs index 5201a30f..0be724bb 100644 --- a/UdpHosts/GameServer/Systems/Aptitude/AbilitySystem.cs +++ b/UdpHosts/GameServer/Systems/Aptitude/AbilitySystem.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Threading; +using AeroMessages.GSS.V66.Character.Command; using GameServer.Data.SDB; using GameServer.Enums; @@ -10,6 +11,9 @@ public class AbilitySystem { public Factory Factory; private Shard Shard; + private Dictionary PlayerVehicleCalldownRequests; + private Dictionary PlayerDeployableCalldownRequests; + private Dictionary PlayerThumperCalldownRequests; private ulong LastUpdate = 0; private ulong UpdateIntervalMs = 20; @@ -18,6 +22,9 @@ public AbilitySystem(Shard shard) { Shard = shard; Factory = new Factory(); + PlayerVehicleCalldownRequests = new(); + PlayerDeployableCalldownRequests = new(); + PlayerThumperCalldownRequests = new(); } public static float RegistryOp(float first, float second, Operand op) @@ -137,19 +144,73 @@ public void DoRemoveEffect(IAptitudeTarget entity, uint effectId) } } - public void HandleVehicleCalldownRequest() + public VehicleCalldownRequest TryConsumeVehicleCalldownRequest(ulong entityId) { - throw new NotImplementedException(); + if (PlayerVehicleCalldownRequests.ContainsKey(entityId)) + { + var result = PlayerVehicleCalldownRequests[entityId]; + PlayerVehicleCalldownRequests.Remove(entityId); + return result; + } + + return null; } - public void HandleDeployableCalldownRequest() + public DeployableCalldownRequest TryConsumeDeployableCalldownRequest(ulong entityId) { - throw new NotImplementedException(); + if (PlayerDeployableCalldownRequests.ContainsKey(entityId)) + { + var result = PlayerDeployableCalldownRequests[entityId]; + PlayerDeployableCalldownRequests.Remove(entityId); + return result; + } + + return null; } - public void HandleResourceNodeBeaconCalldownRequest() + public ResourceNodeBeaconCalldownRequest TryConsumeResourceNodeBeaconCalldownRequest(ulong entityId) { - throw new NotImplementedException(); + if (PlayerThumperCalldownRequests.ContainsKey(entityId)) + { + var result = PlayerThumperCalldownRequests[entityId]; + PlayerThumperCalldownRequests.Remove(entityId); + return result; + } + + return null; + } + + public void HandleVehicleCalldownRequest(ulong entityId, VehicleCalldownRequest request) + { + if (PlayerVehicleCalldownRequests.ContainsKey(entityId)) + { + Console.WriteLine($"Discarded an unconsumed vehicle calldown request"); + PlayerVehicleCalldownRequests.Remove(entityId); + } + + PlayerVehicleCalldownRequests.Add(entityId, request); + } + + public void HandleDeployableCalldownRequest(ulong entityId, DeployableCalldownRequest request) + { + if (PlayerDeployableCalldownRequests.ContainsKey(entityId)) + { + Console.WriteLine($"Discarded an unconsumed deployable calldown request"); + PlayerDeployableCalldownRequests.Remove(entityId); + } + + PlayerDeployableCalldownRequests.Add(entityId, request); + } + + public void HandleResourceNodeBeaconCalldownRequest(ulong entityId, ResourceNodeBeaconCalldownRequest request) + { + if (PlayerThumperCalldownRequests.ContainsKey(entityId)) + { + Console.WriteLine($"Discarded an unconsumed thumper calldown request"); + PlayerThumperCalldownRequests.Remove(entityId); + } + + PlayerThumperCalldownRequests.Add(entityId, request); } public void HandleLocalProximityAbilitySuccess(IShard shard, IAptitudeTarget source, uint commandId, uint time, HashSet targets) diff --git a/UdpHosts/GameServer/Systems/Aptitude/Commands/Calldown/AttemptToCalldownVehicleCommand.cs b/UdpHosts/GameServer/Systems/Aptitude/Commands/Calldown/AttemptToCalldownVehicleCommand.cs new file mode 100644 index 00000000..18733925 --- /dev/null +++ b/UdpHosts/GameServer/Systems/Aptitude/Commands/Calldown/AttemptToCalldownVehicleCommand.cs @@ -0,0 +1,45 @@ +using GameServer.Data.SDB.Records.aptfs; +using GameServer.Entities.Character; +using System.Numerics; + +namespace GameServer.Aptitude; + +public class AttemptToCalldownVehicleCommand : ICommand +{ + private AttemptToCalldownVehicleCommandDef Params; + + public AttemptToCalldownVehicleCommand(AttemptToCalldownVehicleCommandDef par) + { + Params = par; + } + + public bool Execute(Context context) + { + var caller = context.Self; + + var request = context.Abilities.TryConsumeVehicleCalldownRequest(caller.EntityId); + if (request != null) + { + var entityMan = context.Shard.EntityMan; + var typeId = request.VehicleID; + var position = request.Position; + var orientation = request.Rotation; + entityMan.SpawnVehicle(typeId, position, orientation, (Entities.IEntity)caller); + return true; + } + else + { + return false; + + // Atlernate approach spawning without a request + /* + var entityMan = context.Shard.EntityMan; + var typeId = Params.VehicleType; + var position = (caller as CharacterEntity).Position; + var orientation = Quaternion.Identity; + entityMan.SpawnVehicle(typeId, position, orientation, (Entities.IEntity)caller); + return true; + */ + } + } +} \ No newline at end of file diff --git a/UdpHosts/GameServer/Systems/Aptitude/Commands/Calldown/DeployableCalldownCommand.cs b/UdpHosts/GameServer/Systems/Aptitude/Commands/Calldown/DeployableCalldownCommand.cs new file mode 100644 index 00000000..7f9817af --- /dev/null +++ b/UdpHosts/GameServer/Systems/Aptitude/Commands/Calldown/DeployableCalldownCommand.cs @@ -0,0 +1,34 @@ +using GameServer.Data.SDB.Records.aptfs; + +namespace GameServer.Aptitude; + +public class DeployableCalldownCommand : ICommand +{ + private DeployableCalldownCommandDef Params; + + public DeployableCalldownCommand(DeployableCalldownCommandDef par) + { + Params = par; + } + + public bool Execute(Context context) + { + var caller = context.Self; + var request = context.Abilities.TryConsumeDeployableCalldownRequest(caller.EntityId); + if (request != null) + { + var entityMan = context.Shard.EntityMan; + var typeId = Params.DeployableType; + var position = request.Position; + var orientation = request.Rotation; + entityMan.SpawnDeployable(typeId, position, orientation); + + // TODO: Set owner? + return true; + } + else + { + return false; + } + } +} \ No newline at end of file diff --git a/UdpHosts/GameServer/Systems/Aptitude/Commands/Calldown/ResourceNodeBeaconCalldownCommand.cs b/UdpHosts/GameServer/Systems/Aptitude/Commands/Calldown/ResourceNodeBeaconCalldownCommand.cs new file mode 100644 index 00000000..aa90a9a3 --- /dev/null +++ b/UdpHosts/GameServer/Systems/Aptitude/Commands/Calldown/ResourceNodeBeaconCalldownCommand.cs @@ -0,0 +1,32 @@ +using GameServer.Data.SDB.Records.aptfs; + +namespace GameServer.Aptitude; + +public class ResourceNodeBeaconCalldownCommand : ICommand +{ + private ResourceNodeBeaconCalldownCommandDef Params; + + public ResourceNodeBeaconCalldownCommand(ResourceNodeBeaconCalldownCommandDef par) + { + Params = par; + } + + public bool Execute(Context context) + { + var caller = context.Self; + var request = context.Abilities.TryConsumeResourceNodeBeaconCalldownRequest(caller.EntityId); + if (request != null) + { + var entityMan = context.Shard.EntityMan; + uint nodeType = 20; // TODO: Figure out how to use and determine these + var beaconType = Params.ResourceNodeBeaconId; + var position = request.Position; + entityMan.SpawnThumper(nodeType, beaconType, position); + return true; + } + else + { + return false; + } + } +} \ No newline at end of file diff --git a/UdpHosts/GameServer/Systems/Aptitude/Commands/Calldown/VehicleCalldownCommand.cs b/UdpHosts/GameServer/Systems/Aptitude/Commands/Calldown/VehicleCalldownCommand.cs new file mode 100644 index 00000000..eb0d836d --- /dev/null +++ b/UdpHosts/GameServer/Systems/Aptitude/Commands/Calldown/VehicleCalldownCommand.cs @@ -0,0 +1,32 @@ +using GameServer.Data.SDB.Records.aptfs; + +namespace GameServer.Aptitude; + +public class VehicleCalldownCommand : ICommand +{ + private VehicleCalldownCommandDef Params; + + public VehicleCalldownCommand(VehicleCalldownCommandDef par) + { + Params = par; + } + + public bool Execute(Context context) + { + var caller = context.Self; + var request = context.Abilities.TryConsumeVehicleCalldownRequest(caller.EntityId); + if (request != null) + { + var entityMan = context.Shard.EntityMan; + var typeId = request.VehicleID; + var position = request.Position; + var orientation = request.Rotation; + entityMan.SpawnVehicle(typeId, position, orientation, (Entities.IEntity)caller); + return true; + } + else + { + return false; + } + } +} \ No newline at end of file diff --git a/UdpHosts/GameServer/Systems/Aptitude/Factory.cs b/UdpHosts/GameServer/Systems/Aptitude/Factory.cs index 1f6ef58e..b60c121e 100644 --- a/UdpHosts/GameServer/Systems/Aptitude/Factory.cs +++ b/UdpHosts/GameServer/Systems/Aptitude/Factory.cs @@ -150,6 +150,14 @@ public ICommand LoadCommand(uint commandId, uint typeId) return new OrientationLockCommand(SDBInterface.GetOrientationLockCommandDef(commandId)); case CommandType.ApplyFreeze: return new ApplyFreezeCommand(SDBInterface.GetApplyFreezeCommandDef(commandId)); + case CommandType.VehicleCalldown: + return new VehicleCalldownCommand(SDBInterface.GetVehicleCalldownCommandDef(commandId)); + case CommandType.DeployableCalldown: + return new DeployableCalldownCommand(SDBInterface.GetDeployableCalldownCommandDef(commandId)); + case CommandType.ResourceNodeBeaconCalldown: + return new ResourceNodeBeaconCalldownCommand(SDBInterface.GetResourceNodeBeaconCalldownCommandDef(commandId)); + case CommandType.AttemptToCalldownVehicle: + return new AttemptToCalldownVehicleCommand(SDBInterface.GetAttemptToCalldownVehicleCommandDef(commandId)); default: break; } diff --git a/UdpHosts/GameServer/Systems/EntityManager/EntityManager.cs b/UdpHosts/GameServer/Systems/EntityManager/EntityManager.cs index 2e852c30..e3c53a97 100644 --- a/UdpHosts/GameServer/Systems/EntityManager/EntityManager.cs +++ b/UdpHosts/GameServer/Systems/EntityManager/EntityManager.cs @@ -60,7 +60,7 @@ public int GetNumberOfScopedEntities(IPlayer player) public void SpawnCharacter(uint typeId, Vector3 position) { - var characterEntity = new CharacterEntity(Shard, GetNextGuid() & 0xffffffffffffff00); + var characterEntity = new CharacterEntity(Shard, Shard.GetNextGuid()); characterEntity.LoadMonster(typeId); characterEntity.SetCharacterState(CharacterStateData.CharacterStatus.Living, Shard.CurrentTime); characterEntity.SetPosition(position); @@ -71,7 +71,7 @@ public void SpawnCharacter(uint typeId, Vector3 position) public void SpawnVehicle(ushort typeId, Vector3 position, Quaternion orientation, IEntity owner, bool autoMount = false) { var vehicleInfo = SDBUtils.GetDetailedVehicleInfo(typeId); - var vehicleEntity = new VehicleEntity(Shard, GetNextGuid() & 0xffffffffffffff00); + var vehicleEntity = new VehicleEntity(Shard, Shard.GetNextGuid()); vehicleEntity.Load(vehicleInfo); position.Z += vehicleInfo.SpawnHeight; vehicleEntity.SetSpawnPose(new AeroMessages.GSS.V66.Vehicle.Controller.SpawnPoseData() @@ -120,7 +120,7 @@ public void SpawnVehicle(ushort typeId, Vector3 position, Quaternion orientation public void SpawnDeployable(uint typeId, Vector3 position, Quaternion orientation) { var deployableInfo = SDBInterface.GetDeployable(typeId); - var deployableEntity = new DeployableEntity(Shard, GetNextGuid() & 0xffffffffffffff00, typeId, 0); + var deployableEntity = new DeployableEntity(Shard, Shard.GetNextGuid(), typeId, 0); var aimDirection = new Vector3(deployableInfo.AimDirection.x, deployableInfo.AimDirection.y, deployableInfo.AimDirection.z); deployableEntity.SetPosition(position); deployableEntity.SetOrientation(orientation); @@ -184,27 +184,27 @@ public void SpawnDeployable(uint typeId, Vector3 position, Quaternion orientatio public void SpawnMelding(string perimiterSetName, ActiveDataStruct activeData) { - var meldingEntity = new MeldingEntity(Shard, GetNextGuid() & 0xffffffffffffff00, perimiterSetName); + var meldingEntity = new MeldingEntity(Shard, Shard.GetNextGuid(), perimiterSetName); meldingEntity.SetActiveData(activeData); Add(meldingEntity.EntityId, meldingEntity); } public void SpawnOutpost(Outpost outpost) { - var outpostEntity = new OutpostEntity(Shard, GetNextGuid() & 0xffffffffffffff00, outpost); + var outpostEntity = new OutpostEntity(Shard, Shard.GetNextGuid(), outpost); Add(outpostEntity.EntityId, outpostEntity); } public void SpawnThumper(uint nodeType, uint beaconType, Vector3 position) { - var thumperEntity = new ThumperEntity(Shard, GetNextGuid() & 0xffffffffffffff00, nodeType, beaconType); + var thumperEntity = new ThumperEntity(Shard, Shard.GetNextGuid(), nodeType, beaconType); thumperEntity.SetPosition(position); Add(thumperEntity.EntityId, thumperEntity); } public void SpawnCarryable(uint type, Vector3 position) { - var carryableEntity = new CarryableEntity(Shard, GetNextGuid() & 0xffffffffffffff00, type); + var carryableEntity = new CarryableEntity(Shard, Shard.GetNextGuid(), type); carryableEntity.SetPosition(position); Add(carryableEntity.EntityId, carryableEntity); } @@ -359,11 +359,6 @@ public void Tick(double deltaTime, ulong currentTime, CancellationToken ct) } } - public ulong GetNextGuid() - { - return new Core.Data.EntityGuid(ServerId, Shard.CurrentTime, Counter++, (byte)Enums.GSS.Controllers.Character).Full; - } - public void Add(ulong guid, IEntity entity) { ScopedPlayersByEntity.Add(guid, new());