-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Recycle Items schedule/force #4513
Changes from all commits
c49f1cc
80acac7
37aac25
037462d
bc58625
62a5ad0
08f0f40
2a9f345
32f0c5d
b8bb2d1
57896ad
7d561a9
bcbec6e
49344e9
ff03f21
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,13 +8,19 @@ | |
from pokemongo_bot.services.item_recycle_worker import ItemRecycler | ||
from pokemongo_bot.tree_config_builder import ConfigException | ||
from pokemongo_bot.worker_result import WorkerResult | ||
from random import uniform | ||
from datetime import datetime as dt, timedelta | ||
|
||
|
||
DEFAULT_MIN_EMPTY_SPACE = 6 | ||
|
||
class RecycleItems(BaseTask): | ||
""" | ||
Recycle undesired items if there is less than five space in inventory. | ||
You can use either item's name or id. For the full list of items see ../../data/items.json | ||
|
||
Can also force a recycle to occur at a pseudo-random time between recycle_force_min and | ||
recycle_force_max minutes. | ||
|
||
It's highly recommended to put this task before move_to_fort and spin_fort task in the config file so you'll most likely be able to loot. | ||
|
||
|
@@ -38,8 +44,14 @@ class RecycleItems(BaseTask): | |
"Revive": {"keep": 0}, | ||
"Max Revive": {"keep": 20}, | ||
"Razz Berry": {"keep": 20} | ||
} | ||
}, | ||
"recycle_wait_min": 1, | ||
"recycle_wait_max": 4, | ||
"recycle_force": true, | ||
"recycle_force_min": "00:00:00", | ||
"recycle_force_max": "00:01:00" | ||
} | ||
|
||
} | ||
""" | ||
SUPPORTED_TASK_API_VERSION = 1 | ||
|
@@ -54,7 +66,56 @@ def initialize(self): | |
self.max_revives_keep = self.config.get('max_revives_keep', None) | ||
self.recycle_wait_min = self.config.get('recycle_wait_min', 1) | ||
self.recycle_wait_max = self.config.get('recycle_wait_max', 4) | ||
self.recycle_force = self.config.get('recycle_force', False) | ||
self.recycle_force_min = self.config.get('recycle_force_min', '00:01:00') | ||
self.recycle_force_max = self.config.get('recycle_force_max', '00:10:00') | ||
self.minInterval = self.getSeconds(self.recycle_force_min) | ||
self.maxInterval = self.getSeconds(self.recycle_force_max) | ||
self._validate_item_filter() | ||
|
||
if self.recycle_force: | ||
self._schedule_next_force() | ||
|
||
def getSeconds(self, strTime): | ||
''' | ||
Return the duration in seconds of a time string | ||
:param strTime: string time of format %H:%M:%S | ||
''' | ||
try: | ||
x = dt.strptime(strTime, '%H:%M:%S') | ||
seconds = int(timedelta(hours=x.hour,minutes=x.minute,seconds=x.second).total_seconds()) | ||
except ValueError: | ||
seconds = 0; | ||
|
||
if seconds < 0: | ||
seconds = 0; | ||
|
||
return seconds | ||
|
||
def _schedule_next_force(self): | ||
''' | ||
Schedule the time aof the next forced recycle. | ||
''' | ||
self._next_force = self._get_next_force_schedule() | ||
self.emit_event( | ||
'next_force_recycle', | ||
formatted="Next forced item recycle at {time}", | ||
data={ | ||
'time': str(self._next_force.strftime("%H:%M:%S")) | ||
} | ||
) | ||
|
||
def _should_force_now(self): | ||
if dt.now() >= self._next_force: | ||
return True | ||
|
||
return False | ||
|
||
def _get_next_force_schedule(self): | ||
now = dt.now() | ||
next_time = now + timedelta(seconds=int(uniform(self.minInterval, self.maxInterval))) | ||
|
||
return next_time | ||
|
||
def _validate_item_filter(self): | ||
""" | ||
|
@@ -77,6 +138,15 @@ def should_run(self): | |
:return: True if the recycling process should be run; otherwise, False. | ||
:rtype: bool | ||
""" | ||
|
||
if self.recycle_force and self._should_force_now(): | ||
self.emit_event( | ||
'force_recycle', | ||
formatted="Forcing item recycle based on schedule" | ||
) | ||
self._schedule_next_force() | ||
return True | ||
|
||
if inventory.Items.get_space_left() <= (DEFAULT_MIN_EMPTY_SPACE if self.min_empty_space is None else self.min_empty_space): | ||
return True | ||
return False | ||
|
@@ -92,24 +162,33 @@ def work(self): | |
if self.should_run(): | ||
|
||
if not (self.max_balls_keep is None): | ||
worker_result = self.recycle_excess_category_max(self.max_balls_keep, [1,2,3,4]) | ||
this_worker_result = self.recycle_excess_category_max(self.max_balls_keep, [1,2,3,4]) | ||
if this_worker_result <> WorkerResult.SUCCESS: | ||
worker_result = this_worker_result | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the first returns error and the second running, what do we keep ? Looks like running, while we want to return error. For now we want to return error if one of them returns error. That’s it. Don’t make it harder than it needs to be with some boolean complementation. One or two weeks ago we had no error state. This bot is moving fast, you can’t predict what will be the fourth state, thus you can’t predict if it should override the error state or not. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As it stands, the function will return "success" provided the final task is successful. That's inaccurate. If any task returns something other than "success", the function should be able to report it accurately, so yes if the first is "running" and the second is "success", then overall the result is "running". There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah ok I see where you're coming from. However, given that none of the tasks called by the recycler actually return "running", is it something worth worrying about? If it is important, I'm happy to take a look, but I can't currently see any possible condition where "RUNNING" will be returned. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Running isn’t returned. That’s why you don’t see it here
But what about the fourth state. The day someone add it, he won’t know he added a bug by overwriting the error result. It’ll be an annoying bug to catch, hard to reproduce. Why not simply avoiding it by not allowing it to happen right now ? |
||
|
||
if not (self.max_potions_keep is None): | ||
worker_result = self.recycle_excess_category_max(self.max_potions_keep, [101,102,103,104]) | ||
this_worker_result = self.recycle_excess_category_max(self.max_potions_keep, [101,102,103,104]) | ||
if this_worker_result <> WorkerResult.SUCCESS: | ||
worker_result = this_worker_result | ||
|
||
if not (self.max_berries_keep is None): | ||
worker_result = self.recycle_excess_category_max(self.max_berries_keep, [701,702,703,704,705]) | ||
this_worker_result = self.recycle_excess_category_max(self.max_berries_keep, [701,702,703,704,705]) | ||
if this_worker_result <> WorkerResult.SUCCESS: | ||
worker_result = this_worker_result | ||
|
||
if not (self.max_revives_keep is None): | ||
worker_result = self.recycle_excess_category_max(self.max_revives_keep, [201,202]) | ||
|
||
inventory.refresh_inventory() | ||
|
||
this_worker_result = self.recycle_excess_category_max(self.max_revives_keep, [201,202]) | ||
if this_worker_result <> WorkerResult.SUCCESS: | ||
worker_result = this_worker_result | ||
for item_in_inventory in inventory.items().all(): | ||
|
||
if self.item_should_be_recycled(item_in_inventory): | ||
# Make the bot appears more human | ||
action_delay(self.recycle_wait_min, self.recycle_wait_max) | ||
# If at any recycling process call we got an error, we consider that the result of this task is error too. | ||
if ItemRecycler(self.bot, item_in_inventory, self.get_amount_to_recycle(item_in_inventory)).work() == WorkerResult.ERROR: | ||
worker_result = WorkerResult.ERROR | ||
worker_result = WorkerResult.ERROR | ||
|
||
return worker_result | ||
|
||
def recycle_excess_category_max(self, category_max, category_items_list): | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
from pokemongo_bot.base_task import BaseTask | ||
from pokemongo_bot import inventory | ||
|
||
|
||
class UpdateWebInventory(BaseTask): | ||
SUPPORTED_TASK_API_VERSION = 1 | ||
|
||
def initialize(self): | ||
pass | ||
|
||
def work(self): | ||
inventory.update_web_inventory() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did you put the recycling based on type after the recycling based on item amount ? The bot is discarding high balls before looking for lower balls to discard instead of highers one. You’re making the recycling based on type useless for people using both of them (with a well configured task).
What do you think @developerllazy ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gotcha. Didn't see that side of things before, but you're right. Happy to switch them back again.
Also happy to put back the inventory refresh (and remove it from bot tick) if this api call is likely to cause issues. Still just a temp fix, as the bot should be able to export inventory to web from its own internal cache without needing to call the api every time. If the current web interface is likely to disappear soon, then that should work for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both issues fixed in the latest commit:
How's that looking?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still don’t get it about the force inventory feature. Apart from that seems promising.