from flask_socketio import emit from extensions import socketio, db from models import Event, Inventory from flask import request import json from dateutil import parser from datetime import datetime @socketio.on('connect') def handle_connect(): print('Client connected') emit('clear_events') # Send history try: recent_events = Event.query.order_by(Event.timestamp.desc()).limit(30).all() print(f"Sending history: {len(recent_events)} events") for event in reversed(recent_events): emit('game_event', event.to_dict()) except Exception as e: print(f"Error sending history: {e}") @socketio.on('disconnect') def handle_disconnect(): print('Client disconnected') @socketio.on('game_event') def handle_game_event(data): # data = {type: 'CHAT', player: 'Name', content: 'Message', ...} print(f"Received event: {data}") # Save to DB try: if not data.get('type'): print(f"Error: Missing event type in {data}") return event_timestamp = None if data.get('timestamp'): try: event_timestamp = parser.parse(data.get('timestamp')) except Exception as e: print(f"Error parsing timestamp: {e}") event_timestamp = datetime.utcnow() event = Event( event_type=data.get('type'), player_uuid=data.get('uuid'), player_name=data.get('player'), content=data.get('content'), location=data.get('location'), timestamp=event_timestamp or datetime.utcnow() ) db.session.add(event) db.session.commit() print(f"Event saved to DB: {event.id}") # If inventory data is present, save it if 'inventory' in data: inventory = Inventory( event_id=event.id, player_uuid=data.get('uuid'), items=json.dumps(data.get('inventory')) ) db.session.add(inventory) db.session.commit() print(f"Inventory saved for event {event.id}") except Exception as e: print(f"Error saving event to DB: {str(e)}") db.session.rollback() # Broadcast to admin dashboard print(f"Broadcasting event: {data}") emit('game_event', data, broadcast=True) @socketio.on('universal_event') def handle_universal_event(data): # data = {type: 'EventName', package: 'pkg', timestamp: '...', event_data: {...}, player: 'Name'} print(f"Received universal event: {data.get('type')}") # Save to DB try: event_timestamp = None if data.get('timestamp'): try: event_timestamp = parser.parse(data.get('timestamp')) except Exception as e: even_timestamp = datetime.utcnow() # Flatten event_data to string for content if no content provided content = data.get('content') if not content and 'event_data' in data: content = json.dumps(data.get('event_data')) # Map to existing schema event = Event( event_type=data.get('type'), player_uuid=data.get('uuid'), # Might be missing in generic events player_name=data.get('player'), content=content, location=data.get('event_data', {}).get('location'), # Try to find location timestamp=event_timestamp or datetime.utcnow() ) db.session.add(event) db.session.commit() except Exception as e: print(f"Error saving universal event: {e}") db.session.rollback() emit('universal_event', data, broadcast=True) DEFAULT_IGNORED_EVENTS = { "org.bukkit.event.player.PlayerMoveEvent", "org.bukkit.event.player.PlayerInputEvent", "org.bukkit.event.player.PlayerStatisticIncrementEvent", "org.bukkit.event.player.PlayerVelocityEvent", "org.bukkit.event.vehicle.VehicleMoveEvent", "org.bukkit.event.block.BlockPhysicsEvent", "org.bukkit.event.world.ChunkLoadEvent", "org.bukkit.event.world.ChunkUnloadEvent", "com.destroystokyo.paper.event.server.ServerTickEndEvent", "com.destroystokyo.paper.event.server.ServerTickStartEvent", "org.bukkit.event.vehicle.VehicleUpdateEvent", "org.bukkit.event.entity.EntityAirChangeEvent", "org.bukkit.event.entity.CreatureSpawnEvent", "org.bukkit.event.world.GenericGameEvent", "org.bukkit.event.world.EntitiesLoadEvent", "org.bukkit.event.world.EntitiesUnloadEvent", "org.bukkit.event.entity.BatToggleSleepEvent", "org.bukkit.event.entity.EntityPoseChangeEvent", "org.bukkit.event.entity.EntityRemoveEvent" } @socketio.on('event_metadata') def handle_event_metadata(data): from models import EventConfig print(f"Received event metadata: {len(data.get('events', []))} events registered") # Sync with DB received_events = data.get('events', []) try: # Get existing configs existing = {c.event_name: c for c in EventConfig.query.all()} for event_name in received_events: if event_name not in existing: # Add new event package_name = event_name.rsplit('.', 1)[0] is_enabled = event_name not in DEFAULT_IGNORED_EVENTS new_config = EventConfig(event_name=event_name, package_name=package_name, is_enabled=is_enabled) db.session.add(new_config) db.session.commit() # Send back configuration send_config_update() except Exception as e: print(f"Error syncing event config: {e}") db.session.rollback() emit('event_metadata', data, broadcast=True) def send_config_update(): from models import EventConfig try: enabled_events = [c.event_name for c in EventConfig.query.filter_by(is_enabled=True).all()] print(f"Sending config update: {len(enabled_events)} enabled events") emit('config_update', {'enabled_events': enabled_events}, broadcast=True) except Exception as e: print(f"Error sending configs: {e}") @socketio.on("*") def handle_any_event(event, methods=None, data=None): if event not in ['connect', 'disconnect', 'game_event', 'universal_event', 'event_metadata']: print(f"Server received event: {event} with data: {data}")