Skip to content
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

Fix missed tts marks #420

Merged
merged 6 commits into from
Jan 31, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@

TP = concurrent.futures.ThreadPoolExecutor()

__version__ = "6.0.0alpha3"
__version__ = "6.0.0alpha4"
7 changes: 3 additions & 4 deletions src/item/data/item_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class ItemType(Enum):
Tome = "tome"
Wand = "wand"
# Custom Types
Cache = "cache"
Compass = "compass"
Consumable = "consumable"
Gem = "gem"
Expand All @@ -41,6 +42,7 @@ class ItemType(Enum):
Sigil = "nightmare sigil"
TemperManual = "temper manual"
Tribute = "tribute"
WhisperingWood = "whispering wood"


def is_armor(item_type: ItemType) -> bool:
Expand All @@ -63,10 +65,7 @@ def is_consumable(item_type: ItemType) -> bool:


def is_mapping(item_type: ItemType) -> bool:
return item_type in [
ItemType.Compass,
ItemType.Sigil,
]
return item_type in [ItemType.Compass, ItemType.Sigil, ItemType.WhisperingWood]


def is_jewelry(item_type: ItemType) -> bool:
Expand Down
15 changes: 12 additions & 3 deletions src/item/descr/read_descr_tts.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,10 @@ def _create_base_item_from_tts(tts_item: list[str]) -> Item | None:
return Item(item_type=ItemType.Material)
if any(tts_item[1].lower().endswith(x) for x in ["gem"]):
return Item(item_type=ItemType.Gem)
if any(tts_item[1].lower().endswith(x) for x in ["cache"]):
return Item(item_type=ItemType.Cache)
if any(tts_item[1].lower().endswith(x) for x in ["whispering wood"]):
return Item(item_type=ItemType.WhisperingWood)
if "rune of" in tts_item[1].lower():
item = Item(item_type=ItemType.Rune)
search_string_split = tts_item[1].lower().split(" rune of ")
Expand Down Expand Up @@ -232,7 +236,10 @@ def _get_item_type(data: str):


def _is_codex_upgrade(tts_section: list[str], item: Item) -> bool:
return any("upgrades an aspect in the codex of power on salvage" in line.lower() for line in tts_section)
for line in tts_section:
if "upgrades an aspect in the codex of power on salvage" in line.lower() or "unlocks new aspect" in line.lower():
return True
return False


def read_descr_mixed(img_item_descr: np.ndarray) -> Item | None:
Expand Down Expand Up @@ -320,11 +327,13 @@ def read_descr() -> Item | None:
is_consumable(item.item_type),
is_mapping(item.item_type),
is_socketable(item.item_type),
item.item_type in [ItemType.Material, ItemType.Tribute],
item.item_type in [ItemType.Material, ItemType.Tribute, ItemType.Cache],
]
):
return item
if all([not is_armor(item.item_type), not is_jewelry(item.item_type), not is_weapon(item.item_type)]):
if all(
[not is_armor(item.item_type), not is_jewelry(item.item_type), not is_weapon(item.item_type), item.item_type != ItemType.Shield]
):
return None
if item.rarity not in [ItemRarity.Legendary, ItemRarity.Mythic, ItemRarity.Unique]:
return item
Expand Down
7 changes: 4 additions & 3 deletions src/scripts/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,14 @@ def reset_canvas(root, canvas):
def reset_item_status(occupied, inv):
for item_slot in occupied:
if item_slot.is_fav:
inv.hover_item(item_slot)
inv.hover_item_with_delay(item_slot)
keyboard.send("space")
if item_slot.is_junk:
inv.hover_item(item_slot)
inv.hover_item_with_delay(item_slot)
keyboard.send("space")
time.sleep(0.13)
time.sleep(0.15)
keyboard.send("space")
time.sleep(0.15)

