diff --git a/Client/Database/DatabaseManager.cs b/Client/Database/DatabaseManager.cs index 91d854e..a15caf9 100644 --- a/Client/Database/DatabaseManager.cs +++ b/Client/Database/DatabaseManager.cs @@ -81,7 +81,7 @@ public DatabaseManager(RyzomClient client) public DatabaseNodeBranch GetNodePtr() { return _serverDatabase; } /// - /// Returns the root branch of the database. + /// Returns the root branch of the database. /// public DatabaseNodeBranch GetDb() { diff --git a/Client/Database/DatabaseNodeBranch.cs b/Client/Database/DatabaseNodeBranch.cs index 448e2b9..2b70c7b 100644 --- a/Client/Database/DatabaseNodeBranch.cs +++ b/Client/Database/DatabaseNodeBranch.cs @@ -168,9 +168,9 @@ public override bool AddObserver(IPropertyObserver observer, TextId id) } // lookup next element from textid in my index => idx - string str = id.ReadNext(); + var str = id.ReadNext(); - DatabaseNode pNode = Find(str); + var pNode = Find(str); // Property not found. if (pNode == null) { @@ -284,6 +284,14 @@ internal virtual void AttachChild(DatabaseNode node, string nodeName) _predictDatabaseNode = node; } + /// + /// Get the number of nodes. + /// + internal uint NodeCount() + { + return (ushort)_nodes.Count; + } + /// /// Get a database node. Return null if out of bounds (no warning) /// diff --git a/Client/Interface/ServerToLocalAutoCopy.cs b/Client/Interface/ServerToLocalAutoCopy.cs index 37e7d4c..bc66142 100644 --- a/Client/Interface/ServerToLocalAutoCopy.cs +++ b/Client/Interface/ServerToLocalAutoCopy.cs @@ -43,7 +43,7 @@ public class ServerToLocalAutoCopy : IDisposable private List _Nodes = new List(); /// Sorting of Nodes, by Server Node List _ServerNodeMap = new List(); - /// Sorting of Nodes, by Local Node + /// Sorting of Nodes, by Local Node List _LocalNodeMap = new List(); /// List of nodes to update until next synchonized client-server counter private List _UpdateList = new List(); @@ -65,7 +65,7 @@ public void Dispose() // init the AutoCopy public void Init(string dbPath) { - InterfaceManager pIM = _interfaceManger; + var pIM = _interfaceManger; // Get the synchronisation Counter in Server DB _ServerCounter = _databaseManager.GetDbProp("SERVER:" + dbPath + ":COUNTER", false); @@ -158,24 +158,24 @@ void OnServerChange(DatabaseNode serverNode) return; } - DatabaseNodeLeaf serverLeaf = (DatabaseNodeLeaf)serverNode; + var serverLeaf = (DatabaseNodeLeaf)serverNode; var pIM = _interfaceManger; // Add the leaf to the update list. only if not the counter if (serverLeaf != _ServerCounter) { // build the map key - Node nodeComp = new Node(); - NodeServerComp sc = new NodeServerComp(); + var nodeComp = new Node(); + var sc = new NodeServerComp(); nodeComp.ServerNode = serverLeaf; sc.Node = nodeComp; // try to find the node associated to this server leaf - int index = _ServerNodeMap.IndexOf(sc); + var index = _ServerNodeMap.IndexOf(sc); // if found if (index > 0 || _ServerNodeMap[0].Node.ServerNode == serverLeaf) { - Node node = _ServerNodeMap[index].Node; + var node = _ServerNodeMap[index].Node; // if this node is not already inserted if (!node.InsertedInUpdateList) { @@ -190,9 +190,9 @@ void OnServerChange(DatabaseNode serverNode) if (pIM.localActionCounterSynchronizedWith(_ServerCounter)) { // update all leaves - for (int i = 0; i < _UpdateList.Count; i++) + for (var i = 0; i < _UpdateList.Count; i++) { - Node node = _UpdateList[i]; + var node = _UpdateList[i]; _LocalUpdating = true; node.LocalNode.SetValue64(node.ServerNode.GetValue64()); @@ -238,7 +238,7 @@ public override void Update(DatabaseNode node) } } - // A node here is a pair Server<->Local + /// A node here is a pair Server<->Local private class Node { public DatabaseNodeLeaf ServerNode; @@ -253,7 +253,7 @@ public Node() } } - // Struct for comparing nodes, by either Local or Server pointer + /// Struct for comparing nodes, by either Local or Server pointer private class NodeLocalComp : IComparable { public Node Node { get; internal set; } @@ -274,6 +274,29 @@ public int CompareTo([AllowNull] NodeLocalComp other) } } - void BuildRecursLocalLeaves(DatabaseNodeBranch branch, List leaves) { } + void BuildRecursLocalLeaves(DatabaseNodeBranch branch, List leaves) + { + for (ushort i = 0; i < branch.NodeCount(); i++) + { + var node = branch.GetNode(i); + if (node != null) + { + if (node is DatabaseNodeLeaf leaf) + { + // just append to list + leaves.Add(leaf); + } + else + { + // recurs if a branch (should be...) + if (node is DatabaseNodeBranch sonBranch) + { + BuildRecursLocalLeaves(sonBranch, leaves); + } + } + } + } + + } } } diff --git a/Client/Inventory/InventoryManager.cs b/Client/Inventory/InventoryManager.cs index 4259ebf..7a63738 100644 --- a/Client/Inventory/InventoryManager.cs +++ b/Client/Inventory/InventoryManager.cs @@ -6,7 +6,9 @@ // Copyright 2010 Winch Gate Property Limited /////////////////////////////////////////////////////////////////// +using System; using Client.Database; +using Client.Stream; namespace Client.Inventory { @@ -19,7 +21,7 @@ namespace Client.Inventory /// September 2003 public class InventoryManager { - private RyzomClient _client; + private readonly RyzomClient _client; const uint MAX_TEMPINV_ENTRIES = 16; const uint MAX_BAGINV_ENTRIES = 500; @@ -33,12 +35,51 @@ public class InventoryManager const uint MAX_PLAYER_INV_ENTRIES = 500; // db path for the local inventory - //#define LOCAL_INVENTORY "LOCAL:INVENTORY" - //#define SERVER_INVENTORY "SERVER:INVENTORY" + public const string LOCAL_INVENTORY = "LOCAL:INVENTORY"; + public const string SERVER_INVENTORY = "SERVER:INVENTORY"; // db path for all the inventories (without the SERVER: prefix) - public readonly string[] InventoryDBs; - public readonly uint[] InventoryIndexes; + private readonly string[] InventoryDBs = { + "INVENTORY:BAG", + "INVENTORY:PACK_ANIMAL0", + "INVENTORY:PACK_ANIMAL1", + "INVENTORY:PACK_ANIMAL2", + "INVENTORY:PACK_ANIMAL3", + "INVENTORY:TEMP", + "EXCHANGE:GIVE", + "EXCHANGE:RECEIVE", + "TRADING", + "INVENTORY:SHARE", + "GUILD:INVENTORY", + "INVENTORY:ROOM" + }; + + public enum INVENTORIES : ushort + { + // TODO : remove handling, merge it with equipement + handling = 0, + temporary, // 1 + equipment, // 2 + bag, // 3 + pet_animal, // 4 Character can have 5 pack animal + pet_animal1 = pet_animal, // for toString => TInventory convertion + pet_animal2, + pet_animal3, + pet_animal4, + max_pet_animal, // 8 + NUM_INVENTORY = max_pet_animal, // 8 + UNDEFINED = NUM_INVENTORY, // 8 + + exchange, // 9 This is not a bug : exchange is a fake inventory + exchange_proposition, // 10 and should not count in the number of inventory + // same for botChat trading. + trading, // 11 + reward_sharing, // 12 fake inventory, not in database.xml. Used by the item info protocol only + guild, // 13 (warning: number stored in guild saved file) + player_room, // 14 + NUM_ALL_INVENTORY // warning: distinct from NUM_INVENTORY + } + public readonly uint NumInventories = new uint(); // LOCAL INVENTORY @@ -71,6 +112,9 @@ public class InventoryManager // Cache to know if bag is locked or not, because of item worn private bool[] BagItemEquipped = new bool[MAX_BAGINV_ENTRIES]; + // *************************************************************************** + // db path for all the inventories (without the SERVER: prefix) + public InventoryManager(RyzomClient client) { _client = client; @@ -110,5 +154,145 @@ internal void SortBag() { // TODO } + + public void equip(in string bagPath, in string invPath) + { + //if (isSwimming() || isStunned() || isDead() || isRiding()) + //{ + // return; + //} + + var pIM = _client.GetInterfaceManager(); + + if (bagPath.Length == 0 || invPath.Length == 0) + { + return; + } + + // Get inventory and slot + var sIndexInBag = bagPath.Substring(bagPath.LastIndexOf(':') + 1, bagPath.Length); + ushort.TryParse(sIndexInBag, out var indexInBag); + + var inventory = (ushort)INVENTORIES.UNDEFINED; + ushort invSlot = 0xffff; + + if (invPath.StartsWith("LOCAL:INVENTORY:HAND", StringComparison.InvariantCultureIgnoreCase)) + { + inventory = (ushort)INVENTORIES.handling; + ushort.TryParse(invPath.Substring(21, invPath.Length), out invSlot); + } + else if (invPath.StartsWith("LOCAL:INVENTORY:EQUIP", StringComparison.InvariantCultureIgnoreCase)) + { + inventory = (ushort)INVENTORIES.equipment; + ushort.TryParse(invPath.Substring(22, invPath.Length), out invSlot); + } + + // Hands management : check if we have to unequip left hand because of incompatibility with right hand item + var oldRightIndexInBag = _client.GetDatabaseManager().GetDbProp(invPath + ":INDEX_IN_BAG").GetValue16(); + + if (inventory == (ushort)INVENTORIES.handling && invSlot == 0) + { + // TODO DatabaseCtrlSheet pCSLeftHand = CWidgetManager.getInstance().getElementFromId(CTRL_HAND_LEFT) as DatabaseCtrlSheet; + object pCSLeftHand = null; + + if (pCSLeftHand == null) + { + return; + } + + // get sheet of left item + uint leftSheet = 0; + var pNL = _client.GetDatabaseManager().GetDbProp(LOCAL_INVENTORY + ":HAND:1:INDEX_IN_BAG", false); + + if (pNL == null) + { + return; + } + if (pNL.GetValue32() > 0) + { + var pNL2 = _client.GetDatabaseManager().GetDbProp(LOCAL_INVENTORY + ":BAG:" + (pNL.GetValue32() - 1) + ":SHEET", false); + if (pNL2 == null) + { + return; + } + leftSheet = (uint)pNL2.GetValue32(); + } + + // get sheet of previous right hand item + uint lastRightSheet = 0; + if (oldRightIndexInBag > 0) + { + pNL = _client.GetDatabaseManager().GetDbProp(LOCAL_INVENTORY + ":BAG:" + (oldRightIndexInBag - 1) + ":SHEET", false); + if (pNL == null) + { + return; + } + lastRightSheet = (uint)pNL.GetValue32(); + } + + // get sheet of new right hand item + uint rightSheet = 0; + if (indexInBag + 1 > 0) + { + pNL = _client.GetDatabaseManager().GetDbProp(LOCAL_INVENTORY + ":BAG:" + (indexInBag) + ":SHEET", false); + if (pNL == null) + { + return; + } + rightSheet = (uint)pNL.GetValue32(); + } + + //// TODO If incompatible -> remove + //if (!GetInventory().IsLeftHandItemCompatibleWithRightHandItem(leftSheet, rightSheet, lastRightSheet)) + //{ + // GetInventory().Unequip(LOCAL_INVENTORY+ ":HAND:1"); + //} + } + + // update the equip DB pointer + _client.GetDatabaseManager().GetDbProp(invPath + ":INDEX_IN_BAG").SetValue16((short)(indexInBag + 1)); + + //// TODO Yoyo add: when the user equip an item, the action are invalid during some time + //if (indexInBag < MAX_BAGINV_ENTRIES) + //{ + // ItemSheet pIS = _client.GetSheetManager().Get(_client.GetSheetIdFactory().SheetId(GetBagItem(indexInBag).getSheetID())) as ItemSheet; + // if (pIS != null) + // { + // PhraseManager pPM = PhraseManager.getInstance(); + // pPM.setEquipInvalidation(NetMngr.getCurrentServerTick(), pIS.EquipTime); + // } + //} + + //// TODO Update trade window if any + //if ((BotChatPageAll != null) && (BotChatPageAll.Trade != null)) + //{ + // BotChatPageAll.Trade.invalidateCoords(); + //} + + // Send message to the server + if (inventory != (short)INVENTORIES.UNDEFINED) + { + var @out = new BitMemoryStream(); + const string sMsg = "ITEM:EQUIP"; + + if (_client.GetNetworkManager().GetMessageHeaderManager().PushNameToStream(sMsg, @out)) + { + // Fill the message (equipped inventory, equipped inventory slot, bag slot) + @out.Serial(ref inventory); + @out.Serial(ref invSlot); + @out.Serial(ref indexInBag); + _client.GetNetworkManager().Push(@out); + + // TODO pIM.IncLocalSyncActionCounter(); + + //nlinfo("impulseCallBack : %s %d %d %d sent", sMsg.c_str(), inventory, invSlot, indexInBag); + } + else + { + _client.Log.Warn($"Don't know message name {sMsg}"); + } + } + } + } } diff --git a/Client/Sheet/DatabaseCtrlSheet.cs b/Client/Sheet/DatabaseCtrlSheet.cs new file mode 100644 index 0000000..e5bdace --- /dev/null +++ b/Client/Sheet/DatabaseCtrlSheet.cs @@ -0,0 +1,29 @@ +/////////////////////////////////////////////////////////////////// +// This file contains modified code from 'Ryzom - MMORPG Framework' +// http://dev.ryzom.com/projects/ryzom/ +// which is released under GNU Affero General Public License. +// http://www.gnu.org/licenses/ +// Copyright 2010 Winch Gate Property Limited +/////////////////////////////////////////////////////////////////// + +namespace Client.Sheet +{ + public class DatabaseCtrlSheet + { + public enum SheetCategory + { + Item = 0, + Pact, + Skill, + GuildFlag, + Mission, + Phrase, + DontKnow + } + + public DatabaseCtrlSheet() + { + + } + } +}