from fastapi import FastAPI, WebSocket, WebSocketDisconnect import uvicorn import json import os import uuid app = FastAPI() PLAYERS_FILE = "players.json" ENTREPRISES_FILE = "entreprises.json" clients = {} logged_users = {} player_positions = {} coop_requests = {} # ====================================================== # PLAYERS # ====================================================== def load_players(): if os.path.exists(PLAYERS_FILE): with open( PLAYERS_FILE, "r", encoding="utf-8" ) as f: return json.load(f) return {} def save_players(): with open( PLAYERS_FILE, "w", encoding="utf-8" ) as f: json.dump( players_data, f, indent=4, ensure_ascii=False ) # ====================================================== # ENTREPRISES # ====================================================== def load_entreprises(): if os.path.exists( ENTREPRISES_FILE ): with open( ENTREPRISES_FILE, "r", encoding="utf-8" ) as f: return json.load(f) return {} def save_entreprises(): with open( ENTREPRISES_FILE, "w", encoding="utf-8" ) as f: json.dump( entreprises_data, f, indent=4, ensure_ascii=False ) players_data = load_players() entreprises_data = load_entreprises() # ====================================================== # WEBSOCKET # ====================================================== @app.websocket("/ws") async def websocket_endpoint( ws: WebSocket ): await ws.accept() session_id = str( uuid.uuid4() ) clients[session_id] = ws username = None await ws.send_text(json.dumps({ "type":"welcome", "id":session_id })) try: while True: text = await ws.receive_text() data = json.loads(text) msg_type = data.get( "type", "" ) # ===================================== # LOGIN # ===================================== if msg_type == "login": user = str( data.get( "username", "" ) ).strip() password = str( data.get( "password", "" ) ).strip() if ( user == "" or password == "" ): await ws.send_text( json.dumps({ "type":"login_failed" }) ) continue if user not in players_data: players_data[user] = { "password":password, "money":0, "progress":1 } save_players() elif ( players_data[user]["password"] != password ): await ws.send_text( json.dumps({ "type":"login_failed" }) ) continue username = user logged_users[ session_id ] = username await ws.send_text( json.dumps({ "type":"login_success" }) ) await ws.send_text( json.dumps({ "type":"player_data", "money": players_data[user]["money"], "progress": players_data[user]["progress"] }) ) for sid in clients.keys(): if sid == session_id: continue await ws.send_text( json.dumps({ "type":"player_join", "id":sid }) ) for sid, client in clients.items(): if sid == session_id: continue try: await client.send_text( json.dumps({ "type":"player_join", "id":session_id }) ) except: pass for path, owner in ( entreprises_data.items() ): await ws.send_text( json.dumps({ "type":"entreprise_owner", "path":path, "owner":owner }) ) # ===================================== # POSITION # ===================================== elif ( msg_type == "player_update" ): player_positions[ session_id ] = { "x": data.get("x",0), "y": data.get("y",0), "z": data.get("z",0) } data["id"] = session_id for sid, client in clients.items(): if sid == session_id: continue try: await client.send_text( json.dumps( data ) ) except: pass # ===================================== # MONEY # ===================================== elif ( msg_type == "save_money" ): if username: players_data[ username ]["money"] = int( data.get( "money", 0 ) ) save_players() # ===================================== # PROGRESS # ===================================== elif ( msg_type == "save_progress" ): if username: progress = int( data.get( "progress", 1 ) ) players_data[ username ]["progress"] = progress save_players() broadcast = { "type":"player_progress", "id":session_id, "progress":progress } for sid, client in clients.items(): if sid == session_id: continue try: await client.send_text( json.dumps( broadcast ) ) except: pass # ===================================== # ENTREPRISE # ===================================== elif ( msg_type == "save_entreprise" ): path = data.get( "path", "" ) owner = data.get( "owner", "" ) entreprises_data[ path ] = owner save_entreprises() # ===================================== # CHANGE OWNER # ===================================== elif ( msg_type == "set_entreprise_owner" ): path = data.get( "path", "" ) owner = data.get( "owner", "" ) entreprises_data[ path ] = owner save_entreprises() broadcast = { "type":"entreprise_owner", "path":path, "owner":owner } for client in clients.values(): try: await client.send_text( json.dumps( broadcast ) ) except: pass # ===================================== # COOP INVITE # ===================================== elif ( msg_type == "coop_invite" ): if username: target = str( data.get( "target", "" ) ).strip() target_sid = None for sid, uname in logged_users.items(): if uname == target: target_sid = sid break if ( target_sid and target_sid in clients ): coop_requests[ target_sid ] = session_id try: await clients[ target_sid ].send_text( json.dumps({ "type":"coop_invite", "sender":username }) ) except: pass # ===================================== # COOP ACCEPT # ===================================== elif ( msg_type == "coop_accept" ): if username: sender_name = str( data.get( "sender", "" ) ).strip() sender_sid = None for sid, uname in logged_users.items(): if uname == sender_name: sender_sid = sid break if ( sender_sid and sender_sid in clients ): if session_id in coop_requests: del coop_requests[session_id] try: await clients[ sender_sid ].send_text( json.dumps({ "type":"coop_accept", "from":username }) ) except: pass # ===================================== # COOP REFUSE # ===================================== elif ( msg_type == "coop_refuse" ): if username: sender_name = str( data.get( "sender", "" ) ).strip() sender_sid = None for sid, uname in logged_users.items(): if uname == sender_name: sender_sid = sid break if ( sender_sid and sender_sid in clients ): if session_id in coop_requests: del coop_requests[session_id] try: await clients[ sender_sid ].send_text( json.dumps({ "type":"coop_refuse", "from":username }) ) except: pass except WebSocketDisconnect: pass finally: # Libération coop if session_id in coop_requests: del coop_requests[session_id] for k, v in list( coop_requests.items() ): if v == session_id: del coop_requests[k] # Libération entreprises to_clear = [] for path, owner in entreprises_data.items(): if owner == session_id: to_clear.append(path) for path in to_clear: entreprises_data[path] = "" for client in clients.values(): try: await client.send_text( json.dumps({ "type":"entreprise_owner", "path":path, "owner":"" }) ) except: pass save_entreprises() if session_id in clients: del clients[session_id] if session_id in logged_users: del logged_users[session_id] if session_id in player_positions: del player_positions[session_id] for client in clients.values(): try: await client.send_text( json.dumps({ "type":"player_leave", "id":session_id }) ) except: pass if __name__ == "__main__": port = int( os.environ.get( "PORT", 7860 ) ) uvicorn.run( app, host="0.0.0.0", port=port )