初始化项目以及GUI简单实现
This commit is contained in:
14
src/core/__init__.py
Normal file
14
src/core/__init__.py
Normal file
@@ -0,0 +1,14 @@
|
||||
"""
|
||||
LuoLuoTool 核心模块
|
||||
游戏自动化控制核心
|
||||
"""
|
||||
|
||||
from .automation import AutomationController
|
||||
from .game_window import GameWindowManager
|
||||
from .actions import GameActions
|
||||
|
||||
__all__ = [
|
||||
"AutomationController",
|
||||
"GameWindowManager",
|
||||
"GameActions",
|
||||
]
|
||||
41
src/core/actions.py
Normal file
41
src/core/actions.py
Normal file
@@ -0,0 +1,41 @@
|
||||
"""
|
||||
游戏动作定义
|
||||
"""
|
||||
|
||||
import time
|
||||
from typing import Optional
|
||||
from src.utils.logger import logger
|
||||
|
||||
from .game_window import GameWindowManager
|
||||
|
||||
|
||||
class GameActions:
|
||||
"""游戏动作执行器"""
|
||||
|
||||
def __init__(self, window_manager: GameWindowManager):
|
||||
self.window = window_manager
|
||||
|
||||
def click(self, x: int, y: int, delay: float = 0.1):
|
||||
"""点击指定坐标"""
|
||||
self.window.click(x, y)
|
||||
time.sleep(delay)
|
||||
|
||||
def click_template(self, template_name: str, timeout: float = 5.0) -> bool:
|
||||
"""点击匹配到的模板图像"""
|
||||
# TODO: 实现模板匹配点击
|
||||
logger.debug(f"尝试点击模板: {template_name}")
|
||||
return False
|
||||
|
||||
def wait(self, seconds: float):
|
||||
"""等待指定时间"""
|
||||
time.sleep(seconds)
|
||||
|
||||
def swipe(self, x1: int, y1: int, x2: int, y2: int, duration: float = 0.5):
|
||||
"""滑动操作"""
|
||||
# TODO: 实现滑动
|
||||
logger.debug(f"滑动: ({x1}, {y1}) -> ({x2}, {y2})")
|
||||
|
||||
def press_key(self, key: str):
|
||||
"""按下键盘按键"""
|
||||
# TODO: 实现按键
|
||||
logger.debug(f"按键: {key}")
|
||||
87
src/core/automation.py
Normal file
87
src/core/automation.py
Normal file
@@ -0,0 +1,87 @@
|
||||
"""
|
||||
自动化控制主类
|
||||
"""
|
||||
|
||||
import threading
|
||||
import time
|
||||
from typing import Optional, Callable
|
||||
from src.utils.logger import logger
|
||||
|
||||
from .game_window import GameWindowManager
|
||||
from .actions import GameActions
|
||||
|
||||
|
||||
class AutomationController:
|
||||
"""自动化控制器"""
|
||||
|
||||
def __init__(self):
|
||||
self.window_manager = GameWindowManager()
|
||||
self.actions = GameActions(self.window_manager)
|
||||
|
||||
self._running = False
|
||||
self._paused = False
|
||||
self._thread: Optional[threading.Thread] = None
|
||||
self._callback: Optional[Callable] = None
|
||||
|
||||
@property
|
||||
def is_running(self) -> bool:
|
||||
return self._running
|
||||
|
||||
@property
|
||||
def is_paused(self) -> bool:
|
||||
return self._paused
|
||||
|
||||
def set_callback(self, callback: Callable):
|
||||
"""设置状态回调函数"""
|
||||
self._callback = callback
|
||||
|
||||
def _notify(self, message: str):
|
||||
"""通知UI更新"""
|
||||
logger.info(message)
|
||||
if self._callback:
|
||||
self._callback(message)
|
||||
|
||||
def start(self):
|
||||
"""开始自动化"""
|
||||
if self._running:
|
||||
return
|
||||
|
||||
if not self.window_manager.is_window_captured:
|
||||
self._notify("请先捕获游戏窗口")
|
||||
return
|
||||
|
||||
self._running = True
|
||||
self._paused = False
|
||||
self._thread = threading.Thread(target=self._run_loop, daemon=True)
|
||||
self._thread.start()
|
||||
self._notify("自动化已启动")
|
||||
|
||||
def stop(self):
|
||||
"""停止自动化"""
|
||||
self._running = False
|
||||
self._paused = False
|
||||
if self._thread:
|
||||
self._thread.join(timeout=2)
|
||||
self._notify("自动化已停止")
|
||||
|
||||
def pause(self):
|
||||
"""暂停/继续"""
|
||||
if not self._running:
|
||||
return
|
||||
self._paused = not self._paused
|
||||
status = "已暂停" if self._paused else "已继续"
|
||||
self._notify(f"自动化{status}")
|
||||
|
||||
def _run_loop(self):
|
||||
"""主运行循环"""
|
||||
while self._running:
|
||||
if self._paused:
|
||||
time.sleep(0.1)
|
||||
continue
|
||||
|
||||
try:
|
||||
# TODO: 实现具体的任务执行逻辑
|
||||
time.sleep(0.1)
|
||||
except Exception as e:
|
||||
logger.error(f"运行错误: {e}")
|
||||
self._notify(f"错误: {e}")
|
||||
97
src/core/game_window.py
Normal file
97
src/core/game_window.py
Normal file
@@ -0,0 +1,97 @@
|
||||
"""
|
||||
游戏窗口管理
|
||||
"""
|
||||
|
||||
import win32gui
|
||||
import win32con
|
||||
from typing import Optional, Tuple
|
||||
from src.utils.logger import logger
|
||||
|
||||
|
||||
class GameWindowManager:
|
||||
"""游戏窗口管理器"""
|
||||
|
||||
# 游戏窗口类名和标题
|
||||
GAME_CLASS_NAME = "UnityWndClass" # Unity游戏常用类名
|
||||
GAME_WINDOW_TITLE = "桃源深处有人家"
|
||||
|
||||
def __init__(self):
|
||||
self._hwnd: Optional[int] = None
|
||||
self._window_rect: Tuple[int, int, int, int] = (0, 0, 0, 0)
|
||||
|
||||
@property
|
||||
def is_window_captured(self) -> bool:
|
||||
"""是否已捕获窗口"""
|
||||
if self._hwnd is None:
|
||||
return False
|
||||
return win32gui.IsWindow(self._hwnd)
|
||||
|
||||
@property
|
||||
def hwnd(self) -> Optional[int]:
|
||||
"""窗口句柄"""
|
||||
return self._hwnd
|
||||
|
||||
@property
|
||||
def window_rect(self) -> Tuple[int, int, int, int]:
|
||||
"""窗口矩形 (left, top, right, bottom)"""
|
||||
if self.is_window_captured:
|
||||
self._window_rect = win32gui.GetWindowRect(self._hwnd)
|
||||
return self._window_rect
|
||||
|
||||
@property
|
||||
def client_size(self) -> Tuple[int, int]:
|
||||
"""客户端区域大小 (width, height)"""
|
||||
if not self.is_window_captured:
|
||||
return (0, 0)
|
||||
left, top, right, bottom = self.window_rect
|
||||
return (right - left, bottom - top)
|
||||
|
||||
def find_window(self) -> bool:
|
||||
"""查找游戏窗口"""
|
||||
# 先尝试精确匹配
|
||||
hwnd = win32gui.FindWindow(None, self.GAME_WINDOW_TITLE)
|
||||
|
||||
# 如果没找到,尝试模糊匹配
|
||||
if hwnd == 0:
|
||||
def callback(hwnd, extra):
|
||||
if win32gui.IsWindowVisible(hwnd):
|
||||
title = win32gui.GetWindowText(hwnd)
|
||||
if self.GAME_WINDOW_TITLE in title:
|
||||
extra.append(hwnd)
|
||||
return True
|
||||
|
||||
windows = []
|
||||
win32gui.EnumWindows(callback, windows)
|
||||
if windows:
|
||||
hwnd = windows[0]
|
||||
|
||||
if hwnd != 0:
|
||||
self._hwnd = hwnd
|
||||
self._window_rect = win32gui.GetWindowRect(hwnd)
|
||||
logger.info(f"找到游戏窗口: {hwnd}, 大小: {self.client_size}")
|
||||
return True
|
||||
|
||||
logger.warning("未找到游戏窗口")
|
||||
return False
|
||||
|
||||
def capture_window(self) -> bool:
|
||||
"""捕获游戏窗口"""
|
||||
return self.find_window()
|
||||
|
||||
def bring_to_front(self):
|
||||
"""将窗口置前"""
|
||||
if self.is_window_captured:
|
||||
win32gui.SetForegroundWindow(self._hwnd)
|
||||
|
||||
def click(self, x: int, y: int):
|
||||
"""在窗口内点击"""
|
||||
if not self.is_window_captured:
|
||||
return
|
||||
|
||||
left, top, _, _ = self.window_rect
|
||||
# 转换为屏幕坐标
|
||||
screen_x = left + x
|
||||
screen_y = top + y
|
||||
|
||||
# TODO: 使用pyautogui或win32api发送点击
|
||||
logger.debug(f"点击坐标: ({screen_x}, {screen_y})")
|
||||
14
src/core/tasks/__init__.py
Normal file
14
src/core/tasks/__init__.py
Normal file
@@ -0,0 +1,14 @@
|
||||
"""
|
||||
挂机任务模块
|
||||
所有任务逻辑代码写死实现
|
||||
"""
|
||||
|
||||
from .daily_tasks import DailyTaskRunner
|
||||
from .misc_tasks import MiscTaskRunner
|
||||
from .pending_tasks import PendingTaskRunner
|
||||
|
||||
__all__ = [
|
||||
"DailyTaskRunner",
|
||||
"MiscTaskRunner",
|
||||
"PendingTaskRunner",
|
||||
]
|
||||
69
src/core/tasks/daily_tasks.py
Normal file
69
src/core/tasks/daily_tasks.py
Normal file
@@ -0,0 +1,69 @@
|
||||
"""
|
||||
日常挂机任务
|
||||
"""
|
||||
|
||||
from typing import Dict, Any
|
||||
from src.utils.logger import logger
|
||||
|
||||
|
||||
class DailyTaskRunner:
|
||||
"""日常任务执行器"""
|
||||
|
||||
# 任务配置 - 代码写死
|
||||
TASKS = {
|
||||
"daily_mission": {
|
||||
"name": "每日委托",
|
||||
"enabled": True,
|
||||
"description": "完成每日任务",
|
||||
},
|
||||
"resin_farming": {
|
||||
"name": "清体力",
|
||||
"enabled": True,
|
||||
"description": "消耗体力刷资源",
|
||||
},
|
||||
"monthly_card": {
|
||||
"name": "领月卡",
|
||||
"enabled": False,
|
||||
"description": "领取月卡奖励",
|
||||
},
|
||||
"friend_gift": {
|
||||
"name": "好友礼物",
|
||||
"enabled": True,
|
||||
"description": "领取好友赠送的礼物",
|
||||
},
|
||||
"shop_daily": {
|
||||
"name": "每日商店",
|
||||
"enabled": False,
|
||||
"description": "购买每日商店物品",
|
||||
},
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
self._config = self.TASKS.copy()
|
||||
|
||||
def get_tasks(self) -> Dict[str, Any]:
|
||||
"""获取所有任务配置"""
|
||||
return self._config
|
||||
|
||||
def update_task(self, task_id: str, enabled: bool):
|
||||
"""更新任务启用状态"""
|
||||
if task_id in self._config:
|
||||
self._config[task_id]["enabled"] = enabled
|
||||
logger.info(f"任务 {task_id} 状态更新为: {enabled}")
|
||||
|
||||
def run(self, actions):
|
||||
"""执行启用的任务"""
|
||||
for task_id, config in self._config.items():
|
||||
if not config["enabled"]:
|
||||
continue
|
||||
|
||||
logger.info(f"执行任务: {config['name']}")
|
||||
try:
|
||||
self._execute_task(task_id, actions)
|
||||
except Exception as e:
|
||||
logger.error(f"任务 {config['name']} 执行失败: {e}")
|
||||
|
||||
def _execute_task(self, task_id: str, actions):
|
||||
"""执行具体任务"""
|
||||
# TODO: 实现具体任务逻辑
|
||||
logger.debug(f"执行任务逻辑: {task_id}")
|
||||
64
src/core/tasks/misc_tasks.py
Normal file
64
src/core/tasks/misc_tasks.py
Normal file
@@ -0,0 +1,64 @@
|
||||
"""
|
||||
杂项功能任务
|
||||
"""
|
||||
|
||||
from typing import Dict, Any
|
||||
from src.utils.logger import logger
|
||||
|
||||
|
||||
class MiscTaskRunner:
|
||||
"""杂项功能执行器"""
|
||||
|
||||
# 功能配置 - 代码写死
|
||||
FEATURES = {
|
||||
"auto_pickup": {
|
||||
"name": "自动拾取",
|
||||
"enabled": True,
|
||||
"description": "自动拾取掉落物品",
|
||||
},
|
||||
"auto_skip": {
|
||||
"name": "自动跳过对话",
|
||||
"enabled": False,
|
||||
"description": "自动跳过游戏对话",
|
||||
},
|
||||
"auto_heal": {
|
||||
"name": "自动回血",
|
||||
"enabled": True,
|
||||
"description": "低血量自动回血",
|
||||
},
|
||||
"auto_repair": {
|
||||
"name": "自动修理",
|
||||
"enabled": False,
|
||||
"description": "装备损坏自动修理",
|
||||
},
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
self._config = self.FEATURES.copy()
|
||||
|
||||
def get_features(self) -> Dict[str, Any]:
|
||||
"""获取所有功能配置"""
|
||||
return self._config
|
||||
|
||||
def update_feature(self, feature_id: str, enabled: bool):
|
||||
"""更新功能启用状态"""
|
||||
if feature_id in self._config:
|
||||
self._config[feature_id]["enabled"] = enabled
|
||||
logger.info(f"功能 {feature_id} 状态更新为: {enabled}")
|
||||
|
||||
def run(self, actions):
|
||||
"""执行启用的功能"""
|
||||
for feature_id, config in self._config.items():
|
||||
if not config["enabled"]:
|
||||
continue
|
||||
|
||||
logger.info(f"执行功能: {config['name']}")
|
||||
try:
|
||||
self._execute_feature(feature_id, actions)
|
||||
except Exception as e:
|
||||
logger.error(f"功能 {config['name']} 执行失败: {e}")
|
||||
|
||||
def _execute_feature(self, feature_id: str, actions):
|
||||
"""执行具体功能"""
|
||||
# TODO: 实现具体功能逻辑
|
||||
logger.debug(f"执行功能逻辑: {feature_id}")
|
||||
48
src/core/tasks/pending_tasks.py
Normal file
48
src/core/tasks/pending_tasks.py
Normal file
@@ -0,0 +1,48 @@
|
||||
"""
|
||||
待定功能任务
|
||||
预留功能占位
|
||||
"""
|
||||
|
||||
from typing import Dict, Any
|
||||
from src.utils.logger import logger
|
||||
|
||||
|
||||
class PendingTaskRunner:
|
||||
"""待定功能执行器"""
|
||||
|
||||
# 待定功能配置 - 代码写死
|
||||
PENDING_FEATURES = {
|
||||
"feature_a": {
|
||||
"name": "功能A(待开发)",
|
||||
"enabled": False,
|
||||
"description": "预留功能A",
|
||||
},
|
||||
"feature_b": {
|
||||
"name": "功能B(待开发)",
|
||||
"enabled": False,
|
||||
"description": "预留功能B",
|
||||
},
|
||||
"feature_c": {
|
||||
"name": "功能C(待开发)",
|
||||
"enabled": False,
|
||||
"description": "预留功能C",
|
||||
},
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
self._config = self.PENDING_FEATURES.copy()
|
||||
|
||||
def get_features(self) -> Dict[str, Any]:
|
||||
"""获取所有待定功能"""
|
||||
return self._config
|
||||
|
||||
def update_feature(self, feature_id: str, enabled: bool):
|
||||
"""更新功能状态"""
|
||||
if feature_id in self._config:
|
||||
self._config[feature_id]["enabled"] = enabled
|
||||
logger.info(f"待定功能 {feature_id} 状态更新为: {enabled}")
|
||||
|
||||
def run(self, actions):
|
||||
"""执行启用的功能"""
|
||||
logger.info("待定功能模块 - 暂无实现")
|
||||
# 待定功能暂不执行任何操作
|
||||
Reference in New Issue
Block a user