macOS 0 Report post Posted February 3, 2023 Was fooling around with the GM commands and created an item that is invalid (even though I got the id from my iteminfo.txt) Now when trying to log in I am getting an error and the game is closing. "item id in inventory is invalid game going to exit" I wonder if there is a way to manually delete that item from my inventory using the database manager, and if so, where (which database and which table?) Quote Share this post Link to post Share on other sites
Angelix 374 Report post Posted February 3, 2023 There's 2 ItemInfo files. Both must match in order to avoid this error. You probably created a new item within the ItemInfo on server and did not copy-paste that new ItemInfo to client and compile. So just copy ItemInfo to client, compile it and you should be able to enter without issues. 2 Quote Share this post Link to post Share on other sites
V3ct0r 2,116 Report post Posted February 6, 2023 Hello @macOS, you can try use this program to solve your problem: TOP Bag Editor Note: works only with original 1.3x versions of the game. 2 Quote Some useful links / Полезные ссылки Tips for making a topic in 'Questions & Help' / Рекомендации по созданию тем в разделе "Помощь" Server Advertising Section Rules / Правила раздела "Реклама серверов" Available e-mail domains for registration / Допустимые e-mail домены для регистрации User groups / Группы пользователей User ranks / Звания пользователей "Broken" pictures on the forum / "Битые" изображения на форуме Beware of scammers! / Осторожно, мошенники! My developments / Мои разработки Mods for client and server / Моды для клиента и сервера PKOdev.NET website for Tales of Pirates Server / PKOdev.NET веб-обвязка для сервера Пиратии I do not provide any help in private messages and outside the forum. Use 'Questions & Help' section please. Thank you for understanding! Я не оказываю какую-либо помощь в личных сообщениях и вне форума. Пожалуйста, используйте раздел "Пиратия: Помощь". Благодарю за понимание! Share this post Link to post Share on other sites
macOS 0 Report post Posted February 7, 2023 On 2/6/2023 at 9:42 AM, V3ct0r said: Hello @macOS, you can try use this program to solve your problem: TOP Bag Editor Note: works only with original 1.3x versions of the game. That's precisely what I needed. Too bad it doesn't work with the version I am running. I am still wondering if I could manually alter values using SQL Server Management Studio Quote Share this post Link to post Share on other sites
AlGhoul 66 Report post Posted February 8, 2023 (edited) 12 hours ago, macOS said: That's precisely what I needed. Too bad it doesn't work with the version I am running. I am still wondering if I could manually alter values using SQL Server Management Studio If you know the basics of python, you can copy any character's inventory and play with the following script until u grasp it, or atleast remove ur desired item. However This is an ancient script I wrote in python for my old django based PKO site, I'd re-write it if I were to use it in a similar context. It could be used as a base and I can see a room for extension as well. this one supported CO's inventory however the item string could be altered cause the script is "inventory agnostic", here is an example for an inventory item string itemString = f"ITEMSLOT, {item.itemID}, {item.quantity}, {item.durability}, {item.durability}, {item.energy}, {item.energy}, 0, {itemLocked}, {item.levelRequired}, 0, {forgeAttr}, {item.effectiveness}" import re import ctypes import struct """A class that represents TOP/PKO character's inventory and provides an easy API to interact with it. By AG/AlGhoul, Kind regards. Discord: AlGhoul#9988""" class Inventory: """Used to represent Character's Inventory""" _key = "19800216" _loaded = False def __init__(self, inventoryData: str): """Splits the inventory string and Initializes the object with the required vars""" self.invMaxSize, self.version, self.currentInventory = re.split( "[@#]", inventoryData, 3) def _decrypt(self, key: int = _key): """Decrypts Char's inventory DB string to normal comma separated numbers""" buffer = '' for charIndex in range(len(self.currentInventory)): buffer += chr(ord(self.currentInventory[charIndex] ) - ord(str(key[charIndex % 8]))) self._loaded = True self.currentInventory = buffer def _encrypt(self, key: int = _key): """Encrypts Char's inventory from normal comma separated numbers to a DB string""" buffer = '' for charIndex in range(len(self.currentInventory)): buffer += chr(ord(self.currentInventory[charIndex] ) + ord(str(key[charIndex % 8]))) self.currentInventory = buffer def _load(self): """Loads Char's inventory and dumps its data""" self._decrypt() self._temp = self.currentInventory.split(';') self._tempLength = len(self._temp) self.invItems = [self._temp[itemIndex] for itemIndex in range( self._tempLength) if itemIndex > 1 and itemIndex != self._tempLength - 1] self.invItemLength = len(self.invItems) self.invType = self._temp[0] self.occupiedSlotCount = int(self._temp[1]) self.currentCRC = int(self._temp[self._tempLength - 1]) self._loaded = True def calculateCRC(self): """Calculates/Validates 'Cyclic Redundancy Check' 'Checksum' for the current decrypted inventory""" self.newCRC = int(self.invType) for itemIndex in range(self.invItemLength): if not self.invItems[itemIndex]: continue item = self.invItems[itemIndex].split(',') for i in range(len(item)): if i == 0 or i == 7 or i == 10 or i == 13: continue itemAttr = int(item[i]) if i == 11: if itemAttr > 0: itemAttr = struct.unpack( 'l', struct.pack('L', itemAttr))[0] self.newCRC += itemAttr return ctypes.c_long(self.newCRC).value def addItem(self, itemString: str): """Adds normal item string in the first free slot in sight, returns False if failed or inventory is full, none on CRC mismatch""" if not itemString: return None if not self._loaded: self._load() if self.occupiedSlotCount > int(self.invMaxSize) - 1 or self.calculateCRC() != self.currentCRC: return False freeSlot = None for itemIndex in range(self.invItemLength): if itemIndex != int(self.invItems[itemIndex].split(',')[0]): freeSlot = itemIndex break if not freeSlot: return False itemString = itemString.replace('ITEMSLOT', str(freeSlot)) self.invItems.append(itemString) self.invItemLength = self.invItemLength + 1 self.currentInventory = '' for itemIndex in range(self.invItemLength): self.currentInventory += f"{self.invItems[itemIndex]};" self.currentInventory = f"{self.invType};{self.invItemLength};{self.currentInventory};{self.calculateCRC()}" return True def removeItem(self, itemID: int, amount: int): """"Removes an 'amount' of item(s), if amount is set to '-1' it removes the item entirely from all slots, returns false if not enough quantity, none on CRC mismatch""" if amount != -1 and self.GetItemCount(itemID) < amount: return False if not self._loaded: self._load() if self.calculateCRC() != self.currentCRC: return None itemIndexList = [] itemRemoveList = [] for itemIndex in range(self.invItemLength): if itemID == int(self.invItems[itemIndex].split(',')[1]): itemIndexList.append(itemIndex) itemRemoveList.append(self.invItems[itemIndex]) if not itemIndexList or not itemRemoveList: return None nextToRemove = 0 for i in range(len(itemIndexList)): if amount == -1: self.invItems[itemIndexList[i]] = None continue if nextToRemove == 0 and amount > int(self.invItems[itemIndexList[i]].split(',')[2]): nextToRemove = amount - \ int(self.invItems[itemIndexList[i]].split(',')[2]) del self.invItems[itemIndexList[i]] elif nextToRemove != 0: nextToRemove = int(self.invItems[itemIndexList[i]].split(',')[ 2]) - nextToRemove item = self.invItems[itemIndexList[i]].split(',') item[2] = nextToRemove modifiedItem = ','.join(map(str, item)) self.invItems[itemIndexList[i]] = modifiedItem break else: nextToRemove = int( self.invItems[itemIndexList[i]].split(',')[2]) - amount item = self.invItems[itemIndexList[i]].split(',') item[2] = nextToRemove modifiedItem = ','.join(map(str, item)) self.invItems[itemIndexList[i]] = modifiedItem self.currentInventory = '' self.invItemLength = len(self.invItems) for itemIndex in range(self.invItemLength): if self.invItems[itemIndex] == None: continue self.currentInventory += f"{self.invItems[itemIndex]};" self.currentInventory = f"{self.invType};{self.invItemLength};{self.currentInventory};{self.calculateCRC()}" return True def GetItemCount(self, itemID: int): """Gets a specific item's total count""" if not itemID: return 0 if not self._loaded: self._load() itemCount = 0 for itemIndex in range(self.invItemLength): if self.invItems[itemIndex] != None and itemID == int(self.invItems[itemIndex].split(',')[1]): itemCount += int(self.invItems[itemIndex].split(',')[2]) return itemCount def GetNewInventory(self): """Returns a new encrypted inventory, ready to be written into the DB""" self._encrypt() return f"{self.invMaxSize}@{self.version}#{self.currentInventory}" Edited February 8, 2023 by AlGhoul 1 Quote Kind regards, AG. Share this post Link to post Share on other sites
V3ct0r 2,116 Report post Posted February 9, 2023 Hello @AlGhoul, You can use already existing functions decrypt() and encrypt() from the GameDB database to decrypt and encrypt inventory respectively: On 12/13/2022 at 12:02 PM, Magicsea Online said: Select cha_id, dbo.decrypt( content ) from GameDB.dbo.Resource Парсинг одной из строчек 48@113#1;48; 0,6821,1,0,0,1,1,0,0,0,0; 1,7274,14,0,0,0,0,0,0,0,0; 2,3908,1,5000,5000,0,0,0,0,0,0; 3,1031,44,0,0,0,0,0,0,0,0; 4,4022,1,0,0,0,0,0,0,0,0; 5,7248,29,0,0,0,0,0,0,0,0; 6,7255,7,0,0,0,0,0,0,0,0; 7,7256,3,0,0,0,0,0,0,0,0; 8,1012,1,0,0,1,1,0,0,0,0; 9,207,1,10000,10000,0,10,0,0,0,0; 10,195,196,0,0,0,0,0,0,0,0; 11,266,1,200,1000,23,23,0,0,0,1,26,5,28,5,29,5,27,1,30,0; 12,7254,27,0,0,0,0,0,0,0,0; 13,1137,10,0,0,0,0,0,0,0,0; 14,7651,4,0,0,0,0,0,0,0,0; 15,7653,4,0,0,0,0,0,0,0,0; 16,3457,91,0,0,0,0,0,0,0,0; 17,1082,30,0,0,0,0,0,0,0,0; 18,7654,2,0,0,0,0,0,0,0,0; 19,7250,6,0,0,0,0,0,0,0,0; 20,1860,7,0,0,0,0,0,0,0,0; 21,3085,29,0,0,0,0,0,0,0,0; 22,3084,121,0,0,0,0,0,0,0,0; 23,179,133,0,0,0,0,0,0,0,0; 24,864,1,0,0,1,1,0,0,0,0; 25,3047,10,0,0,0,0,0,0,0,0; 26,6821,1,0,0,1,1,0,0,0,0; 27,3424,9,0,0,0,0,0,0,0,0; 28,3458,56,0,0,0,0,0,0,0,0; 29,1139,20,0,0,0,0,0,0,0,0; 30,3152,91,0,0,0,0,0,0,0,0; 31,6823,1,0,0,1,1,0,0,0,0; 32,7634,121,0,0,0,0,0,0,0,0; 33,7647,2,0,0,0,0,0,0,0,0; 34,7629,107,0,0,0,0,0,0,0,0; 35,7659,198,0,0,0,0,0,0,0,0; 36,4146,1,10000,10000,1000,1000,0,1000000000,0,1,35,0,36,0,39,0,40,0,41,0; 37,7628,167,0,0,0,0,0,0,0,0; 38,7633,116,0,0,0,0,0,0,0,0; 39,7636,2,0,0,0,0,0,0,0,0; 40,7635,114,0,0,0,0,0,0,0,0; 41,7631,14,0,0,0,0,0,0,0,0; 42,4231,1,0,0,0,0,0,0,0,0; 43,7632,67,0,0,0,0,0,0,0,0; 44,7640,2,0,0,0,0,0,0,0,0; 45,1092,47,0,0,0,0,0,0,0,0; 46,7652,1,0,0,0,0,0,0,0,0; 47,7630,185,0,0,0,0,0,0,0,0;1000291035 Номер предмета в ячейке, идентификатор предмета, количество предмета в ячейке, остальные данные(форж, характеристики, вставленные гемы и прочее) Там еще есть type: 0 - инвентарь 1 - временный мешок 2 - банк Могу ошибаться, но это легко проверить. Еще есть look - то что надето на персонажа: Select cha_id, look from GameDB.dbo.character Quote Some useful links / Полезные ссылки Tips for making a topic in 'Questions & Help' / Рекомендации по созданию тем в разделе "Помощь" Server Advertising Section Rules / Правила раздела "Реклама серверов" Available e-mail domains for registration / Допустимые e-mail домены для регистрации User groups / Группы пользователей User ranks / Звания пользователей "Broken" pictures on the forum / "Битые" изображения на форуме Beware of scammers! / Осторожно, мошенники! My developments / Мои разработки Mods for client and server / Моды для клиента и сервера PKOdev.NET website for Tales of Pirates Server / PKOdev.NET веб-обвязка для сервера Пиратии I do not provide any help in private messages and outside the forum. Use 'Questions & Help' section please. Thank you for understanding! Я не оказываю какую-либо помощь в личных сообщениях и вне форума. Пожалуйста, используйте раздел "Пиратия: Помощь". Благодарю за понимание! Share this post Link to post Share on other sites
mkhzaleh 131 Report post Posted February 9, 2023 39 minutes ago, V3ct0r said: There's also a type: 0 - inventory 1 - temporary bag 2 - bank inside the source its always 1 for inventory type i ported it to dart class from c++ for little fun will create small admin panel using iteven tho its kinda useless encryption nowadays so not sure if worth to keep that at all lol 1 Quote Share this post Link to post Share on other sites
V3ct0r 2,116 Report post Posted February 10, 2023 On 2/9/2023 at 6:53 PM, mkhzaleh said: inside the source its always 1 for inventory type Yes, as @Magicsea Online said, he can be wrong. On 2/9/2023 at 6:53 PM, mkhzaleh said: even tho its kinda useless encryption nowadays so not sure if worth to keep that at all lol Those who work with official binaries are still faced with encryption, unfortunately. 1 Quote Some useful links / Полезные ссылки Tips for making a topic in 'Questions & Help' / Рекомендации по созданию тем в разделе "Помощь" Server Advertising Section Rules / Правила раздела "Реклама серверов" Available e-mail domains for registration / Допустимые e-mail домены для регистрации User groups / Группы пользователей User ranks / Звания пользователей "Broken" pictures on the forum / "Битые" изображения на форуме Beware of scammers! / Осторожно, мошенники! My developments / Мои разработки Mods for client and server / Моды для клиента и сервера PKOdev.NET website for Tales of Pirates Server / PKOdev.NET веб-обвязка для сервера Пиратии I do not provide any help in private messages and outside the forum. Use 'Questions & Help' section please. Thank you for understanding! Я не оказываю какую-либо помощь в личных сообщениях и вне форума. Пожалуйста, используйте раздел "Пиратия: Помощь". Благодарю за понимание! Share this post Link to post Share on other sites