From a1af615d49a9565c4f656a20337edb273e2c960a Mon Sep 17 00:00:00 2001 From: Meistache Date: Sun, 8 Feb 2015 19:18:52 -0200 Subject: Changes regarding storage implementation on ManaMarket --- config.py.template | 2 +- data_template/delisted.xml | 2 + data_template/stack.xml | 2 + main.py | 273 ++++++++++++++++++++++++++++++++++----------- net/packet_out.py | 5 +- net/protocol.py | 14 +++ storage.py | 114 +++++++++++++++++++ tradey.py | 80 +++++++++++-- utils.py | 9 ++ 9 files changed, 424 insertions(+), 77 deletions(-) create mode 100644 data_template/delisted.xml create mode 100644 data_template/stack.xml create mode 100644 storage.py diff --git a/config.py.template b/config.py.template index e55b2f6..d8af804 100644 --- a/config.py.template +++ b/config.py.template @@ -2,7 +2,7 @@ server = "server.themanaworld.org" port = 6901 account = "" password = "" -relist_time = 604800 # Time in seconds before an item needs to be relisted. +delist_time = 604800 # Time in seconds before an item needs to be relisted. character = 0 #slot character is in, 0 for first, 1 for second, 2 for third admin = "" #nosell = [] # Items which can't be sold - just add the itemid to the list. diff --git a/data_template/delisted.xml b/data_template/delisted.xml new file mode 100644 index 0000000..8208566 --- /dev/null +++ b/data_template/delisted.xml @@ -0,0 +1,2 @@ + + diff --git a/data_template/stack.xml b/data_template/stack.xml new file mode 100644 index 0000000..8208566 --- /dev/null +++ b/data_template/stack.xml @@ -0,0 +1,2 @@ + + diff --git a/main.py b/main.py index 5592a52..a259c4c 100755 --- a/main.py +++ b/main.py @@ -41,6 +41,7 @@ from net.packet import * from net.protocol import * from net.packet_out import * from player import * +from storage import * import tradey import utils import eliza @@ -50,12 +51,37 @@ shop_broadcaster = utils.Broadcast() trader_state = utils.TraderState() ItemDB = utils.ItemDB() player_node = Player('') +storage = Storage() beingManager = BeingManager() user_tree = tradey.UserTree() sale_tree = tradey.ItemTree() +stack_tree = tradey.StackTree() +delisted_tree = tradey.DelistedTree() ItemLog = utils.ItemLog() +DelistedLog = utils.DelistedLog() logger = logging.getLogger('ManaLogger') +def do_delist(): + cleaned = 0 + for elem in sale_tree.root: + item = Item() + item.index = player_node.find_inventory_index(int(elem.get('itemId'))) + item.itemId = int(elem.get('itemId')) + item.amount = int(elem.get('amount')) + if time.time() - float(elem.get('add_time')) > config.delist_time: + try: + storage.storage_send(mapserv, item.index, item.amount) + except: + print("Couldn't send item to storage") + return -10 + storage.add_item(item) + player_node.remove_item(item.index, item.amount) + delisted_tree.add_item(elem.get('name'), item.itemId, item.amount) + sale_tree.remove_item_uid(elem.get('uid')) + DelistedLog.add_item(item.itemId, item.amount, elem.get('name')) + cleaned += 1 + logger.info("Delisting routine done. %d items added to delisted.xml", cleaned) + def process_whisper(nick, msg, mapserv): msg = filter(lambda x: x in utils.allowed_chars, msg) if len(msg) == 0: @@ -90,7 +116,7 @@ def process_whisper(nick, msg, mapserv): mapserv.sendall(whisper(nick, "No items for sale.")) for elem in sale_tree.root: - if time.time() - float(elem.get('add_time')) < config.relist_time: # Check if an items time is up. + if time.time() - float(elem.get('add_time')) < config.delist_time: # Check if an items time is up. msg = "[selling] [" + elem.get("uid") + "] " + elem.get("amount") + " [@@" + \ elem.get("itemId") + "|" + ItemDB.getItem(int(elem.get("itemId"))).name + "@@] for " + elem.get("price") + "gp each" mapserv.sendall(whisper(nick, msg)) @@ -131,10 +157,7 @@ def process_whisper(nick, msg, mapserv): items_for_sale = False for elem in sale_tree.root: if elem.get('name') == nick: - if time.time() - float(elem.get('add_time')) > config.relist_time: - msg = "[expired] [" - else: - msg = "[selling] [" + msg = "[selling] [" msg += elem.get("uid") + "] " + elem.get("amount") + " [@@" + elem.get("itemId") + "|" + \ ItemDB.getItem(int(elem.get("itemId"))).name + "@@] for " + elem.get("price") + "gp each" @@ -145,8 +168,38 @@ def process_whisper(nick, msg, mapserv): mapserv.sendall(whisper(nick, msg)) + for elem in stack_tree.root: + if elem.get('name') == nick: + msg = "[waiting] [" + + msg += elem.get("uid") + "] " + elem.get("amount") + " [@@" + elem.get("itemId") + "|" + \ + ItemDB.getItem(int(elem.get("itemId"))).name + "@@] for " + elem.get("price") + "gp each" + + if items_for_sale == False: + mapserv.sendall(whisper(nick, "Your have the following items waiting for sale:")) + items_for_sale = True + + mapserv.sendall(whisper(nick, msg)) + if items_for_sale == False: mapserv.sendall(whisper(nick, "You have no items for sale.")) + + items_for_getback == False + for elem in delisted_tree.root: + if elem.get('name') == nick: + msg = "[expired] [" + + msg += elem.get("uid") + "] " + elem.get("amount") + " [@@" + elem.get("itemId") + "|" + \ + ItemDB.getItem(int(elem.get("itemId"))).name + "@@]" + + if items_for_getback == False: + mapserv.sendall(whisper(nick, "Your have the following items waiting for getback:")) + items_for_getback = True + + mapserv.sendall(whisper(nick, msg)) + + if items_for_sale == False: + mapserv.sendall(whisper(nick, "You have no expired items.")) money = int(user.get('money')) mapserv.sendall(whisper(nick, "You have " + str(money) + "gp to collect.")) @@ -157,7 +210,7 @@ def process_whisper(nick, msg, mapserv): # Sends help information if len(broken_string) == 1: mapserv.sendall(whisper(nick, "Welcome to ManaMarket!")) - mapserv.sendall(whisper(nick, "The basic commands for the bot are: !list, !find or , !buy , !add , !money, !relist , !info, !getback ")) + mapserv.sendall(whisper(nick, "The basic commands for the bot are: !list, !find or , !buy , !add , !money, !info, !getback ")) mapserv.sendall(whisper(nick, "For a detailed description of each command, type !help e.g. !help !buy")) mapserv.sendall(whisper(nick, "For example to purchase an item shown in the list as:")) mapserv.sendall(whisper(nick, "[selling] [6] 5 [@@640|Iron Ore@@] for 1000gp each")) @@ -189,8 +242,6 @@ def process_whisper(nick, msg, mapserv): mapserv.sendall(whisper(nick, "!add - Add an item to the sell list (requires that you have an account).")) elif broken_string[1] == '!money': mapserv.sendall(whisper(nick, "!money - Allows you to collect money for any sales made on your behalf.")) - elif broken_string[1] == '!relist': - mapserv.sendall(whisper(nick, "!relist - Allows you to relist an item which has expired.")) elif broken_string[1] == '!info': mapserv.sendall(whisper(nick, "!info - Displays basic information about your account.")) elif broken_string[1] == '!getback': @@ -238,20 +289,32 @@ def process_whisper(nick, msg, mapserv): if item.isdigit(): # an id for elem in sale_tree.root: - if ((time.time() - float(elem.get('add_time'))) < config.relist_time) \ - and int(elem.get("itemId")) == int(item): # Check if an items time is up. + if int(elem.get("itemId")) == int(item): msg = "[selling] [" + elem.get("uid") + "] " + elem.get("amount") + " [@@" + elem.get("itemId") + "|" \ + ItemDB.getItem(int(elem.get("itemId"))).name + "@@] for " + elem.get("price") + "gp each" mapserv.sendall(whisper(nick, msg)) items_found = True + if not items_found: # if no items on list, gives priority to stack + for elem in stack_tree.root: + if int(elem.get("itemId")) == int(item): + msg = "[selling] [" + elem.get("uid") + "] " + elem.get("amount") + " [@@" + elem.get("itemId") + "|" \ + + ItemDB.getItem(int(elem.get("itemId"))).name + "@@] for " + elem.get("price") + "gp each" + mapserv.sendall(whisper(nick, msg)) + items_found = True else: # an item name for elem in sale_tree.root: - if ((time.time() - float(elem.get('add_time'))) < config.relist_time) \ - and item.lower() in ItemDB.getItem(int(elem.get("itemId"))).name.lower(): # Check if an items time is up. + if item.lower() in ItemDB.getItem(int(elem.get("itemId"))).name.lower(): msg = "[selling] [" + elem.get("uid") + "] " + elem.get("amount") + " [@@" + elem.get("itemId") + "|" \ + ItemDB.getItem(int(elem.get("itemId"))).name + "@@] for " + elem.get("price") + "gp each" mapserv.sendall(whisper(nick, msg)) items_found = True + if not items_found: # if no items on list, gives priority to stack + for elem in stack_tree.root: + if item.lower() in ItemDB.getItem(int(elem.get("itemId"))).name.lower(): + msg = "[selling] [" + elem.get("uid") + "] " + elem.get("amount") + " [@@" + elem.get("itemId") + "|" \ + + ItemDB.getItem(int(elem.get("itemId"))).name + "@@] for " + elem.get("price") + "gp each" + mapserv.sendall(whisper(nick, msg)) + items_found = True if not items_found: mapserv.sendall(whisper(nick, "Item not found.")) @@ -267,6 +330,8 @@ def process_whisper(nick, msg, mapserv): if trader_state.Trading.test(): mapserv.sendall(whisper(nick, "I'm busy with a trade.")) + elif storage.Open.test(): + mapserv.sendall(whisper(nick, "I'm busy with storage.")) else: mapserv.sendall(whisper(nick, "I'm free.")) @@ -283,7 +348,12 @@ def process_whisper(nick, msg, mapserv): if broken_string[1].isdigit(): uid = int(broken_string[1]) - item_info = sale_tree.get_uid(uid) + if uid <= MAX_INVENTORY: + item_info = sale_tree.get_uid(uid) + elif uid > MAX_INVENTORY and uid <= MAX_STORAGE: + item_info = stack_tree.get_uid(uid) + else: + item_info = delisted_tree.get_uid(uid) if item_info == -10: mapserv.sendall(whisper(nick, "Item not found. Please check the uid number and try again.")) @@ -480,6 +550,9 @@ def process_whisper(nick, msg, mapserv): if not trader_state.Trading.testandset(): mapserv.sendall(whisper(nick, "I'm currently busy with a trade. Try again shortly")) return + if not storage.Open.testandset(): + mapserv.sendall(whisper(nick, "I'm currently busy with storage. Try again shortly")) + return trader_state.item = item player_id = beingManager.findId(nick) @@ -501,7 +574,10 @@ def process_whisper(nick, msg, mapserv): if broken_string[1].isdigit() and broken_string[2].isdigit(): amount = int(broken_string[1]) uid = int(broken_string[2]) - item_info = sale_tree.get_uid(uid) + if uid <= MAX_INVENTORY: + item_info = sale_tree.get_uid(uid) + else: + item_info = stack_tree.get_uid(uid) if item_info == -10: mapserv.sendall(whisper(nick, "Item not found. Please check the uid number and try again.")) @@ -526,6 +602,9 @@ def process_whisper(nick, msg, mapserv): if not trader_state.Trading.testandset(): mapserv.sendall(whisper(nick, "I'm currently busy with a trade. Try again shortly")) return + if not storage.Open.testandset(): + mapserv.sendall(whisper(nick, "I'm currently buse with storage. Try again shortly")) + return trader_state.item = item player_id = beingManager.findId(nick) @@ -560,43 +639,6 @@ def process_whisper(nick, msg, mapserv): elif check == -10: mapserv.sendall(whisper(nick, "User removal failed. Please check spelling.")) - elif broken_string[0] == "!relist": - # Relist an item which has expired - !relist . - if user == -10 or len(broken_string) != 2: - mapserv.sendall(whisper(nick, "Syntax incorrect.")) - return - - if int(user.get("accesslevel")) < 5: - mapserv.sendall(whisper(nick, "You don't have the correct permissions.")) - return - - if broken_string[1].isdigit(): - uid = int(broken_string[1]) - item_info = sale_tree.get_uid(uid) - - if item_info == -10: - mapserv.sendall(whisper(nick, "Item not found. Please check the uid number and try again.")) - return - - if item_info.get('name') != nick: - mapserv.sendall(whisper(nick, "That doesn't belong to you!")) - return - - time_relisted = int(item_info.get('relisted')) - - if int(item_info.get('relisted')) < 3: - sale_tree.get_uid(uid).set('add_time', str(time.time())) - sale_tree.get_uid(uid).set('relisted', str(time_relisted + 1)) - sale_tree.save() - mapserv.sendall(whisper(nick, "The item has been successfully relisted.")) - user_tree.get_user(nick).set('last_use', str(time.time())) - user_tree.save() - else: - mapserv.sendall(whisper(nick, "This item can no longer be relisted. Please collect it using !getback "+str(uid)+".")) - return - else: - mapserv.sendall(whisper(nick, "Syntax incorrect.")) - elif broken_string[0] == "!getback": # Trade the player back uid, remove from sale_items if trade successful - !getback . if user == -10 or len(broken_string) != 2: @@ -609,7 +651,12 @@ def process_whisper(nick, msg, mapserv): if broken_string[1].isdigit(): uid = int(broken_string[1]) - item_info = sale_tree.get_uid(uid) + if uid <= MAX_INVENTORY: + item_info = sale_tree.get_uid(uid) + elif uid > MAX_INVENTORY and uid <= MAX_STORAGE: + item_info = stack_tree.get_uid(uid) + else: + item_info = delisted_tree.get_uid(uid) if item_info == -10: mapserv.sendall(whisper(nick, "Item not found. Please check the uid number and try again.")) @@ -630,6 +677,9 @@ def process_whisper(nick, msg, mapserv): if not trader_state.Trading.testandset(): mapserv.sendall(whisper(nick, "I'm currently busy with a trade. Try again shortly")) return + if not storage.Open.testandset(): + mapserv.sendall(whisper(nick, "I'm currently busy with storage. Try again shortly")) + return trader_state.item = item player_id = beingManager.findId(nick) @@ -785,6 +835,12 @@ def main(): logger.info("Trade Cancelled - Timeout.") trader_state.timer = time.time() mapserv.sendall(str(PacketOut(CMSG_TRADE_CANCEL_REQUEST))) + + # The same applies to storage, now + if storage.Open.test(): + if time.time() - storage.timer > 2*60: + logger.info("Storage operation cancelled - Timeout.") + mapserv.sendall(str(PacketOut(CMSG_CLOSE_STORAGE))) for packet in pb: if packet.is_type(SMSG_MAP_LOGIN_SUCCESS): # connected @@ -868,12 +924,17 @@ def main(): err = packet.read_int8() if err == 0: - if item.index in player_node.inventory: - player_node.inventory[item.index].amount += item.amount - else: - player_node.inventory[item.index] = item + if len(player_node.inventory) <= MAX_INVENTORY: + if item.index in player_node.inventory: + player_node.inventory[item.index].amount += item.amount + else: + player_node.inventory[item.index] = item + placement = "Inventory" + else: # If only one slot left, move to stack + item.index = storage.add_item(item) + placement = "Storage" - logger.info("Picked up: %s, Amount: %s, Index: %s", ItemDB.getItem(item.itemId).name, str(item.amount), str(item.index)) + logger.info("Picked up: %s, Amount: %s, Index: %s - %s", ItemDB.getItem(item.itemId).name, str(item.amount), str(item.index), placement) elif packet.is_type(SMSG_PLAYER_INVENTORY_REMOVE): index = packet.read_int16() - inventory_offset @@ -882,6 +943,24 @@ def main(): logger.info("Remove item: %s, Amount: %s, Index: %s", ItemDB.getItem(player_node.inventory[index].itemId).name, str(amount), str(index)) player_node.remove_item(index, amount) + # Now taking an item from stack if inventory was full before + if len(player_node.inventory) == MAX_INVENTORY-1: + elem = stack_tree.get_uid(stack_tree.next_id) + index = storage.find_storage_index(int(elem.get('itemId'))) + storage.storage_open(mapserv) + try: + storage.storage_get(mapserv, index, elem.get('amount')) + except: + print ("Couldn't remove item from storage") + storage.storage_close(mapserv) + pass + + storage.storage_close(mapserv) + storage.remove_item(index, int(elem.get('amount'))) + sale_tree.add_item(elem.get('name'), int(elem.get('itemId')), int(elem.get('amount')), int(elem.get('price'))) + stack_tree.remove_item_uid(stack_tree.next_id) + + elif packet.is_type(SMSG_PLAYER_INVENTORY): player_node.inventory.clear() # Clear the inventory - incase of new index. packet.skip(2) @@ -920,6 +999,49 @@ def main(): else: logger.info("Inventory Check Passed.") + # IMO the best moment to run delisting + storage.storage_open(mapserv) + do_delist() + storage.storage_close(mapserv) + + elif packet.is_type(SMSG_PLAYER_STORAGE_ITEMS): + storage.storage.clear() # Clear storage - same as inventory. + packet.skip(2) + number = (len(packet.data)-2) / 18 + for loop in range(number): + item = Item() + item.index = packet.read_int16() - storage_offset + item.itemId = packet.read_int16() + packet.skip(2) + item.amount = packet.read_int16() + packet.skip(10) + storage.storage[item.index] = item + + elif packet.is_type(SMSG_PLAYER_STORAGE_EQUIP): + packet.read_int16() + number = (len(packet.data)) / 20 + for loop in range(number): + item = Item() + item.index = packet.read_int16() - storage_offset + item.itemId = packet.read_int16() + packet.skip(16) + item.amount = 1 + storage.storage[item.index] = item + + logger.info("Storage information received:") + for item in storage.storage: + logger.info("Name: %s, Id: %s, Index: %s, Amount: %s.", \ + ItemDB.getItem(storage.storage[item].itemId).name, \ + storage.storage[item].itemId, item, storage.storage[item].amount) + + errorOccured = storage.check_storage(stack_tree, delisted_tree) + if errorOccured: + logger.info(errorOccured) + shop_broadcaster.stop() + sys.exit(1) + else: + logger.info("Storage Check Passed.") + elif packet.is_type(SMSG_TRADE_REQUEST): name = packet.read_string(24) logger.info("Trade request: " + name) @@ -1060,24 +1182,39 @@ def main(): elif packet.is_type(SMSG_TRADE_COMPLETE): commitMessage="" - # The sale_tree is only ammended after a complete trade packet. + # we get here which tree it should be through UID + if trader_state.item.get == 1: + if len(player_node.inventory) <= MAX_INVENTORY: + tree = sale_tree + else: + tree = stack_tree + elif trader_state.item.get == 0: + if trader_state.item.uid <= MAX_INVENTORY: + tree = sale_tree + elif trader_state.item.uid > MAX_INVENTORY \ + and trader_state.item.uid <= MAX_STORAGE: + tree = stack_tree + else: + tree = delisted_tree + + # The trees are only ammended after a complete trade packet. if trader_state.item and trader_state.money == 0: if trader_state.item.get == 1: # !add - sale_tree.add_item(trader_state.item.player, trader_state.item.id, trader_state.item.amount, trader_state.item.price) + tree.add_item(trader_state.item.player, trader_state.item.id, trader_state.item.amount, trader_state.item.price) user_tree.get_user(trader_state.item.player).set('used_stalls', \ str(int(user_tree.get_user(trader_state.item.player).get('used_stalls')) + 1)) user_tree.get_user(trader_state.item.player).set('last_use', str(time.time())) commitMessage = "Add" elif trader_state.item.get == 0: # !buy \ !getback - seller = sale_tree.get_uid(trader_state.item.uid).get('name') - item = sale_tree.get_uid(trader_state.item.uid) + seller = tree.get_uid(trader_state.item.uid).get('name') + item = tree.get_uid(trader_state.item.uid) current_amount = int(item.get("amount")) - sale_tree.get_uid(trader_state.item.uid).set("amount", str(current_amount - trader_state.item.amount)) + tree.get_uid(trader_state.item.uid).set("amount", str(current_amount - trader_state.item.amount)) if int(item.get("amount")) == 0: - user_tree.get_user(sale_tree.get_uid(trader_state.item.uid).get('name')).set('used_stalls', \ - str(int(user_tree.get_user(sale_tree.get_uid(trader_state.item.uid).get('name')).get('used_stalls'))-1)) - sale_tree.remove_item_uid(trader_state.item.uid) + user_tree.get_user(tree.get_uid(trader_state.item.uid).get('name')).set('used_stalls', \ + str(int(user_tree.get_user(tree.get_uid(trader_state.item.uid).get('name')).get('used_stalls'))-1)) + tree.remove_item_uid(trader_state.item.uid) current_money = int(user_tree.get_user(seller).get("money")) user_tree.get_user(seller).set("money", str(current_money + trader_state.item.price * trader_state.item.amount)) @@ -1090,7 +1227,7 @@ def main(): user_tree.get_user(trader_state.money).set('money', str(0)) commitMessage = "Money" - sale_tree.save() + tree.save() user_tree.save() tradey.saveData(commitMessage) @@ -1102,6 +1239,10 @@ def main(): logger.info(errorOccured) shop_broadcaster.stop() sys.exit(1) + + elif packet.is_type(SMSG_PLAYER_STORAGE_CLOSE): + storage.reset() + else: pass diff --git a/net/packet_out.py b/net/packet_out.py index 1d6e2d2..fea93d4 100644 --- a/net/packet_out.py +++ b/net/packet_out.py @@ -15,9 +15,8 @@ def whisper(nick, message): def chat(text): chat_packet = PacketOut(CMSG_CHAT_MESSAGE) - mes = player_node.name + " : " + text - chat_packet.write_int16(len(mes) + 4 + 1) - chat_packet.write_string(mes, len(mes) + 1) + chat_packet.write_int16(len(text) + 4 + 1) + chat_packet.write_string(text, len(text) + 1) return str(chat_packet) def sit(val): diff --git a/net/protocol.py b/net/protocol.py index 4a4b74f..cfc17e0 100644 --- a/net/protocol.py +++ b/net/protocol.py @@ -23,6 +23,13 @@ SMSG_PLAYER_EQUIPMENT = 0x00a4 SMSG_PLAYER_STAT_UPDATE_1 = 0x00b0 SMSG_PLAYER_STAT_UPDATE_2 = 0x00b1 +SMSG_PLAYER_STORAGE_EQUIP = 0x00a6 +SMSG_PLAYER_STORAGE_ITEMS = 0x01f0 +SMSG_PLAYER_STORAGE_STATUS = 0x00f2 +SMSG_PLAYER_STORAGE_ADD = 0x00f4 +SMSG_PLAYER_STORAGE_REMOVE = 0x00f6 +SMSG_PLAYER_STORAGE_CLOSE = 0x00f8 + SMSG_BEING_VISIBLE = 0x0078 SMSG_BEING_MOVE = 0x007b SMSG_BEING_REMOVE = 0x0080 @@ -41,6 +48,10 @@ CMSG_PLAYER_CHANGE_DEST = 0x0085 CMSG_PLAYER_EMOTE = 0x00bf SMSG_WALK_RESPONSE = 0x0087 +CMSG_MOVE_TO_STORAGE = 0x00f3 +CMSG_MOVE_FROM_STORAGE = 0x00f5 +CMSG_CLOSE_STORAGE = 0x00f7 + CMSG_TRADE_REQUEST = 0x00e4 CMSG_TRADE_RESPONSE = 0x00e6 CMSG_TRADE_ITEM_ADD_REQUEST = 0x00e8 @@ -62,3 +73,6 @@ SMSG_ITEM_REMOVE = 0x00a1 inventory_offset = 2 storage_offset = 1 +MAX_STORAGE = 300 +MAX_INVENTORY = 99 +MAX_AMOUNT = 30000 diff --git a/storage.py b/storage.py new file mode 100644 index 0000000..a098ac6 --- /dev/null +++ b/storage.py @@ -0,0 +1,114 @@ +#!/usr/bin/python + +""" + Copyright 2011, Dipesh Amin + Copyright 2011, Stefan Beller + + This file is part of tradey, a trading bot in the mana world + see www.themanaworld.org + + Storage Access class by Fernanda Monteiro +""" + +from utils import ItemDB +from net.packet_out import chat +from net.protocol import * +from net.packet import * +import time +import copy +import mutex + +class Storage: + def __init__(self): + self.storage = {} + self.timer = 0 + self.Open = mutex.mutex() + def reset(self): + self.Open.unlock() + self.timer = 0 + + def find_storage_index(self, item_id): + for item in self.storage: + if item > 1: + if self.storage[item].itemId == item_id: + return item + return -10 # Not found - bug somewhere! + + def add_item(self, item): + if not item.itemId or item.amount <= 0: + return -10 # Not an item - something is messy + + index = self.find_storage_index(item.itemId) + if ItemDB().getItem(item.itemId).type != 'equip-ammo' and 'equip': + if index != -10: + if (item.amount > MAX_AMOUNT - self.storage[index].amount): + return -10 + self.storage[index].amount += item.amount + return 0 + + index = len(self.storage) + self.storage[index] = item + self.storage[index].amount = item.amount + return index + + def remove_item(self, index, amount): + if index in self.storage: + self.storage[index].amount -= amount + if self.storage[index].amount == 0: + del self.storage[index] + + def check_storage(self, stack_tree, delisted_tree): + # Check the inventory state. + test_node = copy.deepcopy(self.storage) + for elem in stack_tree.root: + item_found = False + for item in test_node: + if int(elem.get('itemId')) == test_node[item].itemId \ + and int(elem.get('amount')) <= test_node[item].amount: + test_node[item].amount -= int(elem.get('amount')) + if test_node[item].amount == 0: + del test_node[item] + item_found = True + break + + if not item_found: + return "Server and client storage out of sync." + + for elem in delisted_tree.root: + item_found = False + for item in test_node: + if int(elem.get('itemId')) == test_node[item].itemId \ + and int(elem.get('amount')) <= test_node[item].amount: + test_node[item].amount -= int(elem.get('amount')) + if test_node[item].amount == 0: + del test_node[item] + item_found = True + break + + if not item_found: + return "Server and client storage out of sync." + + def storage_send(self, mapserv, index, amount): + packet = PacketOut(CMSG_MOVE_TO_STORAGE) + packet.write_int16(index + inventory_offset) + packet.write_int32(amount) + mapserv.sendall(str(packet)) + return 0 + + def storage_get(self, mapserv, index, amount): + packet = PacketOut(CMSG_MOVE_FROM_STORAGE) + packet.write_int16(index + storage_offset) + packet.write_int32(amount) + mapserv.sendall(str(packet)) + return 0 + + def storage_open(self, mapserv): + mapserv.sendall(chat("@storage")) + self.timer = time.time() + + def storage_close(self, mapserv): + mapserv.sendall(str(PacketOut(CMSG_CLOSE_STORAGE))) + +if __name__ == '__main__': + print "Do not run this file directly. Run main.py" + diff --git a/tradey.py b/tradey.py index 01f855e..4172a63 100644 --- a/tradey.py +++ b/tradey.py @@ -61,19 +61,20 @@ class UserTree: class ItemTree: def __init__(self): - self.tree = ElementTree(file="data/sale.xml") + self.save_file = 'data/sale.xml' + self.tree = ElementTree(file=self.save_file) self.root = self.tree.getroot() self.u_id = set() + self.id_itter = 1 for elem in self.root: self.u_id.add(int(elem.get("uid"))) def getId(self): - id_itter = 1 - while id_itter in self.u_id: - id_itter += 1 + while self.id_itter in self.u_id: + self.id_itter += 1 self.u_id.add(id_itter) - return id_itter + return self.id_itter def remove_id(self, uid): # Free up used id's. @@ -85,7 +86,6 @@ class ItemTree: user.set("itemId", str(item_id)) user.set("price", str(price)) user.set("add_time", str(time.time())) - user.set("relisted", str(0)) user.set("amount", str(amount)) user.set("uid", str(self.getId())) self.save() @@ -107,11 +107,77 @@ class ItemTree: def save(self): # Be sure to call save() after any changes to the tree. - f = open('data/sale.xml', 'w') + f = open(self.save_file, 'w') dom = xml.dom.minidom.parseString(clean_xml(tostring(self.root))) f.write(dom.toprettyxml(' ')) f.close() +class StackTree(ItemTree): + def __init__(self): + self.save_file = 'data/stack.xml' + self.tree = ElementTree(file=self.save_file) + self.root = self.tree.getroot() + self.u_id = set() + self.id_itter = 101 + self.next_id = self.id_itter + + for elem in self.root: + self.u_id.add(int(elem.get("uid"))) + + def add_item(self, name, item_id, amount, price): + user = SubElement(self.root, "item") + user.set("name", name) + user.set("itemId", str(item_id)) + user.set("price", str(price)) + user.set("amount", str(amount)) + user.set("uid", str(self.getId())) + self.save() + + # Here we take the oldest id put into stack.xml so we have FIFO + def get_next_id(self): + if len(self.u_id) == 0: + self.next_id = self.id_itter + return + else: + # TODO Here I'm handling rotation (gets a high number then + # back to 101). Any better manners to do this? + if min(self.u_id) - self.next_id < 0: + next_uid = self.next_id - min(self.u_id) + self.next_id = self.id_itter + next_uid + 1 + else: + next_uid = min(self.u_id) - self.next_id + self.next_id += next_uid + return + + + def remove_item_uid(self, uid): + for elem in self.root: + if elem.get("uid") == str(uid): + self.root.remove(elem) + self.remove_id(uid) + self.save() + self.get_next_id() + return 1 + return -10 + +class DelistedTree(ItemTree): + def __init__(self): + self.save_file = 'data/delisted.xml' + self.tree = ElementTree(file=self.save_file) + self.root = self.tree.getroot() + self.u_id = set() + self.id_itter = 301 + + for elem in self.root: + self.u_id.add(int(elem.get("uid"))) + + def add_item(self, name, item_id, amount): + user = SubElement(self.root, "item") + user.set("name", name) + user.set("itemId", str(item_id)) + user.set("amount", str(amount)) + user.set("uid", str(self.getId())) + def saveData(commitmessage = "commit"): # This assumes the current working directory is the tradey directory. os.chdir("data") diff --git a/utils.py b/utils.py index 52d51b6..542b7af 100644 --- a/utils.py +++ b/utils.py @@ -86,6 +86,15 @@ class ItemLog: file_node.write(str(item_id)+" "+str(amount)+" "+str(price)+" "+str(time.time())+" "+name+"\n") file_node.close() +class DelistedLog: + def __init__(self): + self.log_file = 'data/logs/delisted.log' + + def add_item(self, item_id, amount, name): + file_node = open(self.log_file, 'a') + file_node.write(str(item_id)+" "+str(amount)+" "+str(time.time())+" "+name+"\n") + file_node.close() + class TraderState: """ Stores information regarding a trade request""" def __init__(self): -- cgit v1.2.3-60-g2f50