Chris4K's picture
Upload 195 files
4c75d73 verified
Raw
History Blame Contribute Delete
15.8 kB
"""
Game Facade - Simplified interface for complex game operations.
"""
import time
from typing import Dict, Any, Optional, List, Tuple
from ..core.game_engine import get_game_engine
from ..core.player import Player
class GameFacade:
"""Facade providing simplified access to game functionality."""
def __init__(self):
self.engine = get_game_engine()
def start_game(self) -> bool:
"""Start the game engine and all services."""
return self.engine.start()
def stop_game(self) -> bool:
"""Stop the game engine and all services."""
return self.engine.stop()
# Player Operations
def join_game(self, name: str, player_type: str = "human") -> Optional[str]:
"""Join a player to the game."""
try:
player_service = self.engine.get_player_service()
# Create player
player = player_service.create_player(name, player_type)
# Add to world
success = player_service.add_player_to_world(player)
if success:
# Notify plugins
self.engine.get_plugin_service().call_plugin_event('on_player_join', player.id)
return player.id
return None
except Exception as e:
print(f"[GameFacade] Error joining game: {e}")
return None
def leave_game(self, player_id: str) -> bool:
"""Remove a player from the game."""
try:
player_service = self.engine.get_player_service()
# Notify plugins before removal
self.engine.get_plugin_service().call_plugin_event('on_player_leave', player_id)
return player_service.remove_player_from_world(player_id)
except Exception as e:
print(f"[GameFacade] Error leaving game: {e}")
return False
def move_player(self, player_id: str, direction: str) -> Tuple[bool, Dict[str, int], List[str]]:
"""Move a player in specified direction, returning success, new position, and triggered events."""
from math import sqrt
success = self.engine.get_player_service().move_player(player_id, direction)
new_position = {}
events = []
if success:
# Get updated player position
player = self.engine.get_player_service().get_player(player_id)
new_position = {'x': player.x, 'y': player.y}
# Gather world events since movement
world_events = self.engine.get_world().get_world_events()
# Extract only new events messages
events = [ev.get('event') for ev in world_events]
return success, new_position, events
def get_player_stats(self, player_id: str) -> Dict:
"""Get player statistics."""
return self.engine.get_player_service().get_player_stats(player_id)
def handle_action(self, player_id: str) -> str:
"""Handle special action: interact with nearest NPC if in range."""
# Determine proximity
prox = self.get_proximity_info(player_id)
nearby = prox.get('nearby_entities', [])
if nearby:
npc_id = nearby[0]['id']
# Interact with NPC via default empty message
return self.interact_with_npc(player_id, npc_id, "")
return "No entity nearby to interact."
def get_proximity_info(self, player_id: str) -> Dict[str, Any]:
"""Get nearby entities (NPCs and other players) within interaction range."""
import math
result = {'nearby_entities': []}
# Get player position
player = self.engine.get_player_service().get_player(player_id)
if not player:
return result
# Check NPCs
world = self.engine.get_world()
for npc_id, npc_data in world.get_all_npcs().items():
dx = player.x - npc_data.get('x', 0)
dy = player.y - npc_data.get('y', 0)
distance = math.hypot(dx, dy)
if distance <= 50:
result['nearby_entities'].append({'id': npc_id, 'name': npc_data.get('name')})
# Optionally include other players
for other_id, other in world.get_all_players().items():
if other_id == player_id:
continue
dx = player.x - other.x
dy = player.y - other.y
if math.hypot(dx, dy) <= 50:
result['nearby_entities'].append({'id': other_id, 'name': other.name})
return result
# Chat Operations
def send_chat_message(self, player_id: str, message: str) -> bool:
"""Send a public chat message."""
try:
chat_service = self.engine.get_chat_service()
success = chat_service.send_public_message(player_id, message)
if success:
# Notify plugins
self.engine.get_plugin_service().call_plugin_event(
'on_chat_message', player_id, message, 'public'
)
return success
except Exception as e:
print(f"[GameFacade] Error sending chat: {e}")
return False
def get_chat_history(self, limit: int = 10) -> List[Dict]:
"""Get recent chat messages."""
return self.engine.get_chat_service().get_chat_history(limit)
# NPC Operations
def interact_with_npc(self, player_id: str, npc_id: str, message: str) -> str:
"""Interact with an NPC."""
return self.engine.get_npc_service().get_npc_response(npc_id, message, player_id)
def get_npc_data(self, npc_id: str) -> Optional[Dict]:
"""Get NPC information."""
return self.engine.get_npc_service().get_npc(npc_id)
# World State
def get_game_state(self) -> Dict:
"""Get current game state."""
return self.engine.get_world().get_world_state()
def get_all_players(self) -> Dict[str, Player]:
"""Get all players in the game."""
return self.engine.get_player_service().get_all_players()
def get_all_npcs(self) -> Dict[str, Dict]:
"""Get all NPCs in the game."""
return self.engine.get_npc_service().get_all_npcs()
# MCP Operations
def register_ai_agent(self, agent_id: str, name: str) -> str:
"""Register an AI agent via MCP."""
return self.engine.get_mcp_service().register_ai_agent(agent_id, name)
def move_ai_agent(self, agent_id: str, direction: str) -> Dict:
"""Move an AI agent."""
return self.engine.get_mcp_service().move_agent(agent_id, direction)
def ai_agent_chat(self, agent_id: str, message: str) -> Dict:
"""Send chat message from AI agent."""
return self.engine.get_mcp_service().send_chat(agent_id, message)
def get_available_npcs(self) -> List[Dict[str, Any]]:
"""Get list of available NPCs with their data for MCP integration."""
try:
npcs = self.get_all_npcs()
available_npcs = []
for npc_id, npc_data in npcs.items():
available_npcs.append({
'id': npc_id,
'name': npc_data.get('name', 'Unknown NPC'),
'type': npc_data.get('type', 'npc'),
'position': {
'x': npc_data.get('x', 0),
'y': npc_data.get('y', 0)
},
'description': npc_data.get('description', ''),
'dialogue_count': len(npc_data.get('dialogue_history', [])),
'active': npc_data.get('active', True)
})
return available_npcs
except Exception as e:
print(f"[GameFacade] Error getting available NPCs: {e}")
return []
def get_available_players(self) -> List[Dict[str, Any]]:
"""Get list of available players with their data for MCP integration."""
try:
players = self.get_all_players()
available_players = []
for player_id, player in players.items():
available_players.append({
'id': player.id,
'name': player.name,
'type': player.type,
'position': {
'x': player.x,
'y': player.y
},
'level': player.level,
'hp': f"{player.hp}/{player.max_hp}",
'gold': player.gold,
'experience': player.experience,
'last_active': player.last_active,
'session_hash': getattr(player, 'session_hash', None)
})
return available_players
except Exception as e:
print(f"[GameFacade] Error getting available players: {e}")
return []
def get_raw_world_data(self) -> Dict[str, Any]:
"""Get comprehensive raw world data without HTML parsing for MCP integration."""
try:
return {
'players': self.get_available_players(),
'npcs': self.get_available_npcs(),
'world_state': self.get_game_state(),
'world_events': self.get_world_events(),
'chat_history': self.get_chat_history(50), # More chat history for context
'system_status': self.get_system_status(),
'loaded_plugins': self.get_loaded_plugins(),
'timestamp': time.time()
}
except Exception as e:
print(f"[GameFacade] Error getting raw world data: {e}")
return {
'error': f"Failed to get raw world data: {str(e)}",
'timestamp': time.time()
}
def get_recent_chat_messages(self, limit: int = 20) -> List[Dict]:
"""Get recent chat messages for MCP integration."""
return self.get_chat_history(limit)
def get_recent_world_events(self, limit: int = 10) -> List[Dict[str, Any]]:
"""Get recent world events for MCP integration."""
try:
all_events = self.get_world_events()
return all_events[-limit:] if len(all_events) > limit else all_events
except Exception as e:
print(f"[GameFacade] Error getting recent world events: {e}")
return []
# Plugin Operations
def reload_plugin(self, plugin_id: str) -> bool:
"""Reload a plugin (hot-reload)."""
return self.engine.get_plugin_service().reload_plugin(plugin_id)
def get_loaded_plugins(self) -> List[str]:
"""Get list of loaded plugins."""
return self.engine.get_plugin_service().get_loaded_plugins()
def get_plugin_status(self, plugin_id: str) -> Optional[Dict]:
"""Get status of a specific plugin."""
return self.engine.get_plugin_service().get_plugin_status(plugin_id)
# World Events
def get_world_events(self) -> List[Dict[str, Any]]:
"""Get all world events."""
try:
world = self.engine.get_world()
return world.get_world_events()
except Exception as e:
print(f"[GameFacade] Error getting world events: {e}")
return []
# System Operations
def get_system_status(self) -> Dict[str, Any]:
"""Get comprehensive system status."""
return self.engine.get_engine_status()
def cleanup_inactive_players(self, timeout_seconds: int = 300) -> int:
"""Remove inactive players."""
return self.engine.get_player_service().cleanup_inactive_players(timeout_seconds)
def is_running(self) -> bool:
"""Check if game is running."""
return self.engine.is_running()
# Private Messaging
def send_private_message(self, sender_id: str, sender_name: str, recipient_id: str, message: str) -> bool:
"""Send a private message between players or to NPCs."""
success, _ = self.engine.get_chat_service().send_private_message(sender_id, recipient_id, message)
if success:
self.engine.get_plugin_service().call_plugin_event('on_chat_message', sender_id, message, 'private')
return success
def get_private_messages(self, player_id: str, entity_id: str) -> List[Dict]:
"""Get private messages between player and entity."""
history = self.engine.get_chat_service().get_chat_history()
private_msgs = []
for msg in history:
msg_type = msg.get('type', '')
# Check for private messages between player and entity (using backup version logic)
if msg_type in ['private_to_npc', 'private_from_npc', 'private_to_player', 'private_from_player']:
# Message is to/from this specific entity and player
if ((msg.get('sender_id') == player_id and msg.get('target') == entity_id) or
(msg.get('sender_id') == entity_id and msg.get('target') == player_id)):
private_msgs.append({
'timestamp': msg.get('timestamp', ''),
'sender': msg.get('sender', 'Unknown'),
'sender_id': msg.get('sender_id', ''),
'message': msg.get('message', ''),
'type': msg_type,
'target': msg.get('target', '')
})
print(f"[GameFacade] Found {len(private_msgs)} private messages between {player_id} and {entity_id}")
return private_msgs
# Utility methods for UI
def get_world_html(self) -> str:
"""Get HTML representation of the game world (for UI)."""
try:
players = self.get_all_players()
npcs = self.get_all_npcs()
# This would be implemented based on the original HTML generation logic
# For now, return a placeholder
return f"<div>Game World - {len(players)} players, {len(npcs)} NPCs</div>"
except Exception as e:
return f"<div>Error loading world: {e}</div>"
def get_player_from_session(self, session_hash: str) -> Optional[Player]:
"""Get player by session hash."""
try:
all_players = self.get_all_players()
for player in all_players.values():
if player.session_hash == session_hash:
return player
return None
except Exception as e:
print(f"[GameFacade] Error getting player from session: {e}")
return None
def update_player_session(self, player_id: str, session_hash: str) -> bool:
"""Update player session hash."""
try:
player = self.engine.get_player_service().get_player(player_id)
if player:
player.session_hash = session_hash
return self.engine.get_player_service().update_player(player)
return False
except Exception as e:
print(f"[GameFacade] Error updating player session: {e}")
return False