-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathgui.py
More file actions
221 lines (180 loc) · 7.96 KB
/
Copy pathgui.py
File metadata and controls
221 lines (180 loc) · 7.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
import os
import tkinter as tk
from tkinter import ttk, filedialog
from datetime import datetime
from PIL import Image
from pynput import keyboard
from fishingbot import FishingBot
from autocrop import autocrop_bait
class FishingBotGUI:
def __init__(self, root):
self.root = root
self.root.title("Fishing Bot")
self.root.resizable(False, False)
self.root.attributes("-topmost", True)
self.bot = None
self.bait_path = None
self._build_ui()
self._start_hotkey_listener()
self.root.protocol("WM_DELETE_WINDOW", self._on_close)
# ── UI construction ──────────────────────────────────────────
def _build_ui(self):
pad = {"padx": 8, "pady": 4}
# --- Bait Image Section ---
bait_frame = ttk.LabelFrame(self.root, text="Bait Image")
bait_frame.pack(fill="x", **pad)
btn_row = ttk.Frame(bait_frame)
btn_row.pack(fill="x", **pad)
ttk.Button(btn_row, text="Browse...", command=self._browse_bait).pack(
side="left", padx=(0, 4)
)
ttk.Button(btn_row, text="Auto-Crop", command=self._autocrop_bait).pack(
side="left"
)
self.bait_info_var = tk.StringVar(value="No image loaded")
ttk.Label(btn_row, textvariable=self.bait_info_var).pack(
side="left", padx=(8, 0)
)
# --- Configuration Section ---
cfg_frame = ttk.LabelFrame(self.root, text="Configuration")
cfg_frame.pack(fill="x", **pad)
self.cfg_entries = {}
fields = [
("Fishing Key", "b"),
("Confidence", "0.7"),
("Mouse Offset (px)", "35"),
("Edge Reset X", "10"),
("Edge Reset Y", "10"),
("Start Delay (s)", "2"),
]
for i, (label, default) in enumerate(fields):
ttk.Label(cfg_frame, text=label).grid(
row=i // 3, column=(i % 3) * 2, sticky="e", padx=(8, 2), pady=2
)
var = tk.StringVar(value=default)
entry = ttk.Entry(cfg_frame, textvariable=var, width=10)
entry.grid(row=i // 3, column=(i % 3) * 2 + 1, sticky="w", padx=(0, 8), pady=2)
self.cfg_entries[label] = (var, entry)
# --- Controls Section ---
ctrl_frame = ttk.LabelFrame(self.root, text="Controls")
ctrl_frame.pack(fill="x", **pad)
self.start_btn = ttk.Button(
ctrl_frame, text="START FISHING", command=self._toggle_bot
)
self.start_btn.pack(fill="x", **pad)
ttk.Label(ctrl_frame, text="Global hotkey: F6").pack(**pad)
# --- Status Section ---
status_frame = ttk.LabelFrame(self.root, text="Status")
status_frame.pack(fill="both", expand=True, **pad)
info_row = ttk.Frame(status_frame)
info_row.pack(fill="x", **pad)
self.state_var = tk.StringVar(value="Idle")
ttk.Label(info_row, textvariable=self.state_var, font=("", 10, "bold")).pack(
side="left"
)
self.fish_var = tk.StringVar(value="Fish: 0")
ttk.Label(info_row, textvariable=self.fish_var).pack(side="right")
self.log_text = tk.Text(status_frame, height=8, width=50, state="disabled")
self.log_text.pack(fill="both", expand=True, **pad)
# ── Bait image handling ──────────────────────────────────────
def _browse_bait(self):
path = filedialog.askopenfilename(
filetypes=[("Images", "*.png *.jpg *.jpeg *.bmp *.gif"), ("All", "*.*")]
)
if path:
self.bait_path = path
self._update_bait_info(path)
def _autocrop_bait(self):
if not self.bait_path:
self._log("No bait image loaded.")
return
try:
cropped = autocrop_bait(self.bait_path)
base, ext = os.path.splitext(self.bait_path)
out_path = base + "_cropped.png"
cropped.save(out_path)
self.bait_path = out_path
self._update_bait_info(out_path)
self._log("Auto-cropped and saved to {}".format(os.path.basename(out_path)))
except Exception as e:
self._log("Auto-crop failed: {}".format(e))
def _update_bait_info(self, path):
try:
img = Image.open(path)
w, h = img.size
self.bait_info_var.set("{} ({}x{})".format(os.path.basename(path), w, h))
except Exception as e:
self.bait_info_var.set("Error: {}".format(e))
# ── Bot start / stop ─────────────────────────────────────────
def _toggle_bot(self):
if self.bot and self.bot.running:
self._stop_bot()
else:
self._start_bot()
def _start_bot(self):
if not self.bait_path:
self._log("Please load a bait image first.")
return
try:
cfg = {k: v.get() for k, (v, _) in self.cfg_entries.items()}
self.bot = FishingBot(
bait_image=self.bait_path,
fishing_button=cfg["Fishing Key"],
mouse_offset_px=int(cfg["Mouse Offset (px)"]),
edge_reset=(int(cfg["Edge Reset X"]), int(cfg["Edge Reset Y"])),
start_delay=float(cfg["Start Delay (s)"]),
confidence=float(cfg["Confidence"]),
on_status=lambda msg: self.root.after(0, self._on_bot_status, msg),
on_fish_caught=lambda n: self.root.after(0, self._on_fish_caught, n),
)
except (ValueError, KeyError) as e:
self._log("Config error: {}".format(e))
return
self.bot.start()
self.start_btn.configure(text="STOP")
self.state_var.set("Running")
self._set_config_state("disabled")
self._poll_bot_stopped()
def _stop_bot(self):
if self.bot:
self.bot.stop()
def _poll_bot_stopped(self):
if self.bot and self.bot.running:
self.root.after(100, self._poll_bot_stopped)
else:
self.start_btn.configure(text="START FISHING")
self.state_var.set("Idle")
self._set_config_state("normal")
def _set_config_state(self, state):
for _, entry in self.cfg_entries.values():
entry.configure(state=state)
# ── Bot callbacks (called on main thread via root.after) ─────
def _on_bot_status(self, msg):
self.state_var.set(msg)
self._log(msg)
def _on_fish_caught(self, count):
self.fish_var.set("Fish: {}".format(count))
# ── Log ───────────────────────────────────────────────────────
def _log(self, msg):
ts = datetime.now().strftime("%H:%M:%S")
self.log_text.configure(state="normal")
self.log_text.insert("end", "[{}] {}\n".format(ts, msg))
self.log_text.see("end")
self.log_text.configure(state="disabled")
# ── Global hotkey (F6) ───────────────────────────────────────
def _start_hotkey_listener(self):
def on_press(key):
if key == keyboard.Key.f6:
self.root.after(0, self._toggle_bot)
self._hotkey_listener = keyboard.Listener(on_press=on_press)
self._hotkey_listener.daemon = True
self._hotkey_listener.start()
# ── Window close ─────────────────────────────────────────────
def _on_close(self):
if self.bot and self.bot.running:
self.bot.stop()
self.root.destroy()
if __name__ == "__main__":
root = tk.Tk()
FishingBotGUI(root)
root.mainloop()