def parseResponse(self): noMeatPattern = PatternManager.getOrCompilePattern( 'traderHasNotEnoughMeat') if noMeatPattern.search(self.responseText): raise Error.Error( "You don't have as much meat as you're promising.", Error.NOT_ENOUGH_MEAT) noItemsPattern = PatternManager.getOrCompilePattern( 'traderHasNotEnoughItems') if noItemsPattern.search(self.responseText): raise Error.Error( "You don't have as many items as you're promising.", Error.NOT_ENOUGH_ITEMS) #Not testing for an offer being cancelled due to a bug in KoL - space reserved successPattern = PatternManager.getOrCompilePattern( 'tradeResponseSentSuccessfully') if successPattern.search(self.responseText): Report.trace( "request", "Response to trade " + str(self.requestData['whichoffer']) + ' sent successfully.') else: raise Error.Error( "Unknown error sending response to trade " + str(self.requestData['whichoffer']), Error.REQUEST_GENERIC)
def getItemFromId(itemId, session=None): "Returns information about an item given its ID." global __dbChanged if not __isInitialized: init() try: return __itemsById[itemId].copy() except KeyError: try: if session is None: raise KeyError() from kol.request.ItemInformationRequest import ItemInformationRequest r = ItemInformationRequest(session, itemId) result = r.doRequest() item = result["item"] addItem(item) Report.trace("itemdatabase", "Discovered new item: %s" % item["name"]) context = {"item": item} FilterManager.executeFiltersForEvent("discoveredNewItem", context, session=session, item=item) __dbChanged = True return item except (KeyError, Error.Error): raise Error.Error("Item ID %s is unknown." % itemId, Error.ITEM_NOT_FOUND)
def parseResponse(self): ignorePattern = PatternManager.getOrCompilePattern("traderIgnoringUs") if ignorePattern.search(self.responseText): raise Error.Error("That player has you on his/her ignore list.", Error.USER_IS_IGNORING) roninPattern = PatternManager.getOrCompilePattern("traderIsInRoninHC") if roninPattern.search(self.responseText): raise Error.Error("That player is in Ronin or HC and cannot receive trade offers.", Error.USER_IN_HARDCORE_RONIN) itemsPattern = PatternManager.getOrCompilePattern("traderHasNotEnoughItems") if itemsPattern.search(self.responseText): raise Error.Error("You don't have enough of one or more of the items you're trying to trade.", Error.NOT_ENOUGH_ITEMS) meatPattern = PatternManager.getOrCompilePattern("traderHasNotEnoughMeat") if meatPattern.search(self.responseText): raise Error.Error("You don't have as much meat as you're trying to trade.", Error.NOT_ENOUGH_MEAT) chatBannedPattern = PatternManager.getOrCompilePattern("traderBannedFromChat") if chatBannedPattern.search(self.responseText): raise Error.Error("You are banned from chat and consequently cannot trade.", Error.BANNED_FROM_CHAT) successPattern = PatternManager.getOrCompilePattern("tradeSentSuccessfully") if successPattern.search(self.responseText): Report.trace("request", "Trade offer sent successfully.") else: raise Error.Error("Other error sending trade offer.", Error.ERROR)
def discoverMissingItems(session): global __isLoaded if not __isLoaded: loadItemsFromFile() newInformation = False from kol.request.InventoryRequest import InventoryRequest from kol.request.ItemInformationRequest import ItemInformationRequest invRequest = InventoryRequest(session) invRequest.ignoreItemDatabase = True invData = invRequest.doRequest() for item in invData["items"]: if item["id"] not in __itemsById: try: itemRequest = ItemInformationRequest(session, item["id"]) itemData = itemRequest.doRequest() item = itemData["item"] addItem(item) Report.trace("itemdatabase", "Discovered new item: %s" % item["name"]) context = { "item" : item } FilterManager.executeFiltersForEvent("discoveredNewItem", context, session=session, item=item) newInformation = True except: pass if newInformation or not __isLoaded: saveItemsToFile() __isLoaded = True
def discoverMissingItems(session): global __isLoaded if not __isLoaded: loadItemsFromFile() newInformation = False from kol.request.InventoryRequest import InventoryRequest from kol.request.ItemInformationRequest import ItemInformationRequest invRequest = InventoryRequest(session) invRequest.ignoreItemDatabase = True invData = invRequest.doRequest() for item in invData["items"]: if item["id"] not in __itemsById: try: itemRequest = ItemInformationRequest(session, item["id"]) itemData = itemRequest.doRequest() item = itemData["item"] addItem(item) Report.trace("itemdatabase", "Discovered new item: %s" % item["name"]) context = {"item": item} FilterManager.executeFiltersForEvent("discoveredNewItem", context, session=session, item=item) newInformation = True except: pass if newInformation or not __isLoaded: saveItemsToFile() __isLoaded = True
def parseResponse(self): # First parse for errors notEnoughPattern = PatternManager.getOrCompilePattern("dontHaveThatManyInStore") if notEnoughPattern.search(self.responseText): raise Error.Error("You either don't have that item, or not enough", Error.ITEM_NOT_FOUND) # Check if responseText matches the success pattern. If not, raise error. itemTakenSuccessfully = PatternManager.getOrCompilePattern("itemTakenSuccessfully") if itemTakenSuccessfully.search(self.responseText): Report.trace('request', 'Item appears to have been taken') else: raise Error.Error("Something went wrong with the taking of the item.", Error.ITEM_NOT_FOUND)
def parseResponse(self): successPattern = PatternManager.getOrCompilePattern( 'tradeCancelledSuccessfully') if successPattern.search(self.responseText): Report.trace( 'request', "Trade offer " + str(self.requestData['whichoffer']) + " cancelled successfully.") else: raise Error.Error( "Unknown error declining trade offer for trade " + str(self.requestData['whichoffer']), Error.REQUEST_GENERIC)
def parseResponse(self): # Get the timestamp we should send to the server next time we make a request. lastSeenPattern = PatternManager.getOrCompilePattern("chatLastSeen") match = lastSeenPattern.search(self.responseText) self.responseData["lastSeen"] = match.group(1) # Parse the chat messages. text = self.responseText[:self.responseText.find('<!--lastseen')] self.responseData["chatMessages"] = ChatUtils.parseMessages(self.responseText, True) # Trace out unknown messages. for chat in self.responseData["chatMessages"]: if chat["type"] == "unknown": Report.trace("chat", "Unable to parse chat message: %s" % chat)
def parseResponse(self): # Get the timestamp we should send to the server next time we make a request. lastSeenPattern = PatternManager.getOrCompilePattern("chatLastSeen") match = lastSeenPattern.search(self.responseText) self.responseData["lastSeen"] = match.group(1) # Parse the chat messages. text = self.responseText[:self.responseText.find('<!--lastseen')] self.responseData["chatMessages"] = ChatUtils.parseMessages( self.responseText, True) # Trace out unknown messages. for chat in self.responseData["chatMessages"]: if chat["type"] == "unknown": Report.trace("chat", "Unable to parse chat message: %s" % chat)
def run(self): Report.trace('relay', 'Starting RelayServer on port %s...' % self.port) started = False numTries = 0 while not started: try: server = HTTPServer(('', self.port), RelayRequestHandler) started = True except socket.error, inst: numTries += 1 if numTries == 10: raise inst Report.trace('relay', 'Could not listen on port %s. Trying %s instead.' % (self.port, self.port + 1)) self.port += 1
def couldNotFindItem(context, **kwargs): if "session" not in kwargs: return session = kwargs["session"] item = None r = ClosetContentsRequest(session) r.skipParseResponse = True r.doRequest() if "descId" in kwargs: descId = kwargs["descId"] pattern = re.compile("<option value='([0-9]+)' descid='%s'>([^<>]*) \([0-9]+\)<\/option>" % descId) match = pattern.search(r.responseText) if match: item = {"id":int(match.group(1)), "descId":descId, "name":match.group(2)} else: raise ItemNotFoundError("Could not find item associated with description ID '%s'." % descId) elif "itemId" in kwargs: itemId = kwargs["itemId"] pattern = re.compile("<option value='%s' descid='([0-9]+)'>([^<>]*) \([0-9]+\)<\/option>" % itemId) match = pattern.search(r.responseText) if match: item = {"id":itemId, "descId":int(match.group(1)), "name":match.group(2)} else: raise ItemNotFoundError("Could not find item associated with ID '%s'." % itemId) elif "itemName" in kwargs: itemName = kwargs["itemName"] pattern = re.compile("<option value='([0-9]+)' descid='([0-9]+)'>%s \([0-9]+\)<\/option>" % itemName) match = pattern.search(r.responseText) if match: item = {"id":int(match.group(1)), "descId":int(match.group(2)), "name":itemName} else: raise ItemNotFoundError("Could not find item with name '%s'." % itemName) if item != None: r = ItemDescriptionRequest(session, item["descId"]) itemInfo = r.doRequest() for k,v in itemInfo.iteritems(): item[k] = v Report.trace("itemdatabase", "Discovered new item: %s" % item) context["item"] = item FilterManager.executeFiltersForEvent("discoveredNewItem", session=session, item=item)
def parseResponse(self): # First parse for errors notEnoughPattern = PatternManager.getOrCompilePattern("dontHaveEnoughOfItem") if notEnoughPattern.search(self.responseText): raise Error.Error("You don't have that many of that item.", Error.ITEM_NOT_FOUND) dontHaveItemPattern = PatternManager.getOrCompilePattern("dontHaveThatItem") if dontHaveItemPattern.search(self.responseText): raise Error.Error("You don't have that item.", Error.ITEM_NOT_FOUND) # Check if responseText matches the success pattern. If not, raise error. itemAddedSuccessfully = PatternManager.getOrCompilePattern("itemAddedSuccessfully") if itemAddedSuccessfully.search(self.responseText): Report.trace('request', 'Item appears to have been added') else: raise Error.Error("Something went wrong with the adding.", Error.ITEM_NOT_FOUND)
def parseResponse(self): noMeatPattern = PatternManager.getOrCompilePattern('traderHasNotEnoughMeat') if noMeatPattern.search(self.responseText): raise Error.Error("You don't have as much meat as you're promising.", Error.NOT_ENOUGH_MEAT) noItemsPattern = PatternManager.getOrCompilePattern('traderHasNotEnoughItems') if noItemsPattern.search(self.responseText): raise Error.Error("You don't have as many items as you're promising.", Error.NOT_ENOUGH_ITEMS) #Not testing for an offer being cancelled due to a bug in KoL - space reserved successPattern = PatternManager.getOrCompilePattern('tradeResponseSentSuccessfully') if successPattern.search(self.responseText): Report.trace("request", "Response to trade " + str(self.requestData['whichoffer']) + ' sent successfully.') else: raise Error.Error("Unknown error sending response to trade " + str(self.requestData['whichoffer']), Error.REQUEST_GENERIC)
class RelayServer(threading.Thread): """ This class acts as a relay server, allowing users to use a browser to communicate with the KoL servers even if they are already logged in via a script or bot. It works much like the KoLmafia relay browser system by listening to a port on the local machine. Any traffic sent to that port will be relayed to the KoL servers. Eventually, the response will be sent back on the same socket. Note that if the port is already in use, this class will try again with the next highest port number. It will do this a total of 10 times before finally giving up and raising a socket.error exception. """ def __init__(self, session, port=8557): super(RelayServer, self).__init__() self.session = session self.port = port self.haltEvent = threading.Event() def run(self): Report.trace('relay', 'Starting RelayServer on port %s...' % self.port) started = False numTries = 0 while not started: try: server = HTTPServer(('', self.port), RelayRequestHandler) started = True except socket.error, inst: numTries += 1 if numTries == 10: raise inst Report.trace( 'relay', 'Could not listen on port %s. Trying %s instead.' % (self.port, self.port + 1)) self.port += 1 server.relayServer = self Report.trace('relay', 'RelayServer started.') # Handle requests for as long as we can. while (not self.haltEvent.isSet()): server.handle_request() # Shut down the RelayServer. Report.trace('relay', 'Shutting down RelayServer.') server.socket.close()
def openAllGiftPackages(self): Report.trace("kmail", "Opening gift package(s).") giftPackages = {} # Get a list of all gift packages in our inventory. r = InventoryRequest(self.session, which=3) responseData = r.doRequest() items = responseData["items"] for item in items: if "type" in item and item["type"] == "gift package": giftPackages[item["id"]] = item["quantity"] # Open all of the gift packages. for itemId,quantity in giftPackages.iteritems(): for i in range(quantity): r = UseItemRequest(self.session, itemId) r.doRequest()
def openAllGiftPackages(self): Report.trace("kmail", "Opening gift package(s).") giftPackages = {} # Get a list of all gift packages in our inventory. r = InventoryRequest(self.session) responseData = r.doRequest() items = responseData["items"] for item in items: if "type" in item and item["type"] == "gift package": giftPackages[item["id"]] = item["quantity"] # Open all of the gift packages. for itemId,quantity in giftPackages.iteritems(): for i in range(quantity): r = UseItemRequest(self.session, itemId) r.doRequest()
def saveItemsToFile(): global __dbChanged if not __dbChanged: return try: f = open(discoveryFile, 'wb') pickle.dump(__discoveryDate, f) pickle.dump(__itemsById, f) pickle.dump(__itemsByDescId, f) pickle.dump(__itemsByName, f) f.close() Report.trace("itemdatabase", "Wrote %d items to file." % len(__itemsById)) __dbChanged = False except: Report.trace("itemdatabase", "Error opening %s for writing" % (discoveryFile)) deleteItemCache()
def run(self): Report.trace('relay', 'Starting RelayServer on port %s...' % self.port) started = False numTries = 0 while not started: try: server = HTTPServer(('', self.port), RelayRequestHandler) started = True except socket.error, inst: numTries += 1 if numTries == 10: raise inst Report.trace( 'relay', 'Could not listen on port %s. Trying %s instead.' % (self.port, self.port + 1)) self.port += 1
def init(): """ Initializes the ItemDatabase. This method should be called before the database is ever accessed as it ensures that the database is populated with all of the data it needs. """ global __dbChanged __dbChanged = False loadItemsFromFile() global __isInitialized if __isInitialized == True: return Report.trace("itemdatabase", "Initializing the item database.") returnCode = FilterManager.executeFiltersForEvent( "preInitializeItemDatabase") if returnCode == FilterManager.FINISHED: Report.trace("itemdatabase", "Item database initialized.") __isInitialized = True return for item in Items.items: addItem(item) FilterManager.executeFiltersForEvent("postInitializeItemDatabase") __isInitialized = True Report.trace("itemdatabase", "Item database initialized.")
def loadItemsFromFile(): global __dbChanged try: f = open(discoveryFile, 'rb') global __itemsById, __itemsByDescId, __itemsByName, __discoveryDate __discoveryDate = pickle.load(f) if __discoveryDate is None or (datetime.datetime.now() - __discoveryDate) < datetime.timedelta( days=14): __itemsById = pickle.load(f) __itemsByDescId = pickle.load(f) __itemsByName = pickle.load(f) else: Report.trace("itemdatabase", "Item cache expired") __discoveryDate = datetime.datetime.now() __dbChanged = True __itemsById = {} __itemsByDescId = {} __itemsByName = {} saveItemsToFile() f.close() Report.trace("itemdatabase", "Loaded %d items from file." % len(__itemsById)) except: Report.trace("itemdatabase", "Error opening %s for loading" % (discoveryFile)) __discoveryDate = datetime.datetime.now() __dbChanged = True __itemsById = {} __itemsByDescId = {} __itemsByName = {} deleteItemCache()
def parseResponse(self): ignorePattern = PatternManager.getOrCompilePattern("traderIgnoringUs") if ignorePattern.search(self.responseText): raise Error.Error("That player has you on his/her ignore list.", Error.USER_IS_IGNORING) roninPattern = PatternManager.getOrCompilePattern("traderIsInRoninHC") if roninPattern.search(self.responseText): raise Error.Error( "That player is in Ronin or HC and cannot receive trade offers.", Error.USER_IN_HARDCORE_RONIN) itemsPattern = PatternManager.getOrCompilePattern( "traderHasNotEnoughItems") if itemsPattern.search(self.responseText): raise Error.Error( "You don't have enough of one or more of the items you're trying to trade.", Error.NOT_ENOUGH_ITEMS) meatPattern = PatternManager.getOrCompilePattern( "traderHasNotEnoughMeat") if meatPattern.search(self.responseText): raise Error.Error( "You don't have as much meat as you're trying to trade.", Error.NOT_ENOUGH_MEAT) chatBannedPattern = PatternManager.getOrCompilePattern( "traderBannedFromChat") if chatBannedPattern.search(self.responseText): raise Error.Error( "You are banned from chat and consequently cannot trade.", Error.BANNED_FROM_CHAT) successPattern = PatternManager.getOrCompilePattern( "tradeSentSuccessfully") if successPattern.search(self.responseText): Report.trace("request", "Trade offer sent successfully.") else: raise Error.Error("Other error sending trade offer.", Error.ERROR)
def botEndCycle(context, **kwargs): returnCode = FilterManager.CONTINUE bot = kwargs['bot'] # Check for new kmails? aleabot.kmail_check_timer += aleabot.config.get('time_to_sleep') if aleabot.kmail_check_timer >= aleabot.config.get('time_to_sleep_kmail'): Report.trace('bot', 'Enabling doWork:kmail') bot.params['doWork:kmail'] = True aleabot.kmail_check_timer = 0 else: Report.trace('bot', 'Disabling doWork:kmail') bot.params.pop('doWork:kmail', None) # Update clan state in regular intervals (as configured) try: aleabot.clanstate.set_session(bot.session) if aleabot.clanstate.update(aleabot.config.get('clan_state_refresh_time')): Report.info('bot', 'Clan state update successful.') Report.trace('bot', 'I am in clan: ' + repr(aleabot.clanstate.my_clan())) Report.trace('bot', 'I have ' + str(len(aleabot.clanstate.my_whitelists())) + ' whitelists') # Set timer to switch back to home clan if aleabot.home_clan_timer < 0: aleabot.home_clan_timer = 0 except alea.clan.ClanRequestError as err: Report.error('bot', 'Unable to update clan state! Error: ' + str(err)) # Switch to home clan after some delay if aleabot.home_clan_timer >= 0: aleabot.home_clan_timer += aleabot.config.get('time_to_sleep') if aleabot.home_clan_timer >= aleabot.config.get('home_clan_delay'): aleabot.home_clan_timer = -1 # Breakfast now if not yet breakfasted today if 'breakfast' not in bot.states['rollover']: alea.breakfast.breakfast(bot.session) bot.states['rollover']['breakfast'] = True bot.writeState('rollover') # Switch to home clan now home_clan_id = aleabot.config.get('home_clan_id') if home_clan_id > 0 and aleabot.clanstate.my_clan().id() != home_clan_id: Report.info('bot', 'Switching back to home clan.') try: aleabot.clanstate.switch(alea.clan.Clan(home_clan_id, '')) except alea.clan.ClanRequestError as err: Report.error('bot', 'Unable to switch clan! Error: ' + str(err)) return returnCode
def whois(bot, name): Report.trace('bot', 'Whois: ' + name) response = bot.sendChatMessage('/whois ' + name) responsetext = ''.join(x['text'] for x in response) match = re.search(r'<a[^>]*showplayer.php[^>]*><b[^>]*>([A-Za-z0-9_ ]+) \(#([0-9]+)\)</b></a>', responsetext) if match: player_name = match.group(1) player_id = match.group(2) Report.trace('bot', 'Whois resolved: Name: ' + str(player_name)) Report.trace('bot', 'Whois resolved: ID: ' + str(player_id)) return player_name, player_id elif 'Unknown Player: ' in responsetext: raise Error.Error("That player could not be found.", Error.USER_NOT_FOUND) else: Report.warning('bot', 'Unable to parse /whois response: ' + repr(responsetext)) raise Error.Error("Unable to parse /whois response.", Error.REQUEST_GENERIC)
def run(self): Report.trace('relay', 'Starting RelayServer on port %s...' % self.port) server = HTTPServer(('', 8557), RelayRequestHandler) server.relayServer = self Report.trace('relay', 'RelayServer started.') # Launch the relay server URL in a browser window. url = 'http://localhost:%s/main.html' % self.port sysname = os.uname()[0] if sysname == "darwin": os.spawnlp(os.P_NOWAIT, "open", "open", url) else: os.startfile(url) # Handle requests for as long as we can. while (not self.haltEvent.isSet()): server.handle_request() # Shut down the RelayServer. Report.trace('relay', 'Shutting down RelayServer.') server.socket.close()
def init(): """ Initializes the SkillDatabase. This method should be called before the database is ever accessed as it ensures that the database is populated with all of the data it needs. """ global __isInitialized if __isInitialized == True: return Report.trace("skilldatabase", "Initializing the skill database.") cxt = FilterManager.executeFiltersForEvent("preInitializeSkillDatabase") if "returnCode" in cxt and cxt["returnCode"] == FilterManager.FINISHED: Report.trace("skilldatabase", "Skill database initialized.") __isInitialized = True return for skill in Skills.skills: addSkill(skill) FilterManager.executeFiltersForEvent("postInitializeSkillDatabase") __isInitialized = True Report.trace("skilldatabase", "Skill database initialized.")
def init(): """ Initializes the SkillDatabase. This method should be called before the database is ever accessed as it ensures that the database is populated with all of the data it needs. """ global __isInitialized if __isInitialized == True: return Report.trace("skilldatabase", "Initializing the skill database.") returnCode = FilterManager.executeFiltersForEvent("preInitializeSkillDatabase") if returnCode == FilterManager.FINISHED: Report.trace("skilldatabase", "Skill database initialized.") __isInitialized = True return for skill in Skills.skills: addSkill(skill) FilterManager.executeFiltersForEvent("postInitializeSkillDatabase") __isInitialized = True Report.trace("skilldatabase", "Skill database initialized.")
def init(): """ Initializes the ItemDatabase. This method should be called before the database is ever accessed as it ensures that the database is populated with all of the data it needs. """ global __isInitialized if __isInitialized == True: return Report.trace("itemdatabase", "Initializing the item database.") returnCode = FilterManager.executeFiltersForEvent("preInitializeItemDatabase") if returnCode == FilterManager.FINISHED: Report.trace("itemdatabase", "Item database initialized.") __isInitialized = True return for item in Items.items: addItem(item) FilterManager.executeFiltersForEvent("postInitializeItemDatabase") __isInitialized = True Report.trace("itemdatabase", "Item database initialized.")
def init(): """ Initializes the QkillDatabase. This method should be called before the database is ever accessed as it ensures that the database is populated with all of the data it needs. """ global __isInitialized if __isInitialized == True: return Report.trace("questdatabase", "Initializing the quest database.") returnCode = FilterManager.executeFiltersForEvent("preInitializeQuestDatabase") if returnCode == FilterManager.FINISHED: Report.trace("questdatabase", "Quest database initialized.") __isInitialized = True return for quest in Quests.quests: addQuest(quest) FilterManager.executeFiltersForEvent("postInitializeQuestDatabase") __isInitialized = True Report.trace("questdatabase", "Quest database initialized.")
def init(): """ Initializes the QkillDatabase. This method should be called before the database is ever accessed as it ensures that the database is populated with all of the data it needs. """ global __isInitialized if __isInitialized == True: return Report.trace("questdatabase", "Initializing the quest database.") returnCode = FilterManager.executeFiltersForEvent( "preInitializeQuestDatabase") if returnCode == FilterManager.FINISHED: Report.trace("questdatabase", "Quest database initialized.") __isInitialized = True return for quest in Quests.quests: addQuest(quest) FilterManager.executeFiltersForEvent("postInitializeQuestDatabase") __isInitialized = True Report.trace("questdatabase", "Quest database initialized.")
def parseResponse(self): successPattern = PatternManager.getOrCompilePattern('tradeAccepted') if successPattern.search(self.responseText): Report.trace('request', "Trade " + str(self.requestData['whichoffer']) "accepted successfully.") else: raise Error.Error("Unknown error accepted trade " + str(self.requestData['whichoffer']), Error.REQUEST_GENERIC)
def parseResponse(self): successPattern = PatternManager.getOrCompilePattern('tradeCancelledSuccessfully') if successPattern.search(self.responseText): Report.trace('request', "Trade response " + str(self.requestData['whichoffer']) + " cancelled successfully.") else: raise Error.Error("Unknown error declining trade response for trade " + str(self.requestData['whichoffer']), Error.REQUEST_GENERIC)
def deleteItemCache(): try: Report.trace("itemdatabase", "Deleted item cache" % (discoveryFile)) os.remove(discoveryFile) except: pass