Add Bot setup UI
This commit is contained in:
parent
96f53ecdfc
commit
494f6e2943
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,6 +1,8 @@
|
|||||||
.env
|
.env
|
||||||
*.log
|
*.log
|
||||||
llm_debug.log
|
llm_debug.log
|
||||||
|
config.py
|
||||||
__pycache__/
|
__pycache__/
|
||||||
debug_screenshots/
|
debug_screenshots/
|
||||||
chat_logs/
|
chat_logs/
|
||||||
|
backup/
|
||||||
134
config.py
134
config.py
@ -1,134 +0,0 @@
|
|||||||
# config.py
|
|
||||||
import os
|
|
||||||
import json # Import json for building args string
|
|
||||||
from dotenv import load_dotenv # Import load_dotenv
|
|
||||||
|
|
||||||
# --- Load environment variables from .env file ---
|
|
||||||
load_dotenv()
|
|
||||||
print("Attempted to load environment variables from .env file.")
|
|
||||||
# --- End Load ---
|
|
||||||
|
|
||||||
# OpenAI API Configuration / OpenAI-Compatible Provider Settings
|
|
||||||
# --- Modify these lines ---
|
|
||||||
# Leave OPENAI_API_BASE_URL as None or "" to use official OpenAI
|
|
||||||
OPENAI_API_BASE_URL = "https://openrouter.ai/api/v1" # <--- For example "http://localhost:1234/v1" or your provider URL
|
|
||||||
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
|
|
||||||
#LLM_MODEL = "anthropic/claude-3.7-sonnet"
|
|
||||||
#LLM_MODEL = "meta-llama/llama-4-maverick"
|
|
||||||
#LLM_MODEL = "deepseek/deepseek-chat-v3-0324:free"
|
|
||||||
#LLM_MODEL = "google/gemini-2.5-flash-preview"
|
|
||||||
LLM_MODEL = "deepseek/deepseek-chat-v3-0324" # <--- Ensure this matches the model name provided by your provider
|
|
||||||
|
|
||||||
#LLM_MODEL = "openai/gpt-4.1-nano"
|
|
||||||
|
|
||||||
EXA_API_KEY = os.getenv("EXA_API_KEY")
|
|
||||||
MCP_REDIS_API_KEY = os.getenv("MCP_REDIS_APU_KEY")
|
|
||||||
MCP_REDIS_PATH = os.getenv("MCP_REDIS_PATH")
|
|
||||||
|
|
||||||
# --- Dynamically build Exa server args ---
|
|
||||||
exa_config_dict = {"exaApiKey": EXA_API_KEY if EXA_API_KEY else "YOUR_EXA_KEY_MISSING"}
|
|
||||||
# Need to dump dict to JSON string, then properly escape it for cmd arg
|
|
||||||
# Using json.dumps handles internal quotes correctly.
|
|
||||||
# The outer quotes for cmd might need careful handling depending on OS / shell.
|
|
||||||
# For cmd /c on Windows, embedding escaped JSON often works like this:
|
|
||||||
exa_config_arg_string = json.dumps(json.dumps(exa_config_dict)) # Double dump for cmd escaping? Or just one? Test needed.
|
|
||||||
# Let's try single dump first, often sufficient if passed correctly by subprocess
|
|
||||||
exa_config_arg_string_single_dump = json.dumps(exa_config_dict) # Use this one
|
|
||||||
|
|
||||||
# --- MCP Server Configuration ---
|
|
||||||
MCP_SERVERS = {
|
|
||||||
#"exa": { # Temporarily commented out to prevent blocking startup
|
|
||||||
## "command": "cmd",
|
|
||||||
# "args": [
|
|
||||||
# "/c",
|
|
||||||
# "npx",
|
|
||||||
# "-y",
|
|
||||||
# "@smithery/cli@latest",
|
|
||||||
# "run",
|
|
||||||
# "exa",
|
|
||||||
# "--config",
|
|
||||||
# # Pass the dynamically created config string with the environment variable key
|
|
||||||
# exa_config_arg_string_single_dump # Use the single dump variable
|
|
||||||
# ],
|
|
||||||
#},
|
|
||||||
"exa": {
|
|
||||||
"command": "npx",
|
|
||||||
"args": [
|
|
||||||
"C:/Users/Bigspring/AppData/Roaming/npm/exa-mcp-server",
|
|
||||||
"--tools=web_search,research_paper_search,twitter_search,company_research,crawling,competitor_finder"
|
|
||||||
],
|
|
||||||
"env": {
|
|
||||||
"EXA_API_KEY": EXA_API_KEY
|
|
||||||
}
|
|
||||||
},
|
|
||||||
#"github.com/modelcontextprotocol/servers/tree/main/src/memory": {
|
|
||||||
# "command": "npx",
|
|
||||||
# "args": [
|
|
||||||
# "-y",
|
|
||||||
# "@modelcontextprotocol/server-memory"
|
|
||||||
# ],
|
|
||||||
# "disabled": False
|
|
||||||
#},
|
|
||||||
#"redis": {
|
|
||||||
# "command": "uv",
|
|
||||||
# "args": [
|
|
||||||
# "--directory",
|
|
||||||
# MCP_REDIS_PATH,
|
|
||||||
# "run",
|
|
||||||
# "src/main.py"
|
|
||||||
# ],
|
|
||||||
# "env": {
|
|
||||||
# "REDIS_HOST": "127.0.0.1",
|
|
||||||
# "REDIS_PORT": "6379",
|
|
||||||
# "REDIS_SSL": "False",
|
|
||||||
# "REDIS_CLUSTER_MODE": "False"
|
|
||||||
# }
|
|
||||||
# }
|
|
||||||
#"basic-memory": {
|
|
||||||
# "command": "uvx",
|
|
||||||
# "args": [
|
|
||||||
# "basic-memory",
|
|
||||||
# "mcp"
|
|
||||||
# ],
|
|
||||||
#}
|
|
||||||
"chroma": {
|
|
||||||
"command": "uvx",
|
|
||||||
"args": [
|
|
||||||
"chroma-mcp",
|
|
||||||
"--client-type",
|
|
||||||
"persistent",
|
|
||||||
"--data-dir",
|
|
||||||
"Z:/mcp/Server/Chroma-MCP"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
# MCP Client Configuration
|
|
||||||
MCP_CONFIRM_TOOL_EXECUTION = False # True: Confirm before execution, False: Execute automatically
|
|
||||||
|
|
||||||
# --- Chat Logging Configuration ---
|
|
||||||
ENABLE_CHAT_LOGGING = True # True: Enable logging, False: Disable logging
|
|
||||||
LOG_DIR = "chat_logs" # Directory to store chat logs
|
|
||||||
|
|
||||||
# Persona Configuration
|
|
||||||
PERSONA_NAME = "Wolfhart"
|
|
||||||
# PERSONA_RESOURCE_URI = "persona://wolfhart/details" # Now using local file instead
|
|
||||||
|
|
||||||
# Game window title (used in ui_interaction.py and game_monitor.py)
|
|
||||||
WINDOW_TITLE = "Last War-Survival Game"
|
|
||||||
|
|
||||||
# --- Game Monitor Configuration ---
|
|
||||||
ENABLE_SCHEDULED_RESTART = True # 是否啟用定時重啟遊戲功能
|
|
||||||
RESTART_INTERVAL_MINUTES = 60 # 定時重啟的間隔時間(分鐘),預設 4 小時
|
|
||||||
GAME_EXECUTABLE_PATH = r"C:\Users\Bigspring\AppData\Local\TheLastWar\Launch.exe" # Path to the game launcher
|
|
||||||
GAME_WINDOW_X = 50 # Target X position for the game window
|
|
||||||
GAME_WINDOW_Y = 30 # Target Y position for the game window
|
|
||||||
GAME_WINDOW_WIDTH = 600 # Target width for the game window
|
|
||||||
GAME_WINDOW_HEIGHT = 1070 # Target height for the game window
|
|
||||||
MONITOR_INTERVAL_SECONDS = 5 # How often to check the window (in seconds)
|
|
||||||
|
|
||||||
# --- Print loaded keys for verification (Optional - BE CAREFUL!) ---
|
|
||||||
# print(f"DEBUG: Loaded OPENAI_API_KEY: {'*' * (len(OPENAI_API_KEY) - 4) + OPENAI_API_KEY[-4:] if OPENAI_API_KEY else 'Not Found'}")
|
|
||||||
print(f"DEBUG: Loaded EXA_API_KEY: {'*' * (len(EXA_API_KEY) - 4) + EXA_API_KEY[-4:] if EXA_API_KEY else 'Not Found'}") # Uncommented Exa key check
|
|
||||||
# print(f"DEBUG: Exa args: {MCP_SERVERS['exa']['args']}")
|
|
||||||
62
config_template.py
Normal file
62
config_template.py
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
# ====================================================================
|
||||||
|
# Wolf Chat Configuration Template
|
||||||
|
# This file is used by setup.py to generate the final config.py
|
||||||
|
# ====================================================================
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
# --- Load environment variables from .env file ---
|
||||||
|
load_dotenv()
|
||||||
|
print("Loaded environment variables from .env file.")
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# OpenAI API Configuration / OpenAI-Compatible Provider Settings
|
||||||
|
# =============================================================================
|
||||||
|
# Leave OPENAI_API_BASE_URL as None or "" to use official OpenAI
|
||||||
|
OPENAI_API_BASE_URL = "${OPENAI_API_BASE_URL}"
|
||||||
|
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
|
||||||
|
LLM_MODEL = "${LLM_MODEL}"
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# External API Keys
|
||||||
|
# =============================================================================
|
||||||
|
EXA_API_KEY = os.getenv("EXA_API_KEY")
|
||||||
|
|
||||||
|
# --- Exa Configuration ---
|
||||||
|
exa_config_dict = {"exaApiKey": EXA_API_KEY if EXA_API_KEY else "YOUR_EXA_KEY_MISSING"}
|
||||||
|
exa_config_arg_string = json.dumps(exa_config_dict)
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# MCP Server Configuration
|
||||||
|
# =============================================================================
|
||||||
|
MCP_SERVERS = ${MCP_SERVERS}
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# MCP Client Configuration
|
||||||
|
# =============================================================================
|
||||||
|
MCP_CONFIRM_TOOL_EXECUTION = False # True: Confirm before execution, False: Execute automatically
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Chat Logging Configuration
|
||||||
|
# =============================================================================
|
||||||
|
ENABLE_CHAT_LOGGING = ${ENABLE_CHAT_LOGGING}
|
||||||
|
LOG_DIR = "${LOG_DIR}"
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Persona Configuration
|
||||||
|
# =============================================================================
|
||||||
|
PERSONA_NAME = "Wolfhart"
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Game Window Configuration
|
||||||
|
# =============================================================================
|
||||||
|
WINDOW_TITLE = "${WINDOW_TITLE}"
|
||||||
|
ENABLE_SCHEDULED_RESTART = ${ENABLE_SCHEDULED_RESTART}
|
||||||
|
RESTART_INTERVAL_MINUTES = ${RESTART_INTERVAL_MINUTES}
|
||||||
|
GAME_EXECUTABLE_PATH = r"${GAME_EXECUTABLE_PATH}"
|
||||||
|
GAME_WINDOW_X = ${GAME_WINDOW_X}
|
||||||
|
GAME_WINDOW_Y = ${GAME_WINDOW_Y}
|
||||||
|
GAME_WINDOW_WIDTH = ${GAME_WINDOW_WIDTH}
|
||||||
|
GAME_WINDOW_HEIGHT = ${GAME_WINDOW_HEIGHT}
|
||||||
|
MONITOR_INTERVAL_SECONDS = ${MONITOR_INTERVAL_SECONDS}
|
||||||
137
install.py
Normal file
137
install.py
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Wolf Chat Installation Script
|
||||||
|
Installs required dependencies for Wolf Chat
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import subprocess
|
||||||
|
import tkinter as tk
|
||||||
|
from tkinter import ttk, messagebox
|
||||||
|
|
||||||
|
REQUIREMENTS = [
|
||||||
|
"openai",
|
||||||
|
"mcp",
|
||||||
|
"pyautogui",
|
||||||
|
"opencv-python",
|
||||||
|
"numpy",
|
||||||
|
"pyperclip",
|
||||||
|
"pygetwindow",
|
||||||
|
"psutil",
|
||||||
|
"pywin32",
|
||||||
|
"python-dotenv",
|
||||||
|
"keyboard"
|
||||||
|
]
|
||||||
|
|
||||||
|
def install_requirements(progress_var=None, status_label=None, root=None):
|
||||||
|
"""Install all required packages using pip"""
|
||||||
|
|
||||||
|
total = len(REQUIREMENTS)
|
||||||
|
success_count = 0
|
||||||
|
failed_packages = []
|
||||||
|
|
||||||
|
for i, package in enumerate(REQUIREMENTS):
|
||||||
|
if status_label:
|
||||||
|
status_label.config(text=f"Installing {package}...")
|
||||||
|
if progress_var:
|
||||||
|
progress_var.set((i / total) * 100)
|
||||||
|
if root:
|
||||||
|
root.update()
|
||||||
|
|
||||||
|
try:
|
||||||
|
print(f"Installing {package}...")
|
||||||
|
# Use subprocess to run pip install
|
||||||
|
process = subprocess.run(
|
||||||
|
[sys.executable, "-m", "pip", "install", package],
|
||||||
|
check=True,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE,
|
||||||
|
text=True
|
||||||
|
)
|
||||||
|
print(f"Successfully installed {package}")
|
||||||
|
success_count += 1
|
||||||
|
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
print(f"Failed to install {package}: {e}")
|
||||||
|
print(f"Error output: {e.stderr}")
|
||||||
|
failed_packages.append(package)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Unexpected error installing {package}: {str(e)}")
|
||||||
|
failed_packages.append(package)
|
||||||
|
|
||||||
|
# Final progress update
|
||||||
|
if progress_var:
|
||||||
|
progress_var.set(100)
|
||||||
|
|
||||||
|
# Report results
|
||||||
|
if not failed_packages:
|
||||||
|
result_message = f"All {success_count} packages installed successfully!"
|
||||||
|
print(result_message)
|
||||||
|
if status_label:
|
||||||
|
status_label.config(text=result_message)
|
||||||
|
return True, result_message
|
||||||
|
else:
|
||||||
|
result_message = f"Installed {success_count}/{total} packages. Failed: {', '.join(failed_packages)}"
|
||||||
|
print(result_message)
|
||||||
|
if status_label:
|
||||||
|
status_label.config(text=result_message)
|
||||||
|
return False, result_message
|
||||||
|
|
||||||
|
def run_installer_gui():
|
||||||
|
"""Run a simple GUI for the installer"""
|
||||||
|
root = tk.Tk()
|
||||||
|
root.title("Wolf Chat Installer")
|
||||||
|
root.geometry("400x200")
|
||||||
|
root.resizable(False, False)
|
||||||
|
|
||||||
|
# Main frame
|
||||||
|
main_frame = ttk.Frame(root, padding=20)
|
||||||
|
main_frame.pack(fill=tk.BOTH, expand=True)
|
||||||
|
|
||||||
|
# Title
|
||||||
|
title_label = ttk.Label(main_frame, text="Wolf Chat Dependency Installer", font=("", 12, "bold"))
|
||||||
|
title_label.pack(pady=(0, 10))
|
||||||
|
|
||||||
|
# Info text
|
||||||
|
info_text = f"This will install {len(REQUIREMENTS)} required packages for Wolf Chat."
|
||||||
|
info_label = ttk.Label(main_frame, text=info_text)
|
||||||
|
info_label.pack(pady=(0, 15))
|
||||||
|
|
||||||
|
# Progress bar
|
||||||
|
progress_var = tk.DoubleVar()
|
||||||
|
progress_bar = ttk.Progressbar(main_frame, variable=progress_var, maximum=100)
|
||||||
|
progress_bar.pack(fill=tk.X, pady=(0, 10))
|
||||||
|
|
||||||
|
# Status label
|
||||||
|
status_label = ttk.Label(main_frame, text="Ready to install...")
|
||||||
|
status_label.pack(pady=(0, 15))
|
||||||
|
|
||||||
|
# Install button
|
||||||
|
def start_installation():
|
||||||
|
# Disable button during installation
|
||||||
|
install_button.config(state=tk.DISABLED)
|
||||||
|
|
||||||
|
# Run installation in a separate thread to keep UI responsive
|
||||||
|
success, message = install_requirements(progress_var, status_label, root)
|
||||||
|
|
||||||
|
# Show completion message
|
||||||
|
if success:
|
||||||
|
messagebox.showinfo("Installation Complete", message)
|
||||||
|
else:
|
||||||
|
messagebox.showwarning("Installation Issues", message)
|
||||||
|
|
||||||
|
# Close the window
|
||||||
|
root.destroy()
|
||||||
|
|
||||||
|
install_button = ttk.Button(main_frame, text="Install Dependencies", command=start_installation)
|
||||||
|
install_button.pack()
|
||||||
|
|
||||||
|
# Start the GUI loop
|
||||||
|
root.mainloop()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
# If run directly, show GUI
|
||||||
|
run_installer_gui()
|
||||||
@ -1,121 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
"""
|
|
||||||
Game Window Monitor Script - Keep game window on top and in position
|
|
||||||
|
|
||||||
This script monitors a specified game window, ensuring it stays
|
|
||||||
always on top and at the desired screen coordinates.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import time
|
|
||||||
import argparse
|
|
||||||
import pygetwindow as gw
|
|
||||||
import win32gui
|
|
||||||
import win32con
|
|
||||||
|
|
||||||
def find_window_by_title(window_title):
|
|
||||||
"""Find the first window matching the title."""
|
|
||||||
try:
|
|
||||||
windows = gw.getWindowsWithTitle(window_title)
|
|
||||||
if windows:
|
|
||||||
return windows[0]
|
|
||||||
except Exception as e:
|
|
||||||
# pygetwindow can sometimes raise exceptions if a window disappears
|
|
||||||
# during enumeration. Ignore these for monitoring purposes.
|
|
||||||
# print(f"Error finding window: {e}")
|
|
||||||
pass
|
|
||||||
return None
|
|
||||||
|
|
||||||
def set_window_always_on_top(hwnd):
|
|
||||||
"""Set the window to be always on top."""
|
|
||||||
try:
|
|
||||||
win32gui.SetWindowPos(hwnd, win32con.HWND_TOPMOST, 0, 0, 0, 0,
|
|
||||||
win32con.SWP_NOMOVE | win32con.SWP_NOSIZE | win32con.SWP_SHOWWINDOW)
|
|
||||||
# print(f"Window {hwnd} set to always on top.")
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error setting window always on top: {e}")
|
|
||||||
|
|
||||||
def move_window_if_needed(window, target_x, target_y):
|
|
||||||
"""Move the window to the target coordinates if it's not already there."""
|
|
||||||
try:
|
|
||||||
current_x, current_y = window.topleft
|
|
||||||
if current_x != target_x or current_y != target_y:
|
|
||||||
print(f"Window moved from ({current_x}, {current_y}). Moving back to ({target_x}, {target_y}).")
|
|
||||||
window.moveTo(target_x, target_y)
|
|
||||||
# print(f"Window moved to ({target_x}, {target_y}).")
|
|
||||||
except gw.PyGetWindowException as e:
|
|
||||||
# Handle cases where the window might close unexpectedly
|
|
||||||
print(f"Error accessing window properties (might be closed): {e}")
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error moving window: {e}")
|
|
||||||
|
|
||||||
def main():
|
|
||||||
parser = argparse.ArgumentParser(description='Game Window Monitor Tool')
|
|
||||||
parser.add_argument('--window_title', default="Last War-Survival Game", help='Game window title to monitor')
|
|
||||||
parser.add_argument('--x', type=int, default=50, help='Target window X coordinate')
|
|
||||||
parser.add_argument('--y', type=int, default=30, help='Target window Y coordinate')
|
|
||||||
parser.add_argument('--interval', type=float, default=1.0, help='Check interval in seconds')
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
print(f"Monitoring window: '{args.window_title}'")
|
|
||||||
print(f"Target position: ({args.x}, {args.y})")
|
|
||||||
print(f"Check interval: {args.interval} seconds")
|
|
||||||
print("Press Ctrl+C to stop.")
|
|
||||||
|
|
||||||
hwnd = None
|
|
||||||
last_hwnd_check_time = 0
|
|
||||||
|
|
||||||
try:
|
|
||||||
while True:
|
|
||||||
current_time = time.time()
|
|
||||||
window = None
|
|
||||||
|
|
||||||
# Find window handle (HWND) - less frequent check if already found
|
|
||||||
# pygetwindow can be slow, so avoid calling it too often if we have a valid handle
|
|
||||||
if not hwnd or current_time - last_hwnd_check_time > 5: # Re-check HWND every 5 seconds
|
|
||||||
window_obj = find_window_by_title(args.window_title)
|
|
||||||
if window_obj:
|
|
||||||
# Get the HWND (window handle) needed for win32gui
|
|
||||||
# Accessing _hWnd is using an internal attribute, but it's common practice with pygetwindow
|
|
||||||
try:
|
|
||||||
hwnd = window_obj._hWnd
|
|
||||||
window = window_obj # Keep the pygetwindow object for position checks
|
|
||||||
last_hwnd_check_time = current_time
|
|
||||||
# print(f"Found window HWND: {hwnd}")
|
|
||||||
except AttributeError:
|
|
||||||
print("Could not get HWND from window object. Retrying...")
|
|
||||||
hwnd = None
|
|
||||||
else:
|
|
||||||
if hwnd:
|
|
||||||
print(f"Window '{args.window_title}' lost.")
|
|
||||||
hwnd = None # Reset hwnd if window not found
|
|
||||||
|
|
||||||
if hwnd:
|
|
||||||
# Ensure it's always on top
|
|
||||||
set_window_always_on_top(hwnd)
|
|
||||||
|
|
||||||
# Check and correct position using the pygetwindow object if available
|
|
||||||
# Re-find the pygetwindow object if needed for position check
|
|
||||||
if not window:
|
|
||||||
window = find_window_by_title(args.window_title)
|
|
||||||
|
|
||||||
if window:
|
|
||||||
move_window_if_needed(window, args.x, args.y)
|
|
||||||
else:
|
|
||||||
# If we have hwnd but can't get pygetwindow object, maybe it's closing
|
|
||||||
print(f"Have HWND {hwnd} but cannot get window object for position check.")
|
|
||||||
hwnd = None # Force re-find next cycle
|
|
||||||
|
|
||||||
else:
|
|
||||||
# print(f"Window '{args.window_title}' not found. Waiting...")
|
|
||||||
pass # Wait for the window to appear
|
|
||||||
|
|
||||||
time.sleep(args.interval)
|
|
||||||
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
print("\nMonitoring stopped by user.")
|
|
||||||
except Exception as e:
|
|
||||||
print(f"\nAn unexpected error occurred: {e}")
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
@ -1,103 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
"""
|
|
||||||
Game Window Setup Script - Adjust game window position and size
|
|
||||||
|
|
||||||
This script will launch the game and adjust its window to a specified position and size (100,100 1280x768),
|
|
||||||
making it easier to take screenshots of UI elements for later use.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import os
|
|
||||||
import time
|
|
||||||
import subprocess
|
|
||||||
import pygetwindow as gw
|
|
||||||
import psutil
|
|
||||||
import argparse
|
|
||||||
|
|
||||||
def is_process_running(process_name):
|
|
||||||
"""Check if a specified process is currently running"""
|
|
||||||
for proc in psutil.process_iter(['name']):
|
|
||||||
if proc.info['name'].lower() == process_name.lower():
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def launch_game(game_path):
|
|
||||||
"""Launch the game"""
|
|
||||||
if not os.path.exists(game_path):
|
|
||||||
print(f"Error: Game executable not found at {game_path}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
print(f"Launching game: {game_path}")
|
|
||||||
subprocess.Popen(game_path)
|
|
||||||
return True
|
|
||||||
|
|
||||||
def find_game_window(window_title, max_wait=30):
|
|
||||||
"""Find the game window"""
|
|
||||||
print(f"Searching for game window: {window_title}")
|
|
||||||
|
|
||||||
start_time = time.time()
|
|
||||||
while time.time() - start_time < max_wait:
|
|
||||||
try:
|
|
||||||
windows = gw.getWindowsWithTitle(window_title)
|
|
||||||
if windows:
|
|
||||||
return windows[0]
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error finding window: {e}")
|
|
||||||
|
|
||||||
print("Window not found, waiting 1 second before retrying...")
|
|
||||||
time.sleep(1)
|
|
||||||
|
|
||||||
print(f"Error: Game window not found within {max_wait} seconds")
|
|
||||||
return None
|
|
||||||
|
|
||||||
def set_window_position_size(window, x, y, width, height):
|
|
||||||
"""Set window position and size"""
|
|
||||||
try:
|
|
||||||
print(f"Adjusting window position to ({x}, {y}) and size to {width}x{height}")
|
|
||||||
window.moveTo(x, y)
|
|
||||||
window.resizeTo(width, height)
|
|
||||||
print("Window adjustment completed")
|
|
||||||
return True
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error adjusting window: {e}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
def main():
|
|
||||||
parser = argparse.ArgumentParser(description='Game Window Setup Tool')
|
|
||||||
parser.add_argument('--launch', action='store_true', help='Whether to launch the game')
|
|
||||||
parser.add_argument('--game_path', default=r"C:\Users\Bigspring\AppData\Local\TheLastWar\Launch.exe", help='Game launcher path')
|
|
||||||
parser.add_argument('--window_title', default="Last War-Survival Game", help='Game window title')
|
|
||||||
parser.add_argument('--process_name', default="LastWar.exe", help='Game process name')
|
|
||||||
parser.add_argument('--x', type=int, default=50, help='Window X coordinate')
|
|
||||||
parser.add_argument('--y', type=int, default=30, help='Window Y coordinate')
|
|
||||||
parser.add_argument('--width', type=int, default=600, help='Window width')
|
|
||||||
parser.add_argument('--height', type=int, default=1070, help='Window height')
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
# Check if game is already running
|
|
||||||
if not is_process_running(args.process_name):
|
|
||||||
if args.launch:
|
|
||||||
# Launch the game
|
|
||||||
if not launch_game(args.game_path):
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
print(f"Game process {args.process_name} is not running, please launch the game first or use the --launch parameter")
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
print(f"Game process {args.process_name} is already running")
|
|
||||||
|
|
||||||
# Find game window
|
|
||||||
window = find_game_window(args.window_title)
|
|
||||||
if not window:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Set window position and size
|
|
||||||
set_window_position_size(window, args.x, args.y, args.width, args.height)
|
|
||||||
|
|
||||||
# Display final window state
|
|
||||||
print("\nFinal window state:")
|
|
||||||
print(f"Position: ({window.left}, {window.top})")
|
|
||||||
print(f"Size: {window.width}x{window.height}")
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
Loading…
x
Reference in New Issue
Block a user