# Player Management API Endpoints - Fixed for accounts+characters schema @app.route('/api/editor/players', methods=['GET']) @require_auth def get_players(): """Get list of all characters with their account info""" sys.path.insert(0, str(PARENT_DIR)) try: from api import database except ImportError: return jsonify({'error': 'Database module not available'}), 500 import asyncio import time from sqlalchemy import text async def fetch_players(): players_list = [] try: async with database.engine.connect() as conn: # Get all characters with account info result = await conn.execute(text(""" SELECT c.id, c.account_id, c.name, c.location_id, c.hp, c.max_hp, c.stamina, c.max_stamina, c.level, c.xp, c.strength, c.agility, c.endurance, c.intellect, c.unspent_points, a.email, a.premium_expires_at, a.created_at, c.created_at as character_created_at FROM characters c LEFT JOIN accounts a ON c.account_id = a.id ORDER BY c.name """)) rows = result.fetchall() for row in rows: players_list.append({ 'id': row[0], 'account_id': row[1], 'character_name': row[2], 'location_id': row[3], 'hp': row[4], 'max_hp': row[5], 'stamina': row[6], 'max_stamina': row[7], 'level': row[8], 'xp': row[9], 'strength': row[10], 'agility': row[11], 'endurance': row[12], 'intellect': row[13], 'unspent_points': row[14], 'email': row[15], 'premium_expires_at': row[16], 'account_created_at': row[17], 'character_created_at': row[18], 'is_premium': row[16] and row[16] > time.time() if row[16] else False }) except Exception as e: print(f"[PLAYERS] Error fetching players: {e}", flush=True) import traceback traceback.print_exc() return players_list players = asyncio.run(fetch_players()) return jsonify({'players': players}) @app.route('/api/editor/player/', methods=['GET']) @require_auth def get_player_details(character_id): """Get detailed character information including inventory""" sys.path.insert(0, str(PARENT_DIR)) try: from api import database except ImportError: return jsonify({'error': 'Database module not available'}), 500 import asyncio from sqlalchemy import text async def fetch_player_details(): player_data = {} try: async with database.engine.connect() as conn: # Get character basic info with account result = await conn.execute(text(""" SELECT c.*, a.email, a.premium_expires_at, a.created_at as account_created_at FROM characters c LEFT JOIN accounts a ON c.account_id = a.id WHERE c.id = :cid """), {'cid': character_id}) row = result.fetchone() if not row: return None player_data = dict(row._mapping) # Get inventory result = await conn.execute(text(""" SELECT i.item_id, i.quantity, i.is_equipped, i.unique_item_id, u.durability, u.max_durability, u.tier, u.unique_stats FROM inventory i LEFT JOIN unique_items u ON i.unique_item_id = u.id WHERE i.character_id = :cid """), {'cid': character_id}) inventory = [] equipped = {} for row in result.fetchall(): item_data = { 'item_id': row[0], 'quantity': row[1] } if row[3]: # Has unique_item_id item_data['unique_item_data'] = { 'durability': row[4], 'max_durability': row[5], 'tier': row[6], 'unique_stats': row[7] } if row[2]: # is_equipped equipped[row[0]] = item_data else: inventory.append(item_data) player_data['inventory'] = inventory player_data['equipped'] = equipped except Exception as e: print(f"[PLAYER-DETAILS] Error: {e}", flush=True) import traceback traceback.print_exc() return None return player_data player = asyncio.run(fetch_player_details()) if not player: return jsonify({'error': 'Player not found'}), 404 return jsonify(player) @app.route('/api/editor/player/', methods=['POST']) @require_auth def update_player(character_id): """Update character stats and properties""" sys.path.insert(0, str(PARENT_DIR)) try: from api import database except ImportError: return jsonify({'error': 'Database module not available'}), 500 import asyncio from sqlalchemy import text data = request.get_json() async def update_player_data(): try: async with database.engine.begin() as conn: # Update character stats await conn.execute(text(""" UPDATE characters SET name = :name, location_id = :location, hp = :hp, max_hp = :max_hp, stamina = :stamina, max_stamina = :max_stamina, level = :level, xp = :xp, strength = :str, agility = :agi, endurance = :end, intellect = :int, unspent_points = :unspent WHERE id = :cid """), { 'cid': character_id, 'name': data.get('character_name'), 'location': data.get('location_id'), 'hp': data.get('hp'), 'max_hp': data.get('max_hp'), 'stamina': data.get('stamina'), 'max_stamina': data.get('max_stamina'), 'level': data.get('level'), 'xp': data.get('xp'), 'str': data.get('strength'), 'agi': data.get('agility'), 'end': data.get('endurance'), 'int': data.get('intellect'), 'unspent': data.get('unspent_points', 0) }) return True except Exception as e: print(f"[UPDATE-PLAYER] Error: {e}", flush=True) import traceback traceback.print_exc() return False success = asyncio.run(update_player_data()) if success: return jsonify({'success': True, 'message': 'Player updated successfully'}) else: return jsonify({'error': 'Failed to update player'}), 500 # Simplified inventory/equipment endpoints - not fully implemented @app.route('/api/editor/player//inventory', methods=['POST']) @require_auth def update_player_inventory(character_id): return jsonify({'success': True, 'message': 'Inventory editing not yet implemented'}) @app.route('/api/editor/player//equipment', methods=['POST']) @require_auth def update_player_equipment(character_id): return jsonify({'success': True, 'message': 'Equipment managed via inventory'}) # Simplified account management - accounts don't have ban functionality in new schema @app.route('/api/editor/account//ban', methods=['POST']) @require_auth def ban_account(account_id): return jsonify({'success': True, 'message': 'Ban functionality not implemented in new schema'}) @app.route('/api/editor/account//delete', methods=['DELETE']) @require_auth def delete_account(account_id): """Delete an account and all associated characters""" sys.path.insert(0, str(PARENT_DIR)) try: from api import database except ImportError: return jsonify({'error': 'Database module not available'}), 500 import asyncio from sqlalchemy import text async def delete_account_data(): try: async with database.engine.begin() as conn: # CASCADE will handle characters and their inventory await conn.execute(text("DELETE FROM accounts WHERE id = :aid"), {'aid': account_id}) return True except Exception as e: print(f"[DELETE-ACCOUNT] Error: {e}", flush=True) import traceback traceback.print_exc() return False success = asyncio.run(delete_account_data()) if success: return jsonify({'success': True, 'message': 'Account deleted successfully'}) else: return jsonify({'error': 'Failed to delete account'}), 500 @app.route('/api/editor/player//reset', methods=['POST']) @require_auth def reset_player(character_id): """Reset character to starting state""" sys.path.insert(0, str(PARENT_DIR)) try: from api import database except ImportError: return jsonify({'error': 'Database module not available'}), 500 import asyncio from sqlalchemy import text async def reset_player_data(): try: async with database.engine.begin() as conn: # Clear inventory await conn.execute(text("DELETE FROM inventory WHERE character_id = :cid"), {'cid': character_id}) # Reset character stats to defaults await conn.execute(text(""" UPDATE characters SET location_id = 'cabin', hp = 100, max_hp = 100, stamina = 100, max_stamina = 100, level = 1, xp = 0, strength = 0, agility = 0, endurance = 0, intellect = 0, unspent_points = 20, is_dead = false WHERE id = :cid """), {'cid': character_id}) return True except Exception as e: print(f"[RESET-PLAYER] Error: {e}", flush=True) import traceback traceback.print_exc() return False success = asyncio.run(reset_player_data()) if success: return jsonify({'success': True, 'message': 'Player reset successfully'}) else: return jsonify({'error': 'Failed to reset player'}), 500