if occupied:
mouse.move(*Cam().abs_window_to_monitor((0, 0)))
59 changes: 36 additions & 23 deletions src/scripts/handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class ScriptHandler:
def __init__(self):
self.loot_interaction_thread = None
self.script_threads = []
self.vision_mode = src.scripts.vision_mode_tts.VisionMode()

self.setup_key_binds()
if IniConfigLoader().general.run_vision_mode_on_startup:
Expand Down Expand Up @@ -71,6 +72,8 @@ def _start_or_stop_loot_interaction_thread(self, loot_interaction_method: typing
LOGGER.info("Stopping filter or move process")
kill_thread(self.loot_interaction_thread)
self.loot_interaction_thread = None
if self.did_stop_scripts and IniConfigLoader().general.use_tts == UseTTSType.full and not self.vision_mode.running():
self.vision_mode.start()
else:
self.loot_interaction_thread = threading.Thread(
target=self._wrapper_run_loot_interaction_method, args=(loot_interaction_method, method_args), daemon=True
Expand All @@ -84,41 +87,51 @@ def _start_or_stop_loot_interaction_thread(self, loot_interaction_method: typing
def _wrapper_run_loot_interaction_method(self, loot_interaction_method: typing.Callable, method_args=()):
try:
# We will stop all scripts if they are currently running and restart them afterward if needed
did_stop_scripts = False
if len(self.script_threads) > 0:
LOGGER.info("Stopping Scripts")
for script_thread in self.script_threads:
kill_thread(script_thread)
self.script_threads = []
did_stop_scripts = True
self.did_stop_scripts = False
if IniConfigLoader().general.use_tts == UseTTSType.full:
if self.vision_mode.running():
self.vision_mode.stop()
self.did_stop_scripts = True
else:
if len(self.script_threads) > 0:
LOGGER.info("Stopping Scripts")
for script_thread in self.script_threads:
kill_thread(script_thread)
self.script_threads = []
self.did_stop_scripts = True

loot_interaction_method(*method_args)

if did_stop_scripts:
if self.did_stop_scripts:
self.run_scripts()
finally:
self.loot_interaction_thread = None

def run_scripts(self):
if LOCK.acquire(blocking=False):
try:
if len(self.script_threads) > 0:
LOGGER.info("Stopping Vision Mode")
for script_thread in self.script_threads:
kill_thread(script_thread)
self.script_threads = []
if not IniConfigLoader().advanced_options.scripts:
LOGGER.info("No scripts configured")
return

# TODO Probably just remove the "scripts" concept and change to a checkbox for vision mode
if IniConfigLoader().general.use_tts == UseTTSType.full:
if self.vision_mode.running():
self.vision_mode.stop()
else:
self.vision_mode.start()
else:
if not IniConfigLoader().advanced_options.scripts:
LOGGER.info("No scripts configured")
return
for name in IniConfigLoader().advanced_options.scripts:
if name == "vision_mode":
if IniConfigLoader().general.use_tts == UseTTSType.full:
vision_mode_thread = threading.Thread(target=src.scripts.vision_mode_tts.VisionMode().start, daemon=True)
else:
if len(self.script_threads) > 0:
LOGGER.info("Stopping Vision Mode")
for script_thread in self.script_threads:
kill_thread(script_thread)
self.script_threads = []
else:
for name in IniConfigLoader().advanced_options.scripts:
if name == "vision_mode":
vision_mode_thread = threading.Thread(target=src.scripts.vision_mode.vision_mode, daemon=True)
vision_mode_thread.start()
self.script_threads.append(vision_mode_thread)
vision_mode_thread.start()
self.script_threads.append(vision_mode_thread)
finally:
LOCK.release()
else:
Expand Down
21 changes: 16 additions & 5 deletions src/scripts/loot_filter_tts.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,24 +32,35 @@ def check_items(inv: InventoryBase, force_refresh: ItemRefreshType):
if item.is_junk or item.is_fav:
continue
inv.hover_item(item)
time.sleep(0.15)
time.sleep(0.10)
img = Cam().grab()
item_descr = None
item_descr_previous_check = None
try:
item_descr = src.item.descr.read_descr_tts.read_descr()
item_descr_previous_check = src.item.descr.read_descr_tts.read_descr()
LOGGER.debug(f"Parsed item based on TTS: {item_descr}")
except Exception:
screenshot("tts_error", img=img)
LOGGER.exception(f"Error in TTS read_descr. {src.tts.LAST_ITEM=}")
if item_descr is None:
LOGGER.info("Retry item detection")
time.sleep(0.3)

retry_count = 0
while item_descr is None and retry_count != 5:
# Check again to make sure the item is what we think.
# Move off of the item then back on again
inv.hover_left_of_item(item)
inv.hover_item(item)
time.sleep(0.10)
try:
item_descr = src.item.descr.read_descr_tts.read_descr()
LOGGER.debug(f"Parsed item based on TTS: {item_descr}")
if item_descr != item_descr_previous_check:
item_descr_previous_check = item_descr
item_descr = None
except Exception:
screenshot("tts_error", img=img)
LOGGER.exception(f"Error in TTS read_descr. {src.tts.LAST_ITEM=}")
retry_count += 1

if item_descr is None:
continue

Expand Down
2 changes: 1 addition & 1 deletion src/scripts/vision_mode.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ def vision_mode():
canvas = tk.Canvas(root, bg="black", highlightthickness=0)
canvas.pack(fill=tk.BOTH, expand=True)

LOGGER.info("Starting Vision Filter")
LOGGER.info("Starting Vision Mode")
inv = CharInventory()
chest = Chest()
img = Cam().grab()
Expand Down
14 changes: 13 additions & 1 deletion src/scripts/vision_mode_tts.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ def __init__(self):
self.clear_timer_id = None
self.queue = queue.Queue()
self.draw_from_queue()
self.stop_thread = None
self.is_running = False

def adjust_textbox_size(self):
self.textbox.config(state=tk.NORMAL)
Expand Down Expand Up @@ -157,8 +159,18 @@ def on_tts(self, _):
LOGGER.exception("Error in vision mode. Please create a bug report")

def start(self):
LOGGER.info("Starting Vision Filter")
LOGGER.info("Starting Vision Mode")
Publisher().subscribe(self.on_tts)
self.is_running = True

def stop(self):
LOGGER.info("Stopping Vision Mode")
self.request_clear()
Publisher().unsubscribe(self.on_tts)
self.is_running = False

def running(self):
return self.is_running


def create_match_text(matches: list[MatchedFilter]):
Expand Down
10 changes: 10 additions & 0 deletions src/ui/inventory_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,13 @@ def get_item_slots(self, img: np.ndarray | None = None) -> tuple[list[ItemSlot],

def hover_item(self, item: ItemSlot):
mouse.move(*Cam().window_to_monitor(item.center), randomize=15)

# Needed for double checking a TTS
def hover_left_of_item(self, item: ItemSlot):
mouse.move(
*Cam().window_to_monitor([item.bounding_box[0] - item.bounding_box[2] / 2, item.bounding_box[1] + item.bounding_box[3] / 2]),
randomize=15,
)

def hover_item_with_delay(self, item: ItemSlot, delay_factor: tuple[float, float] = (1.5, 2.0)):
mouse.move(*Cam().window_to_monitor(item.center), randomize=15, delay_factor=delay_factor)
2 changes: 1 addition & 1 deletion src/utils/custom_mouse.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ def move(x: int, y: int, absolute: bool = True, randomize: int | tuple[int, int]
from_point, (x, y), offsetBoundaryX=offsetBoundaryX, offsetBoundaryY=offsetBoundaryY, targetPoints=targetPoints
)

duration = min(0.3, max(0.05, dist * 0.0004) * random.uniform(delay_factor[0], delay_factor[1]))
duration = min(0.5, max(0.05, dist * 0.0004) * random.uniform(delay_factor[0], delay_factor[1]))
delta = duration / len(human_curve.points)

for point in human_curve.points:
Expand Down