#!/usr/bin/env python3 import socket import time import sys import os import asyncio import importlib sys.path.append(os.path.dirname(os.path.abspath(__file__))) from src.database import Database from src.game_engine import GameEngine from modules import CoreCommands, Exploration, BattleSystem, PetManagement, Achievements, Admin, Inventory, GymBattles, TeamBuilder from webserver import PetBotWebServer class PetBotDebug: def __init__(self): print("šŸ¤– PetBot Debug Mode - Initializing...") self.database = Database() self.game_engine = GameEngine(self.database) self.config = { "server": "irc.libera.chat", "port": 6667, "nickname": "PetBot", "channel": "#petz", "command_prefix": "!" } self.socket = None self.connected = False self.running = True self.active_encounters = {} self.modules = {} self.command_map = {} self.web_server = None print("āœ… Basic initialization complete") def initialize_async_components(self): """Initialize async components""" print("šŸ”„ Creating event loop...") loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) print("āœ… Event loop created") print("šŸ”„ Initializing database...") loop.run_until_complete(self.database.init_database()) print("āœ… Database initialized") print("šŸ”„ Loading game data...") loop.run_until_complete(self.game_engine.load_game_data()) print("āœ… Game data loaded") print("šŸ”„ Loading modules...") self.load_modules() print("āœ… Modules loaded") print("šŸ”„ Validating player data and achievements...") loop.run_until_complete(self.validate_all_player_data()) print("āœ… Player data validation complete") print("šŸ”„ Starting background validation task...") self.start_background_validation(loop) print("āœ… Background validation started") print("šŸ”„ Starting web server...") self.web_server = PetBotWebServer(self.database, port=8080, bot=self) self.web_server.start_in_thread() print("āœ… Web server started") self.loop = loop print("āœ… Async components ready") def load_modules(self): """Load all command modules""" module_classes = [ CoreCommands, Exploration, BattleSystem, PetManagement, Achievements, Admin, Inventory, GymBattles, TeamBuilder ] self.modules = {} self.command_map = {} for module_class in module_classes: module_name = module_class.__name__ print(f" Loading {module_name}...") module_instance = module_class(self, self.database, self.game_engine) self.modules[module_name] = module_instance # Map commands to modules commands = module_instance.get_commands() for command in commands: self.command_map[command] = module_instance print(f" āœ… {module_name}: {len(commands)} commands") print(f"āœ… Loaded {len(self.modules)} modules with {len(self.command_map)} commands") async def validate_all_player_data(self): """Validate and refresh all player data on startup to prevent state loss""" try: # Get all players from database import aiosqlite async with aiosqlite.connect(self.database.db_path) as db: cursor = await db.execute("SELECT id, nickname FROM players") players = await cursor.fetchall() print(f"šŸ”„ Found {len(players)} players to validate...") for player_id, nickname in players: try: # Check and award any missing achievements for each player new_achievements = await self.game_engine.check_all_achievements(player_id) if new_achievements: print(f" šŸ† {nickname}: Restored {len(new_achievements)} missing achievements") for achievement in new_achievements: print(f" - {achievement['name']}") else: print(f" āœ… {nickname}: All achievements up to date") # Validate team composition team_composition = await self.database.get_team_composition(player_id) if team_composition["active_pets"] == 0 and team_composition["total_pets"] > 0: # Player has pets but none active - activate the first one pets = await self.database.get_player_pets(player_id) if pets: first_pet = pets[0] await self.database.activate_pet(player_id, str(first_pet["id"])) print(f" šŸ”§ {nickname}: Auto-activated pet {first_pet['nickname'] or first_pet['species_name']} (no active pets)") except Exception as e: print(f" āŒ Error validating {nickname}: {e}") print("āœ… All player data validated and updated") except Exception as e: print(f"āŒ Error during player data validation: {e}") # Don't fail startup if validation fails def start_background_validation(self, loop): """Start background task to periodically validate player data""" import asyncio async def periodic_validation(): while True: try: await asyncio.sleep(1800) # Run every 30 minutes print("šŸ”„ Running periodic player data validation...") await self.validate_all_player_data() except Exception as e: print(f"āŒ Error in background validation: {e}") # Create background task loop.create_task(periodic_validation()) async def reload_modules(self): """Reload all modules (for admin use)""" try: # Reload module files import modules importlib.reload(modules.core_commands) importlib.reload(modules.exploration) importlib.reload(modules.battle_system) importlib.reload(modules.pet_management) importlib.reload(modules.achievements) importlib.reload(modules.admin) importlib.reload(modules) # Reinitialize modules print("šŸ”„ Reloading modules...") self.load_modules() print("āœ… Modules reloaded successfully") return True except Exception as e: print(f"āŒ Module reload failed: {e}") return False def test_connection(self): """Test if we can connect to IRC""" print("šŸ”„ Testing IRC connection...") try: test_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) test_sock.settimeout(5) test_sock.connect((self.config["server"], self.config["port"])) test_sock.close() print("āœ… IRC connection test successful") return True except Exception as e: print(f"āŒ IRC connection failed: {e}") return False def connect(self): print("šŸš€ Starting bot connection process...") print("šŸ”„ Step 1: Initialize async components...") self.initialize_async_components() print("āœ… Step 1 complete") print("šŸ”„ Step 2: Test IRC connectivity...") if not self.test_connection(): print("āŒ IRC connection test failed - would run offline mode") print("āœ… Bot core systems are working - IRC connection unavailable") return print("āœ… Step 2 complete") print("šŸ”„ Step 3: Create IRC socket...") self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.socket.settimeout(10) print("āœ… Socket created") print("šŸ”„ Step 4: Connect to IRC server...") try: self.socket.connect((self.config["server"], self.config["port"])) print("āœ… Connected to IRC server!") except Exception as e: print(f"āŒ Failed to connect: {e}") return print("šŸ”„ Step 5: Send IRC handshake...") self.send(f"NICK {self.config['nickname']}") self.send(f"USER {self.config['nickname']} 0 * :{self.config['nickname']}") print("āœ… Handshake sent") print("šŸ”„ Step 6: Start main loop...") self.socket.settimeout(1) print("āœ… Bot is now running!") print(f"āœ… Will join {self.config['channel']} when connected") print(f"āœ… Loaded commands: {', '.join(sorted(self.command_map.keys()))}") print("šŸŽ® Ready for testing! Press Ctrl+C to stop.") self.main_loop() def main_loop(self): message_count = 0 while self.running: try: data = self.socket.recv(4096).decode('utf-8', errors='ignore') if not data: print("šŸ’€ Connection closed by server") break lines = data.strip().split('\n') for line in lines: if line.strip(): message_count += 1 if message_count <= 10: # Show first 10 messages for debugging print(f"šŸ“Ø {message_count}: {line.strip()}") self.handle_line(line.strip()) except socket.timeout: continue except KeyboardInterrupt: print("\nšŸ›‘ Shutting down bot...") self.running = False break except Exception as e: print(f"āŒ Error in main loop: {e}") time.sleep(1) if self.socket: self.socket.close() self.loop.close() print("āœ… Bot shutdown complete") def send(self, message): if self.socket: full_message = f"{message}\r\n" print(f"šŸ“¤ >> {message}") self.socket.send(full_message.encode('utf-8')) def handle_line(self, line): if line.startswith("PING"): pong_response = line.replace("PING", "PONG") self.send(pong_response) return # Handle connection messages if "376" in line or "422" in line: # End of MOTD if not self.connected: self.send(f"JOIN {self.config['channel']}") self.connected = True print(f"šŸŽ‰ Joined {self.config['channel']} - Bot is ready for commands!") return parts = line.split() if len(parts) < 4: return if parts[1] == "PRIVMSG": channel = parts[2] message = " ".join(parts[3:])[1:] hostmask = parts[0][1:] nickname = hostmask.split('!')[0] if message.startswith(self.config["command_prefix"]): print(f"šŸŽ® Command from {nickname}: {message}") self.handle_command(channel, nickname, message) def handle_command(self, channel, nickname, message): from modules.base_module import BaseModule command_parts = message[1:].split() if not command_parts: return command = BaseModule.normalize_input(command_parts[0]) args = BaseModule.normalize_input(command_parts[1:]) try: if command in self.command_map: module = self.command_map[command] print(f"šŸ”§ Executing {command} via {module.__class__.__name__}") # Run async command handler self.loop.run_until_complete( module.handle_command(channel, nickname, command, args) ) else: self.send_message(channel, f"{nickname}: Unknown command. Use !help for available commands.") except Exception as e: self.send_message(channel, f"{nickname}: Error processing command: {str(e)}") print(f"āŒ Command error: {e}") import traceback traceback.print_exc() def send_message(self, target, message): self.send(f"PRIVMSG {target} :{message}") time.sleep(0.5) async def send_team_builder_pin(self, nickname, pin_code): """Send team builder PIN via private message""" if hasattr(self.modules.get('TeamBuilder'), 'send_team_builder_pin'): await self.modules['TeamBuilder'].send_team_builder_pin(nickname, pin_code) else: # Fallback direct PM message = f"šŸ” Team Builder PIN: {pin_code} (expires in 10 minutes)" self.send_message(nickname, message) def run_async_command(self, coro): return self.loop.run_until_complete(coro) if __name__ == "__main__": print("🐾 Starting Pet Bot for IRC (Debug Mode)...") bot = PetBotDebug() # Make bot instance globally accessible for webserver import sys sys.modules[__name__].bot_instance = bot try: bot.connect() except KeyboardInterrupt: print("\nšŸ”„ Bot stopping...") # Gracefully shutdown the game engine try: bot.loop.run_until_complete(bot.game_engine.shutdown()) except Exception as e: print(f"Error during shutdown: {e}") print("āœ… Bot stopped by user") except Exception as e: print(f"āŒ Bot crashed: {e}") import traceback traceback.print_exc()