diff --git a/Arrowgene.Ddon.Database/IDatabase.cs b/Arrowgene.Ddon.Database/IDatabase.cs index 16d9929c..690abc77 100644 --- a/Arrowgene.Ddon.Database/IDatabase.cs +++ b/Arrowgene.Ddon.Database/IDatabase.cs @@ -92,7 +92,7 @@ public interface IDatabase bool InsertEquipItem(uint commonId, JobId job, EquipType equipType, byte equipSlot, string itemUId); bool ReplaceEquipItem(uint commonId, JobId job, EquipType equipType, byte equipSlot, string itemUId); bool UpdateEquipItem(uint commonId, JobId job, EquipType equipType, byte equipSlot, string itemUId); - bool DeleteEquipItem(uint commonId, JobId job, EquipType equipType, byte equipSlot, string itemUId); + bool DeleteEquipItem(uint commonId, JobId job, EquipType equipType, byte equipSlot); // Job Items bool InsertEquipJobItem(string itemUId, uint commonId, JobId job, ushort slotNo); diff --git a/Arrowgene.Ddon.Database/Sql/Core/DdonSqlDbEquipItem.cs b/Arrowgene.Ddon.Database/Sql/Core/DdonSqlDbEquipItem.cs index e6442357..f318a508 100644 --- a/Arrowgene.Ddon.Database/Sql/Core/DdonSqlDbEquipItem.cs +++ b/Arrowgene.Ddon.Database/Sql/Core/DdonSqlDbEquipItem.cs @@ -1,5 +1,4 @@ using System.Data.Common; -using Arrowgene.Ddon.Shared.Entity.Structure; using Arrowgene.Ddon.Shared.Model; namespace Arrowgene.Ddon.Database.Sql.Core @@ -18,7 +17,7 @@ public abstract partial class DdonSqlDb : SqlDb { - AddParameter(command, commonId, job, equipType, equipSlot, itemUId); + AddParameter(command, commonId, job, equipType, equipSlot); }) == 1; } - private void AddParameter(TCom command, uint commonId, JobId job, EquipType equipType, byte equipSlot, string itemUId) + private void AddParameter(TCom command, uint commonId, JobId job, EquipType equipType, byte equipSlot) { - AddParameter(command, "item_uid", itemUId); AddParameter(command, "character_common_id", commonId); AddParameter(command, "job", (byte) job); AddParameter(command, "equip_type", (byte) equipType); AddParameter(command, "equip_slot", equipSlot); } + + private void AddParameter(TCom command, uint commonId, JobId job, EquipType equipType, byte equipSlot, string itemUId) + { + AddParameter(command, "item_uid", itemUId); + AddParameter(command, commonId, job, equipType, equipSlot); + } } } diff --git a/Arrowgene.Ddon.GameServer/Characters/EquipManager.cs b/Arrowgene.Ddon.GameServer/Characters/EquipManager.cs index 525c9e29..49e0dc80 100644 --- a/Arrowgene.Ddon.GameServer/Characters/EquipManager.cs +++ b/Arrowgene.Ddon.GameServer/Characters/EquipManager.cs @@ -79,17 +79,27 @@ public void HandleChangeEquipList(DdonGameServer server, GameClient client, Char string itemUId = changeCharacterEquipInfo.EquipItemUId; EquipType equipType = (EquipType) changeCharacterEquipInfo.EquipType; byte equipSlot = changeCharacterEquipInfo.EquipCategory; + ushort storageSlot = equipSlot; + + if(equipType == EquipType.Visual) + { + storageSlot += Equipment.TOTAL_EQUIP_SLOTS; + } uint characterId, pawnId; + StorageType equipmentStorageType; if(characterToEquipTo is Character character1) { characterId = character1.CharacterId; pawnId = 0; + equipmentStorageType = StorageType.CharacterEquipment; } else if(characterToEquipTo is Pawn pawn) { characterId = pawn.CharacterId; pawnId = pawn.PawnId; + equipmentStorageType = StorageType.PawnEquipment; + storageSlot = (ushort)(storageSlot + client.Character.Pawns.IndexOf(pawn)*Equipment.TOTAL_EQUIP_SLOTS*2); } else { @@ -98,11 +108,26 @@ public void HandleChangeEquipList(DdonGameServer server, GameClient client, Char if(itemUId.Length == 0) { - this.UnequipItem(server, client, characterToEquipTo, updateCharacterItemNtc, equipType, equipSlot, storageTypes, characterId, pawnId); + // Unequip + // TODO: Move to the other storage types if the first one is full + StorageType destinationStorageType = storageTypes[0]; + Item? equippedItem = characterToEquipTo.Equipment.SetEquipItem(null, characterToEquipTo.Job, equipType, equipSlot); + if(equippedItem == null) + { + throw new ResponseErrorException(ErrorCode.ERROR_CODE_ITEM_NOT_FOUND); + } + server.Database.DeleteEquipItem(characterToEquipTo.CommonId, characterToEquipTo.Job, equipType, equipSlot); + // Update storage + updateCharacterItemNtc.UpdateItemList.AddRange(server.ItemManager.MoveItem(server, client.Character, equipmentStorageType, equippedItem.UId, 1, destinationStorageType, 0)); } else { - this.EquipItem(server, client, characterToEquipTo, updateCharacterItemNtc, equipType, equipSlot, storageTypes, itemUId, characterId, pawnId); + // Equip + StorageType sourceStorageType = storageTypes[0]; + characterToEquipTo.Equipment.SetEquipItem(server.Database.SelectItem(itemUId), characterToEquipTo.Job, equipType, equipSlot); + server.Database.ReplaceEquipItem(characterToEquipTo.CommonId, characterToEquipTo.Job, equipType, equipSlot, itemUId); + // Update storage + updateCharacterItemNtc.UpdateItemList.AddRange(server.ItemManager.MoveItem(server, client.Character, sourceStorageType, itemUId, 1, equipmentStorageType, storageSlot)); } } @@ -142,199 +167,6 @@ public void HandleChangeEquipList(DdonGameServer server, GameClient client, Char } client.Send(updateCharacterItemNtc); - } - - private void UnequipItem(DdonGameServer server, GameClient client, CharacterCommon characterToEquipTo, S2CItemUpdateCharacterItemNtc updateCharacterItemNtc, EquipType equipType, byte equipSlot, List storageTypes, uint characterId, uint pawnId) - { - // TODO: Move to the other storage types if the first one is full - StorageType storageType = storageTypes[0]; - - // Find in equipment the item to unequip - Item item = characterToEquipTo.Equipment.GetEquipItem(characterToEquipTo.Job, equipType, equipSlot) ?? throw new Exception("No item found in this slot"); - - characterToEquipTo.Equipment.SetEquipItem(null, characterToEquipTo.Job, equipType, equipSlot); - server.Database.DeleteEquipItem(characterToEquipTo.CommonId, characterToEquipTo.Job, equipType, equipSlot, item.UId); - - ushort dstSlotNo = client.Character.Storage.addStorageItem(item, 1, storageType); - server.Database.InsertStorageItem(client.Character.CharacterId, storageType, dstSlotNo, item.UId, 1); - - updateCharacterItemNtc.UpdateItemList.Add(new CDataItemUpdateResult() { - UpdateItemNum = 0, - ItemList = new CDataItemList() { - ItemUId = item.UId, - ItemId = item.ItemId, - ItemNum = 0, - Unk3 = item.Unk3, - StorageType = StorageType.Unk14, - SlotNo = 1, - Color = item.Color, - PlusValue = item.PlusValue, - Bind = true, - EquipPoint = 0, - EquipCharacterID = characterId, - EquipPawnID = pawnId, - WeaponCrestDataList = item.WeaponCrestDataList, - ArmorCrestDataList = item.ArmorCrestDataList, - EquipElementParamList = item.EquipElementParamList - } - }); - updateCharacterItemNtc.UpdateItemList.Add(new CDataItemUpdateResult() { - UpdateItemNum = 1, - ItemList = new CDataItemList() { - ItemUId = item.UId, - ItemId = item.ItemId, - ItemNum = 1, - Unk3 = item.Unk3, - StorageType = storageType, - SlotNo = dstSlotNo, - Color = item.Color, - PlusValue = item.PlusValue, - Bind = true, - EquipPoint = 0, - EquipCharacterID = 0, - EquipPawnID = 0, - WeaponCrestDataList = item.WeaponCrestDataList, - ArmorCrestDataList = item.ArmorCrestDataList, - EquipElementParamList = item.EquipElementParamList - } - }); - } - - private void EquipItem(DdonGameServer server, GameClient client, CharacterCommon characterToEquipTo, S2CItemUpdateCharacterItemNtc updateCharacterItemNtc, EquipType equipType, byte equipSlot, List storageTypes, string itemUId, uint characterId, uint pawnId) - { - Item? previouslyEquippedItem = characterToEquipTo.Equipment.GetEquipItem(characterToEquipTo.Job, equipType, equipSlot); - if (previouslyEquippedItem?.UId == itemUId) - { - // Don't do anything - return; - } - - // Find in the storages the item to equip - Item? itemToEquip = null; - uint itemToEquipNum = 0; - ushort storageSlotNo = 0; - StorageType storageType = 0; - foreach (StorageType storageTypeToCheck in storageTypes) - { - try - { - var tuple = client.Character.Storage.getStorage(storageTypeToCheck).Items - .Select((item, index) => new { item, slot = (ushort) (index+1)}) - .Where(tuple => tuple.item?.Item1.UId == itemUId) - .First(); - itemToEquip = tuple.item!.Item1; - itemToEquipNum = tuple.item.Item2; - storageSlotNo = tuple.slot; - storageType = storageTypeToCheck; - break; - } - catch(InvalidOperationException) - { - // Do nothing, continue and try other storage - } - } - - if (itemToEquip == null) - { - throw new ResponseErrorException(ErrorCode.ERROR_CODE_ITEM_NOT_FOUND, "Couldn't find the item to equip"); - } - - characterToEquipTo.Equipment.SetEquipItem(itemToEquip, characterToEquipTo.Job, equipType, equipSlot); - - server.Database.ReplaceEquipItem(characterToEquipTo.CommonId, characterToEquipTo.Job, equipType, equipSlot, itemToEquip.UId); - - if(previouslyEquippedItem != null) - { - // When equipping over an already equipped slot, move item in that slot to storage - client.Character.Storage.setStorageItem(previouslyEquippedItem, 1, storageType, storageSlotNo); - server.Database.ReplaceStorageItem(client.Character.CharacterId, storageType, storageSlotNo, previouslyEquippedItem.UId, 1); - updateCharacterItemNtc.UpdateItemList.Add(new CDataItemUpdateResult() { - UpdateItemNum = 0, - ItemList = new CDataItemList() { - ItemUId = previouslyEquippedItem.UId, - ItemId = previouslyEquippedItem.ItemId, - ItemNum = 0, - Unk3 = previouslyEquippedItem.Unk3, - StorageType = StorageType.Unk14, - SlotNo = 1, - Color = previouslyEquippedItem.Color, - PlusValue = previouslyEquippedItem.PlusValue, - Bind = true, - EquipPoint = 0, - EquipCharacterID = characterId, - EquipPawnID = pawnId, - WeaponCrestDataList = previouslyEquippedItem.WeaponCrestDataList, - ArmorCrestDataList = previouslyEquippedItem.ArmorCrestDataList, - EquipElementParamList = previouslyEquippedItem.EquipElementParamList - } - }); - updateCharacterItemNtc.UpdateItemList.Add(new CDataItemUpdateResult() { - UpdateItemNum = 1, - ItemList = new CDataItemList() { - ItemUId = previouslyEquippedItem.UId, - ItemId = previouslyEquippedItem.ItemId, - ItemNum = 1, - Unk3 = previouslyEquippedItem.Unk3, - StorageType = storageType, - SlotNo = storageSlotNo, - Color = previouslyEquippedItem.Color, - PlusValue = previouslyEquippedItem.PlusValue, - Bind = true, - EquipPoint = 0, - EquipCharacterID = 0, - EquipPawnID = 0, - WeaponCrestDataList = previouslyEquippedItem.WeaponCrestDataList, - ArmorCrestDataList = previouslyEquippedItem.ArmorCrestDataList, - EquipElementParamList = previouslyEquippedItem.EquipElementParamList - } - }); - } - else - { - client.Character.Storage.setStorageItem(null, 0, storageType, storageSlotNo); - server.Database.DeleteStorageItem(client.Character.CharacterId, storageType, storageSlotNo); - } - - updateCharacterItemNtc.UpdateItemList.Add(new CDataItemUpdateResult() { - UpdateItemNum = 0, // TODO: ? - ItemList = new CDataItemList() { - ItemUId = itemToEquip.UId, - ItemId = itemToEquip.ItemId, - ItemNum = 0, - Unk3 = itemToEquip.Unk3, - StorageType = storageType, - SlotNo = storageSlotNo, - Color = itemToEquip.Color, - PlusValue = itemToEquip.PlusValue, - Bind = true, - EquipPoint = 0, - EquipCharacterID = characterId, - EquipPawnID = pawnId, - WeaponCrestDataList = itemToEquip.WeaponCrestDataList, - ArmorCrestDataList = itemToEquip.ArmorCrestDataList, - EquipElementParamList = itemToEquip.EquipElementParamList - } - }); - updateCharacterItemNtc.UpdateItemList.Add(new CDataItemUpdateResult() { - UpdateItemNum = 1, - ItemList = new CDataItemList() { - ItemUId = itemToEquip.UId, - ItemId = itemToEquip.ItemId, - ItemNum = 1, - Unk3 = itemToEquip.Unk3, - StorageType = StorageType.Unk14, - SlotNo = 1, - Color = itemToEquip.Color, - PlusValue = itemToEquip.PlusValue, - Bind = true, - EquipPoint = 0, - EquipCharacterID = characterId, - EquipPawnID = pawnId, - WeaponCrestDataList = itemToEquip.WeaponCrestDataList, - ArmorCrestDataList = itemToEquip.ArmorCrestDataList, - EquipElementParamList = itemToEquip.EquipElementParamList - } - }); - } + } } } diff --git a/Arrowgene.Ddon.GameServer/Characters/JobManager.cs b/Arrowgene.Ddon.GameServer/Characters/JobManager.cs index 239c6461..5d36e88b 100644 --- a/Arrowgene.Ddon.GameServer/Characters/JobManager.cs +++ b/Arrowgene.Ddon.GameServer/Characters/JobManager.cs @@ -1,16 +1,13 @@ using System; using System.Collections.Generic; -using System.ComponentModel.Design; using System.Linq; using Arrowgene.Ddon.Database; -using Arrowgene.Ddon.Database.Model; using Arrowgene.Ddon.GameServer.Handler; using Arrowgene.Ddon.Server; using Arrowgene.Ddon.Shared; using Arrowgene.Ddon.Shared.Entity.PacketStructure; using Arrowgene.Ddon.Shared.Entity.Structure; using Arrowgene.Ddon.Shared.Model; -using Arrowgene.Ddon.Shared.Model.Quest; using Arrowgene.Logging; namespace Arrowgene.Ddon.GameServer.Characters @@ -18,18 +15,43 @@ namespace Arrowgene.Ddon.GameServer.Characters public class JobManager { private static readonly ServerLogger Logger = LogProvider.Logger(typeof(JobManager)); - private readonly IDatabase _Database; + private readonly DdonGameServer _Server; - public JobManager(IDatabase database) + public JobManager(DdonGameServer server) { - _Database = database; + _Server = server; } - public void SetJob(DdonServer server, GameClient client, CharacterCommon common, JobId jobId) + public void SetJob(GameClient client, CharacterCommon common, JobId jobId) { + // TODO: Reject job change if there's no primary and secondary weapon for the new job in storage + + JobId oldJobId = common.Job; common.Job = jobId; - server.Database.UpdateCharacterCommonBaseInfo(common); + // Swap equipment + int pawnIdx; + StorageType equipmentStorageType; + S2CItemUpdateCharacterItemNtc updateCharacterItemNtc = new S2CItemUpdateCharacterItemNtc(); + if (common is Character) + { + pawnIdx = 0; + equipmentStorageType = StorageType.CharacterEquipment; + updateCharacterItemNtc.UpdateType = (ushort) ItemNoticeType.ChangeJob; + } + else if (common is Pawn) + { + pawnIdx = client.Character.Pawns.IndexOf((Pawn)common); + equipmentStorageType = StorageType.PawnEquipment; + updateCharacterItemNtc.UpdateType = (ushort) ItemNoticeType.ChangePawnJob; + } + else + { + throw new Exception("Unknown character type"); + } + updateCharacterItemNtc.UpdateItemList.AddRange(SwapEquipmentAndStorage(client, common, pawnIdx, equipmentStorageType, oldJobId, jobId, EquipType.Performance)); + updateCharacterItemNtc.UpdateItemList.AddRange(SwapEquipmentAndStorage(client, common, pawnIdx, equipmentStorageType, oldJobId, jobId, EquipType.Visual)); + client.Send(updateCharacterItemNtc); CDataCharacterJobData? activeCharacterJobData = common.ActiveCharacterJobData; @@ -42,7 +64,7 @@ public void SetJob(DdonServer server, GameClient client, CharacterCo activeCharacterJobData.Lv = 1; // TODO: All the other stats common.CharacterJobDataList.Add(activeCharacterJobData); - server.Database.ReplaceCharacterJobData(common.CommonId, activeCharacterJobData); + _Server.Database.ReplaceCharacterJobData(common.CommonId, activeCharacterJobData); } // TODO: Figure out if it should send all equips or just the ones for the current job @@ -67,9 +89,6 @@ public void SetJob(DdonServer server, GameClient client, CharacterCo .ToList(); List jobItems = common.Equipment.getJobItemsAsCDataEquipJobItem(common.Job); - S2CItemUpdateCharacterItemNtc updateCharacterItemNtc = new S2CItemUpdateCharacterItemNtc(); - // TODO: Move previous job equipment to storage box, and move new job equipment from storage box - if (common is Character) { Character character = (Character)common; @@ -84,14 +103,11 @@ public void SetJob(DdonServer server, GameClient client, CharacterCo changeJobNotice.EquipJobItemList = jobItems; // TODO: Unk0 - foreach (GameClient otherClient in server.ClientLookup.GetAll()) + foreach (GameClient otherClient in _Server.ClientLookup.GetAll()) { otherClient.Send(changeJobNotice); } - updateCharacterItemNtc.UpdateType = 0x28; - client.Send(updateCharacterItemNtc); - S2CJobChangeJobRes changeJobResponse = new S2CJobChangeJobRes(); changeJobResponse.CharacterJobData = activeCharacterJobData; changeJobResponse.CharacterEquipList = characterEquipList; @@ -122,14 +138,11 @@ public void SetJob(DdonServer server, GameClient client, CharacterCo changeJobNotice.LearnNormalSkillParamList = normalSkills; changeJobNotice.EquipJobItemList = jobItems; // TODO: Unk0 - foreach (GameClient otherClient in server.ClientLookup.GetAll()) + foreach (GameClient otherClient in _Server.ClientLookup.GetAll()) { otherClient.Send(changeJobNotice); } - updateCharacterItemNtc.UpdateType = 0x29; - client.Send(updateCharacterItemNtc); - S2CJobChangePawnJobRes changeJobResponse = new S2CJobChangePawnJobRes(); changeJobResponse.PawnId = pawn.PawnId; changeJobResponse.CharacterJobData = activeCharacterJobData; @@ -150,6 +163,76 @@ public void SetJob(DdonServer server, GameClient client, CharacterCo } } + private List SwapEquipmentAndStorage(GameClient client, CharacterCommon common, int pawnIdx, StorageType equipmentStorageType, JobId oldJobId, JobId newJobId, EquipType equipType) + { + // TODO: Run in a transaction + + int equipmentStorageSlotOffset = pawnIdx * Equipment.TOTAL_EQUIP_SLOTS * 2; + if(equipType == EquipType.Visual) + { + equipmentStorageSlotOffset += Equipment.TOTAL_EQUIP_SLOTS; + } + + List itemUpdateResultList = new List(); + List oldEquipment = common.Equipment.GetEquipment(oldJobId, equipType); + List equipment = common.Equipment.GetEquipment(newJobId, equipType); + for (int i = 0; i < equipment.Count; i++) + { + ushort equipSlot = (ushort)(i+1); + ushort equipmentStorageSlot = (ushort)(equipSlot + equipmentStorageSlotOffset); + Item? oldEquippedItem = oldEquipment[i]; + Item? equippedItem = equipment[i]; + if(oldEquippedItem != null && equippedItem == null) + { + // Unequip item from an empty slot + // TODO: Attempt moving into other storages if the storage box is full + try + { + List moveResult = _Server.ItemManager.MoveItem(_Server, client.Character, equipmentStorageType, oldEquippedItem.UId, 1, StorageType.StorageBoxNormal, 0); + itemUpdateResultList.AddRange(moveResult); + } + catch (InvalidOperationException) + { + // Handle the item not being in equipment storage + // This should probably return an error response instead? Logging and handling gracefully prevents messy situations, but may be undesirable + Logger.Error($"Failed to unequip item {oldEquippedItem.UId} from {equipType} slot {equipSlot} of {oldJobId}. The item wasn't in the {equipmentStorageType} slot {equipmentStorageSlot}"); + common.Equipment.SetEquipItem(null, oldJobId, equipType, (byte) equipSlot); + _Server.Database.DeleteEquipItem(common.CommonId, oldJobId, equipType, (byte) equipSlot); + } + } + else if (equippedItem != null && equippedItem.UId != oldEquippedItem?.UId) + { + // Equip item to a slot, if said item is not already equipped. Search item in multiple storages + List? moveResult = null; + foreach (StorageType searchStorageType in ItemManager.BothStorageTypes) + { + try + { + moveResult = _Server.ItemManager.MoveItem(_Server, client.Character, searchStorageType, equippedItem.UId, 1, equipmentStorageType, equipmentStorageSlot); + itemUpdateResultList.AddRange(moveResult); + break; + } + catch (InvalidOperationException) + { + // Do nothing, item to equip not in this storage type. + } + } + + if (moveResult == null) + { + // Handle the item not being in storage anymore + common.Equipment.SetEquipItem(null, newJobId, equipType, (byte) equipSlot); + _Server.Database.DeleteEquipItem(common.CommonId, oldJobId, equipType, (byte) equipSlot); + } + } + } + + // Persist job change in DB + _Server.Database.UpdateCharacterCommonBaseInfo(common); + + return itemUpdateResultList; + } + public void UnlockSkill(IDatabase database, GameClient client, CharacterCommon character, JobId job, uint skillId, byte skillLv) { // Check if there is a learned skill of the same ID (This unlock is a level upgrade) @@ -557,7 +640,7 @@ public void RemoveAbility(IDatabase database, CharacterCommon character, byte sl public bool UnlockSecretAbility(CharacterCommon Character, SecretAbility secretAbilityType) { - return _Database.InsertSecretAbilityUnlock(Character.CommonId, secretAbilityType); + return _Server.Database.InsertSecretAbilityUnlock(Character.CommonId, secretAbilityType); } } } diff --git a/Arrowgene.Ddon.GameServer/Chat/Command/Commands/JobCommand.cs b/Arrowgene.Ddon.GameServer/Chat/Command/Commands/JobCommand.cs index 43308fe0..c8fbe7c8 100644 --- a/Arrowgene.Ddon.GameServer/Chat/Command/Commands/JobCommand.cs +++ b/Arrowgene.Ddon.GameServer/Chat/Command/Commands/JobCommand.cs @@ -72,7 +72,7 @@ public override void Execute(string[] command, GameClient client, ChatMessage me } else { - _server.JobManager.SetJob(_server, client, client.Character, (JobId) job); + _server.JobManager.SetJob(client, client.Character, (JobId) job); } } } diff --git a/Arrowgene.Ddon.GameServer/DdonGameServer.cs b/Arrowgene.Ddon.GameServer/DdonGameServer.cs index e4ba9960..1b93b04b 100644 --- a/Arrowgene.Ddon.GameServer/DdonGameServer.cs +++ b/Arrowgene.Ddon.GameServer/DdonGameServer.cs @@ -63,7 +63,7 @@ public DdonGameServer(GameServerSetting setting, IDatabase database, AssetReposi ItemManager = new ItemManager(); PartyManager = new PartyManager(assetRepository); ExpManager = new ExpManager(database, ClientLookup); - JobManager = new JobManager(database); + JobManager = new JobManager(this); EquipManager = new EquipManager(); ShopManager = new ShopManager(assetRepository, database); WalletManager = new WalletManager(database); diff --git a/Arrowgene.Ddon.GameServer/Handler/ItemGetStorageItemListHandler.cs b/Arrowgene.Ddon.GameServer/Handler/ItemGetStorageItemListHandler.cs index 8678e712..7d92cfd4 100644 --- a/Arrowgene.Ddon.GameServer/Handler/ItemGetStorageItemListHandler.cs +++ b/Arrowgene.Ddon.GameServer/Handler/ItemGetStorageItemListHandler.cs @@ -1,6 +1,7 @@ using System.Linq; using Arrowgene.Ddon.Server; using Arrowgene.Ddon.Shared.Entity.PacketStructure; +using Arrowgene.Ddon.Shared.Entity.Structure; using Arrowgene.Ddon.Shared.Model; using Arrowgene.Ddon.Shared.Network; using Arrowgene.Logging; @@ -21,7 +22,7 @@ public override void Handle(GameClient client, StructurePacket client.Character.Storage.getStorageAsCDataItemList((StorageType) cDataCommonU8.Value)) + .SelectMany(cDataCommonU8 => client.Character.Storage.getStorageAsCDataItemList(client.Character, (StorageType) cDataCommonU8.Value)) .ToList() }; client.Send(res); diff --git a/Arrowgene.Ddon.GameServer/Handler/JobChangeJobHandler.cs b/Arrowgene.Ddon.GameServer/Handler/JobChangeJobHandler.cs index f154dc65..2b87aa50 100644 --- a/Arrowgene.Ddon.GameServer/Handler/JobChangeJobHandler.cs +++ b/Arrowgene.Ddon.GameServer/Handler/JobChangeJobHandler.cs @@ -4,7 +4,6 @@ using Arrowgene.Logging; using Arrowgene.Ddon.Shared.Network; using Arrowgene.Ddon.GameServer.Characters; -using Arrowgene.Ddon.Shared.Entity; namespace Arrowgene.Ddon.GameServer.Handler { @@ -21,7 +20,7 @@ public JobChangeJobHandler(DdonGameServer server) : base(server) public override void Handle(GameClient client, StructurePacket packet) { - jobManager.SetJob(Server, client, client.Character, packet.Structure.JobId); + jobManager.SetJob(client, client.Character, packet.Structure.JobId); } } } \ No newline at end of file diff --git a/Arrowgene.Ddon.GameServer/Handler/JobChangePawnJobHandler.cs b/Arrowgene.Ddon.GameServer/Handler/JobChangePawnJobHandler.cs index 934d5447..3353abdc 100644 --- a/Arrowgene.Ddon.GameServer/Handler/JobChangePawnJobHandler.cs +++ b/Arrowgene.Ddon.GameServer/Handler/JobChangePawnJobHandler.cs @@ -22,7 +22,7 @@ public JobChangePawnJobHandler(DdonGameServer server) : base(server) public override void Handle(GameClient client, StructurePacket packet) { Pawn pawn = client.Character.Pawns.Where(pawn => pawn.PawnId == packet.Structure.PawnId).Single(); - jobManager.SetJob(Server, client, pawn, packet.Structure.JobId); + jobManager.SetJob(client, pawn, packet.Structure.JobId); } } } \ No newline at end of file diff --git a/Arrowgene.Ddon.LoginServer/Handler/CreateCharacterHandler.cs b/Arrowgene.Ddon.LoginServer/Handler/CreateCharacterHandler.cs index c857371a..0c8163c3 100644 --- a/Arrowgene.Ddon.LoginServer/Handler/CreateCharacterHandler.cs +++ b/Arrowgene.Ddon.LoginServer/Handler/CreateCharacterHandler.cs @@ -1131,6 +1131,23 @@ public override void Handle(LoginClient client, StructurePacket performanceEquipItems = character.Equipment.GetEquipment(character.Job, EquipType.Performance); + for (int i = 0; i < performanceEquipItems.Count; i++) + { + Item? item = performanceEquipItems[i]; + ushort slot = (ushort)(i+1); + character.Storage.setStorageItem(item, 1, StorageType.CharacterEquipment, slot); + } + + List visualEquipItems = character.Equipment.GetEquipment(character.Job, EquipType.Visual); + for (int i = 0; i < visualEquipItems.Count; i++) + { + Item? item = visualEquipItems[i]; + ushort slot = (ushort)(i+Equipment.TOTAL_EQUIP_SLOTS+1); + character.Storage.setStorageItem(item, 1, StorageType.CharacterEquipment, slot); + } + L2CCreateCharacterDataRes res = new L2CCreateCharacterDataRes(); if (!Database.CreateCharacter(character)) { @@ -1148,18 +1165,46 @@ public override void Handle(LoginClient client, StructurePacket pawnPerformanceEquipItems = pawn.Equipment.GetEquipment(pawn.Job, EquipType.Performance); + for (int j = 0; j < pawnPerformanceEquipItems.Count; j++) + { + Item? item = pawnPerformanceEquipItems[j]; + ushort slot = (ushort)(pawnSlotOffset+j+1); + character.Storage.setStorageItem(item, 1, StorageType.PawnEquipment, slot); + if(item != null) + { + Database.InsertStorageItem(character.CharacterId, StorageType.PawnEquipment, slot, item.UId, 1); + } + } + + List pawnVisualEquipItems = pawn.Equipment.GetEquipment(pawn.Job, EquipType.Visual); + for (int j = 0; j < pawnVisualEquipItems.Count; j++) + { + Item? item = pawnVisualEquipItems[j]; + ushort slot = (ushort)(pawnSlotOffset+j+Equipment.TOTAL_EQUIP_SLOTS+1); + character.Storage.setStorageItem(item, 1, StorageType.PawnEquipment, slot); + if(item != null) + { + Database.InsertStorageItem(character.CharacterId, StorageType.PawnEquipment, slot, item.UId, 1); + } + } } - // Pawns - LoadDefaultPawns(character); - foreach (Pawn pawn in character.Pawns) + // Default unlock some secret abilities based on server admin desires + foreach (var ability in _AssetRepository.SecretAbilitiesAsset.DefaultSecretAbilities) { - Database.CreatePawn(pawn); - Database.InsertGainExtendParam(pawn.CommonId, ExtendParams); + Database.InsertSecretAbilityUnlock(character.CommonId, ability); } // Insert the first main quest to start the chain @@ -1180,11 +1225,6 @@ public override void Handle(LoginClient client, StructurePacket LoadDefaultPawn(character, myPawnCsvData)).ToList(); - } - private Pawn LoadDefaultPawn(Character character, MyPawnCsv myPawnCsvData) { S2CContextGetPartyMypawnContextNtc pcapPawn = EntitySerializer.Get().Read(data_Dump_Pawn35_3_16); // TODO: Replace pcap data diff --git a/Arrowgene.Ddon.Shared/Files/Assets/Storage.csv b/Arrowgene.Ddon.Shared/Files/Assets/Storage.csv index 8c6d782d..eebcf3c9 100644 --- a/Arrowgene.Ddon.Shared/Files/Assets/Storage.csv +++ b/Arrowgene.Ddon.Shared/Files/Assets/Storage.csv @@ -17,7 +17,7 @@ 11, 0 12, 800 13, 400 -14, 0 -15, 0 +14, 30 +15, 90 16, 0 17, 0 \ No newline at end of file diff --git a/Arrowgene.Ddon.Shared/Model/CharacterCommon.cs b/Arrowgene.Ddon.Shared/Model/CharacterCommon.cs index 921baa73..10e75f00 100644 --- a/Arrowgene.Ddon.Shared/Model/CharacterCommon.cs +++ b/Arrowgene.Ddon.Shared/Model/CharacterCommon.cs @@ -1,7 +1,6 @@ #nullable enable using System.Collections.Generic; using System.Linq; -using Arrowgene.Ddon.Shared.Entity.PacketStructure; using Arrowgene.Ddon.Shared.Entity.Structure; namespace Arrowgene.Ddon.Shared.Model @@ -27,6 +26,7 @@ public CharacterCommon() .Select(jobId => (jobId, Enumerable.Repeat(null, 10).ToList())) .ToDictionary(pair => pair.jobId, pair => pair.Item2); OnlineStatus = OnlineStatus.Offline; + ExtendedParams = new CDataOrbGainExtendParam(); } public CDataCharacterJobData? ActiveCharacterJobData diff --git a/Arrowgene.Ddon.Shared/Model/Equipment.cs b/Arrowgene.Ddon.Shared/Model/Equipment.cs index 5e3f7f64..19d7d7ae 100644 --- a/Arrowgene.Ddon.Shared/Model/Equipment.cs +++ b/Arrowgene.Ddon.Shared/Model/Equipment.cs @@ -8,8 +8,8 @@ namespace Arrowgene.Ddon.Shared.Model #nullable enable public class Equipment { - private static readonly byte EQUIP_SLOT_NUMBER = 15; - private static readonly byte JOB_ITEM_SLOT_NUMBER = 2; // TODO: Verify + public static readonly byte TOTAL_EQUIP_SLOTS = 15; + private static readonly byte TOTAL_JOB_ITEM_SLOT = 2; // TODO: Verify private readonly Dictionary>> equipment; private readonly Dictionary> jobItems; @@ -28,14 +28,14 @@ public Equipment() equipment[job] = new Dictionary>(); foreach (EquipType equipType in Enum.GetValues(typeof(EquipType))) { - equipment[job][equipType] = Enumerable.Repeat(null, EQUIP_SLOT_NUMBER).ToList(); + equipment[job][equipType] = Enumerable.Repeat(null, TOTAL_EQUIP_SLOTS).ToList(); } } jobItems = new Dictionary>(); foreach (JobId job in Enum.GetValues(typeof(JobId))) { - jobItems[job] = Enumerable.Repeat(null, JOB_ITEM_SLOT_NUMBER).ToList(); + jobItems[job] = Enumerable.Repeat(null, TOTAL_JOB_ITEM_SLOT).ToList(); } } @@ -130,7 +130,6 @@ public List getEquipmentAsCDataCharacterEquipInfo(JobId .ToList(); } - public List getJobItemsAsCDataEquipJobItem(JobId job) { return GetJobItems(job) diff --git a/Arrowgene.Ddon.Shared/Model/Storages.cs b/Arrowgene.Ddon.Shared/Model/Storages.cs index 5a0e6a4e..5c02e933 100644 --- a/Arrowgene.Ddon.Shared/Model/Storages.cs +++ b/Arrowgene.Ddon.Shared/Model/Storages.cs @@ -46,7 +46,7 @@ public void addStorage(StorageType storageType, Storage storage) storages[storageType] = storage; } - public List getStorageAsCDataItemList(StorageType storageType) + public List getStorageAsCDataItemList(Character character, StorageType storageType) { return getStorage(storageType).Items .Select((item, index) => new {item = item, slot = (ushort) (index+1)}) @@ -63,8 +63,8 @@ public List getStorageAsCDataItemList(StorageType storageType) PlusValue = tuple.item.Item1.PlusValue, Bind = true, EquipPoint = 0, - EquipCharacterID = 0, - EquipPawnID = 0, + EquipCharacterID = DetermineCharacterId(character, storageType, tuple.slot), + EquipPawnID = DeterminePawnId(character, storageType, tuple.slot), WeaponCrestDataList = tuple.item.Item1.WeaponCrestDataList, ArmorCrestDataList = tuple.item.Item1.ArmorCrestDataList, EquipElementParamList = tuple.item.Item1.EquipElementParamList @@ -99,6 +99,31 @@ public List getStorageAsCDataItemList(StorageType storageType) : new Tuple(newItem, itemCount); return oldItem; } + + private uint DetermineCharacterId(Character character, StorageType storageType, ushort slot) + { + if(storageType == StorageType.CharacterEquipment) + { + return character.CharacterId; + } + else + { + return 0; + } + } + + private uint DeterminePawnId(Character character, StorageType storageType, ushort slot) + { + if(storageType == StorageType.PawnEquipment) + { + int pawnIndex = slot / (Equipment.TOTAL_EQUIP_SLOTS * 2); + return character.Pawns[pawnIndex].PawnId; + } + else + { + return 0; + } + } } public class Storage @@ -148,8 +173,8 @@ public enum StorageType : byte Unk11 = 0xB, Unk12 = 0xC, Unk13 = 0xD, - Unk14 = 0xE, - Unk15 = 0xF, + CharacterEquipment = 0xE, + PawnEquipment = 0xF, Unk16 = 0x10, Unk17 = 0x11, }