diff options
author | Rawng <rawng.github@gmail.com> | 2015-06-01 19:56:10 -0400 |
---|---|---|
committer | Rawng <rawng.github@gmail.com> | 2015-06-01 19:56:10 -0400 |
commit | 1e8140f0f62ecfd0ccbe046cf6ea9faed926f327 (patch) | |
tree | ca92a7a0cd2256ffbb0b43563ee183400d1aacc5 | |
parent | b4f19a8e28cf09b7c8a042c8faf068217669bca5 (diff) | |
parent | b7e3823588ae9354daf5fc0a0cbf27b699afb7d5 (diff) | |
download | manamarket-1e8140f0f62ecfd0ccbe046cf6ea9faed926f327.tar.gz manamarket-1e8140f0f62ecfd0ccbe046cf6ea9faed926f327.tar.bz2 manamarket-1e8140f0f62ecfd0ccbe046cf6ea9faed926f327.tar.xz manamarket-1e8140f0f62ecfd0ccbe046cf6ea9faed926f327.zip |
Merge branch 'storage'
-rw-r--r-- | config.py.template | 2 | ||||
-rw-r--r-- | data_template/delisted.xml | 2 | ||||
-rw-r--r-- | data_template/stack.xml | 2 | ||||
-rwxr-xr-x | main.py | 307 | ||||
-rw-r--r-- | net/packet_out.py | 5 | ||||
-rw-r--r-- | net/protocol.py | 14 | ||||
-rw-r--r-- | storage.py | 117 | ||||
-rw-r--r-- | tradey.py | 83 | ||||
-rw-r--r-- | utils.py | 23 |
9 files changed, 478 insertions, 77 deletions
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 @@ +<?xml version="1.0" ?> +<items/> 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 @@ +<?xml version="1.0" ?> +<items/> @@ -22,7 +22,6 @@ this program. If not, see <http://www.gnu.org/licenses/>. Additionally to the GPL, you are *strongly* encouraged to share any modifications you do on these sources. """ - import logging import logging.handlers import socket @@ -41,6 +40,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 +50,74 @@ 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(item.index, item.amount) + except: + logger.info("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(int(elem.get('uid'))) + DelistedLog.add_item(item.itemId, item.amount, elem.get('name')) + cleaned += 1 + if cleaned > 0: + logger.info("Delisting routine done. %d items added to delisted.xml", cleaned) + stacked = len(stack_tree.u_id) + if stacked > 0: + if cleaned - stacked < 0: + stacked = cleaned + while stacked: + err = unstack() + if err == -10: + return err + else: + stacked -= 1 + return 0 + +def unstack(): + elem = stack_tree.get_uid(stack_tree.next_id) + index = storage.find_storage_index(int(elem.get('itemId'))) + try: + storage.storage_get(index, int(elem.get('amount'))) + except: + logger.info("Couldn't remove item from storage") + return -10 + + 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) + return 0 + +def storage_operation(func, args=[]): + storage.storage_open() + # Using a timed thread here to wait storage response. + # Main reason: time.sleep() stops execution, thus it denies storage to open. Yeah, that bad. + timer = utils.CustomTimer(2.0, func, args) + timer.start() + result = timer.join() + if timer.finished: + storage.storage_close() + return result + def process_whisper(nick, msg, mapserv): msg = filter(lambda x: x in utils.allowed_chars, msg) if len(msg) == 0: @@ -90,7 +152,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)) @@ -100,7 +162,7 @@ def process_whisper(nick, msg, mapserv): data = '\302\202B1' for elem in sale_tree.root: - if time.time() - float(elem.get('add_time')) < config.relist_time: + if time.time() - float(elem.get('add_time')) < config.delist_time: # Check if an items time is up. data += utils.encode_str(int(elem.get("itemId")), 2) data += utils.encode_str(int(elem.get("price")), 4) data += utils.encode_str(int(elem.get("amount")), 3) @@ -131,10 +193,10 @@ 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: + if time.time() - float(elem.get('add_time')) < config.delist_time: msg = "[selling] [" + else: + msg = "[expired] [" 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 +207,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 +249,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 <id> or <Item Name>, !buy <amount> <uid>, !add <amount> <price> <Item Name>, !money, !relist <uid>, !info, !getback <uid> ")) + mapserv.sendall(whisper(nick, "The basic commands for the bot are: !list, !find <id> or <Item Name>, !buy <amount> <uid>, !add <amount> <price> <Item Name>, !money, !info, !getback <uid> ")) mapserv.sendall(whisper(nick, "For a detailed description of each command, type !help <command> 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 +281,6 @@ def process_whisper(nick, msg, mapserv): mapserv.sendall(whisper(nick, "!add <amount> <price> <Item Name> - 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 <uid> - 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': @@ -217,6 +307,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.money = nick player_id = beingManager.findId(nick) @@ -238,20 +331,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 +372,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 +390,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 +592,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 +616,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 +644,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 +681,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 <uid>. - 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 <uid>. if user == -10 or len(broken_string) != 2: @@ -609,7 +693,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,10 +719,16 @@ 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) if player_id != -10: + if uid > MAX_INVENTORY: + item.index = storage.find_storage_index(item.id) + storage_operation(storage.storage_get, (item.index, item.amount)) mapserv.sendall(trade_request(player_id)) trader_state.timer = time.time() else: @@ -770,6 +865,7 @@ def main(): pb = PacketBuffer() shop_broadcaster.mapserv = mapserv + storage.mapserv = mapserv # Map server packet loop print "Entering map packet loop\n"; @@ -785,6 +881,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.") + storage.storage_close() for packet in pb: if packet.is_type(SMSG_MAP_LOGIN_SUCCESS): # connected @@ -870,12 +972,19 @@ 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 + err = storage_operation(storage.storage_send, (item.index, item.amount)) + if err == 0: + 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 @@ -884,6 +993,10 @@ 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: + storage_operation(unstack) + elif packet.is_type(SMSG_PLAYER_INVENTORY): player_node.inventory.clear() # Clear the inventory - incase of new index. packet.skip(2) @@ -922,6 +1035,47 @@ def main(): else: logger.info("Inventory Check Passed.") + # IMO the best moment to run delisting + storage_operation(do_delist) + + 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) @@ -1062,24 +1216,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)) @@ -1092,7 +1261,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) @@ -1104,6 +1273,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..873f087 100644 --- a/net/packet_out.py +++ b/net/packet_out.py @@ -15,8 +15,11 @@ def whisper(nick, message): def chat(text): chat_packet = PacketOut(CMSG_CHAT_MESSAGE) - mes = player_node.name + " : " + text + #TODO Find another automated manner to get ManaMarket name (previous didn't work either) + # Maybe a temp solution would be setting as a variable in config.py + mes = "ManaMarket"+" : "+text chat_packet.write_int16(len(mes) + 4 + 1) + # chat_packet = PacketOut(CMSG_CHAT_MESSAGE) chat_packet.write_string(mes, len(mes) + 1) return str(chat_packet) diff --git a/net/protocol.py b/net/protocol.py index fc64767..c8f4a6e 100644 --- a/net/protocol.py +++ b/net/protocol.py @@ -24,6 +24,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 @@ -42,6 +49,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 @@ -63,3 +74,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..8afda66 --- /dev/null +++ b/storage.py @@ -0,0 +1,117 @@ +#!/usr/bin/python + +""" + Copyright 2011, Dipesh Amin <yaypunkrock@gmail.com> + Copyright 2011, Stefan Beller <stefanbeller@googlemail.com> + + This file is part of tradey, a trading bot in the mana world + see www.themanaworld.org + + Storage Access class by Fernanda Monteiro <crie.fernanda@gmail.com> +""" + +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.mapserv = 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 index + + 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, index, amount): + packet = PacketOut(CMSG_MOVE_TO_STORAGE) + packet.write_int16(index + inventory_offset) + packet.write_int32(amount) + self.mapserv.sendall(str(packet)) + return 0 + + def storage_get(self, index, amount): + packet = PacketOut(CMSG_MOVE_FROM_STORAGE) + packet.write_int16(index + storage_offset) + packet.write_int32(amount) + self.mapserv.sendall(str(packet)) + return 0 + + def storage_open(self): + self.timer = time.time() + self.mapserv.sendall(chat("@storage")) + + def storage_close(self): + self.reset() + self.mapserv.sendall(str(PacketOut(CMSG_CLOSE_STORAGE))) + +if __name__ == '__main__': + print "Do not run this file directly. Run main.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 - self.u_id.add(id_itter) - return id_itter + while self.id_itter in self.u_id: + self.id_itter += 1 + self.u_id.add(self.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,78 @@ 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() + return 1 + self.get_next_id() + 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())) + self.save() + def saveData(commitmessage = "commit"): # This assumes the current working directory is the tradey directory. os.chdir("data") @@ -13,6 +13,7 @@ import time import mutex import threading from net.packet_out import * +from threading import _Timer allowed_chars = "abcdefghijklmnoprstquvwxyzABCDEFGHIJKLMNOPRSTQUVWXYZ1234567890-_+=!@$%^&*();'<>,.?/~`| " @@ -86,6 +87,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): @@ -129,5 +139,18 @@ class Broadcast: self.Active = False self.shop_broadcast.join() +class CustomTimer(_Timer): + def __init__(self, interval, function, args=[], kwargs={}): + self._original_function = function + super(CustomTimer, self).__init__(interval, self._do_execute, args, kwargs) + self._result = None + + def _do_execute(self, *a, **kw): + self._result = self._original_function(*a, **kw) + + def join(self): + super(CustomTimer, self).join() + return self._result + if __name__ == '__main__': print "Do not run this file directly. Run main.py" |