Spaces:
Runtime error
Runtime error
File size: 15,761 Bytes
4c75d73 | 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 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 | """
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
|