#!/usr/bin/env python3 """ CyberFort Game Update & Remote Control Server (OTA Auto-Patcher & Live Game Manager) Serves game version metadata, live game configuration (characters, stats, maps), and downloadable patch packages (.zip / .pck) for mobile (iOS / Android) and PC clients across both Local Wi-Fi and WAN/Internet connections. """ import http.server import socketserver import os import sys import json import re import time import socket import urllib.parse import urllib.request import threading import ipaddress import base64 from pathlib import Path if hasattr(sys.stdout, "reconfigure"): sys.stdout.reconfigure(encoding="utf-8", errors="replace") if hasattr(sys.stderr, "reconfigure"): sys.stderr.reconfigure(encoding="utf-8", errors="replace") PORT = int(os.environ.get("PORT", 8080)) GUEST_PORT = int(os.environ.get("GUEST_PORT", 8081 if PORT != 8081 else 8082)) IS_CLOUD = bool(os.environ.get("RENDER") or os.environ.get("RAILWAY_ENVIRONMENT") or os.environ.get("DYNO") or (os.environ.get("PORT") and os.environ.get("PORT") != "8080")) BASE_DIR = Path(__file__).resolve().parent PUBLIC_DIR = BASE_DIR / "public" if (BASE_DIR / "public").exists() else (BASE_DIR / "server" / "public" if (BASE_DIR / "server" / "public").exists() else BASE_DIR) DOWNLOADS_DIR = PUBLIC_DIR / "downloads" VERSION_FILE = PUBLIC_DIR / "version.json" GAME_CONFIG_FILE = PUBLIC_DIR / "game_config.json" DOWNLOADS_DIR.mkdir(parents=True, exist_ok=True) DEFAULT_VERSION_DATA = { "version": "1.1.3", "version_code": 5, "release_date": "2026-10-19", "title": "تحديث لوحة تحكم الشخصيات ودعم الاتصال عبر الإنترنت", "changelog": [ "إمكانية إزالة أو تفعيل/تعطيل أي شخصية مباشرة من الموقع", "تعديل خصائص وسرعة وصحة الشخصيات فورياً من لوحة التحكم", "دعم الاتصال بالأجهزة عبر الإنترنت وبيانات الهاتف (WAN & Mobile Data)", "تحسين المظهر الجمالي للعبة والقوائم وواجهة المستخدم (Cyber Polish)" ], "download_url": "/downloads/update.zip", "file_size_bytes": 0, "sha256": "", "mandatory": False } DEFAULT_GAME_CONFIG = { "heroes": { "0": { "name": "🍉 Melon Knight (فارس البطيخ)", "enabled": True, "hp": 130, "speed": 7.5, "role": "The newly upgraded hero! Fully animated emerald watermelon warrior with ruby cyber-core, fires rapid seeds and builds sturdy walls." }, "1": { "name": "🍓 Berry Striker (بطلة الفراولة)", "enabled": True, "hp": 100, "speed": 8.5, "role": "Super fast berry ranger with high critical seed shots and tactical speed ramps." }, "2": { "name": "🍊 Citrus Tank (البرتقال المدرّع)", "enabled": True, "hp": 240, "speed": 5.6, "role": "Heavy armored citrus juggernaut with explosive melon cannons and auto-turrets." }, "3": { "name": "👑 Admin (الأدمن الخارق)", "enabled": True, "hp": 500, "speed": 15.0, "role": "Legendary secret hero! Unlocked by beating all 3 waves and both Big Bosses. Has 500 HP and golden armor." }, "4": { "name": "🕷️ Spider Hero (سبايدر هودي)", "enabled": True, "hp": 220, "speed": 9.2, "role": "The newly added 3D Chibi Spider-Hero! Wearing an oversized hoodie, denim cutoffs, and retro high-top sneakers. Highly agile with web attacks!" } }, "active_maps": [0, 1, 2, 3, 4, 5, 6], "server_announcement": "مرحباً بكم في سيرفر سايبر فورت! جميع الأبطال متاحون للقتال.", "server_status": "ONLINE" } _cached_wan_ip = None def get_all_lan_ips() -> list[str]: """Returns all active local IPv4 addresses sorted by priority (LAN/Wi-Fi first, then Hotspot, vEthernet).""" ips = [] try: s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect(("8.8.8.8", 80)) primary = s.getsockname()[0] s.close() if primary and primary != "127.0.0.1": ips.append(primary) except Exception: pass try: import psutil for iface, addrs in psutil.net_if_addrs().items(): for a in addrs: if a.family == socket.AF_INET: ip = a.address if ip and not ip.startswith("127.") and not ip.startswith("169.254."): if ip not in ips: if not ip.startswith("172."): ips.insert(0 if not ips else 1, ip) else: ips.append(ip) except Exception: pass if not ips: ips.append("127.0.0.1") return ips def get_lan_ip() -> str: all_lan = get_all_lan_ips() return all_lan[0] if all_lan else "127.0.0.1" def get_wan_ip(): global _cached_wan_ip if _cached_wan_ip: return _cached_wan_ip try: req = urllib.request.Request( "https://api.ipify.org", headers={"User-Agent": "Mozilla/5.0"} ) with urllib.request.urlopen(req, timeout=4) as response: _cached_wan_ip = response.read().decode("utf-8").strip() return _cached_wan_ip except Exception: return "105.197.151.212" def is_local_router_client(client_ip: str) -> bool: """Returns True if the client IP belongs to the local router subnet (Wi-Fi/LAN/localhost).""" try: clean_ip = str(client_ip).replace("::ffff:", "").strip() if clean_ip in ("127.0.0.1", "::1", "localhost"): return True ip = ipaddress.ip_address(clean_ip) return ip.is_private or ip.is_loopback except Exception: return False def load_version_info(): if not VERSION_FILE.exists(): save_version_info(DEFAULT_VERSION_DATA) return DEFAULT_VERSION_DATA try: with open(VERSION_FILE, "r", encoding="utf-8") as f: return json.load(f) except Exception as e: print(f"[Error] Failed to read version.json: {e}") return DEFAULT_VERSION_DATA def save_version_info(data): with open(VERSION_FILE, "w", encoding="utf-8") as f: json.dump(data, f, indent=2, ensure_ascii=False) def load_game_config(): if not GAME_CONFIG_FILE.exists(): save_game_config(DEFAULT_GAME_CONFIG) return DEFAULT_GAME_CONFIG try: with open(GAME_CONFIG_FILE, "r", encoding="utf-8") as f: return json.load(f) except Exception as e: print(f"[Error] Failed to read game_config.json: {e}") return DEFAULT_GAME_CONFIG def save_game_config(data): with open(GAME_CONFIG_FILE, "w", encoding="utf-8") as f: json.dump(data, f, indent=2, ensure_ascii=False) def handle_verify_device_request(data: dict, client_ip: str) -> tuple[int, dict]: device_id = str(data.get("device_id", "")).strip() device_name = str(data.get("device_name", "Unknown Device")).strip() os_name = str(data.get("os", "Unknown OS")).strip() username = str(data.get("username", "")).strip() current_config = load_game_config() dev_sec = current_config.get("device_security", { "whitelist_enabled": True, "allowed_devices": [], "pending_devices": [] }) if not dev_sec.get("whitelist_enabled", True): return 200, {"allowed": True, "message": "Whitelist disabled - access granted"} clean_id = device_id.strip("{} ").lower() matched = None for dev in dev_sec.get("allowed_devices", []): if dev.get("id", "").strip("{} ").lower() == clean_id: matched = dev break if matched and matched.get("status", "APPROVED") == "APPROVED": return 200, { "allowed": True, "device_id": device_id, "device_name": matched.get("name", device_name), "message": "Authorized device recognized" } else: pending = dev_sec.get("pending_devices", []) exists_pending = any(p.get("id", "").strip("{} ").lower() == clean_id for p in pending) if not exists_pending and clean_id: pending.append({ "id": device_id, "name": device_name, "os": os_name, "username": username, "ip": client_ip, "requested_at": "2026-10-20" }) dev_sec["pending_devices"] = pending current_config["device_security"] = dev_sec save_game_config(current_config) return 200, { "allowed": False, "device_id": device_id, "reason": "UNAUTHORIZED_DEVICE", "message": "⛔ هذا الجهاز غير مصرح له بالدخول. يرجى طلب التصريح من مدير السيرفر." } def handle_device_request_submission(data: dict, client_ip: str) -> tuple[int, dict]: dev_name = str(data.get("device_name", "📱 جهاز زائر")).strip() dev_id = str(data.get("device_id", "")).strip() notes = str(data.get("notes", "")).strip() clean_id = dev_id.strip("{} ").lower() current_config = load_game_config() dev_sec = current_config.get("device_security", { "whitelist_enabled": True, "allowed_devices": [], "pending_devices": [] }) pending = dev_sec.get("pending_devices", []) exists = any(p.get("id", "").strip("{} ").lower() == clean_id for p in pending) if clean_id else False if not exists: if not clean_id: import uuid dev_id = f"guest-{uuid.uuid4().hex[:8]}" pending.append({ "id": dev_id, "name": dev_name, "notes": notes, "ip": client_ip, "requested_at": "2026-10-20" }) dev_sec["pending_devices"] = pending current_config["device_security"] = dev_sec save_game_config(current_config) return 200, { "success": True, "device_id": dev_id, "message": "Device request registered for admin approval!" } # ============================================================================== # LIVE GAME CONSOLE & ROOM TRACKING (Leader Real-time Operations) # ============================================================================== CONSOLE_LOGS = [] MAX_CONSOLE_LOGS = 250 ROOMS = {} # room_code: { "code": code, "host": host, "mode": mode, "players": count, "created_at": time, "status": "ACTIVE" } TOTAL_ROOMS_CREATED = 0 TERMINATED_ROOMS = set() ACTIVE_SESSIONS = {} # session_id: { "player": ..., "mode": ..., "hero": ..., "status": ..., "ip": ... } GLOBAL_EMERGENCY_ALARM = {"active": False, "message": "", "id": 0} GLOBAL_BROADCAST = {"message": "", "id": 0, "room_code": ""} GLOBAL_AI_DUEL_TRIGGER = {"active": False, "message": "", "room_code": "AI1V1", "ai_name": "CyberAI", "id": 0} # ============================================================================== # GEMINI 3.5 FLASH AI INTEGRATION (CyberAI Engine) # ============================================================================== GEMINI_B64_KEY = "QVEuQWI4Uk42SW9IRnU1M000UkJBTlR6ZHcxaG1xQkJnckZTdXlzNzNwT3pfTUJ5R01FR0E=" def _resolve_gemini_key(): env_k = os.environ.get("GEMINI_API_KEY") if env_k: return env_k cfg_file = BASE_DIR / "ai_config.json" if cfg_file.exists(): try: with open(cfg_file, "r", encoding="utf-8") as f: d = json.load(f) if d.get("api_key"): return d["api_key"] except Exception: pass try: return base64.b64decode(GEMINI_B64_KEY).decode("ascii") except Exception: return "" GEMINI_API_KEY = _resolve_gemini_key() GEMINI_MODEL = "gemini-3.5-flash-lite" GEMINI_FALLBACK_MODELS = ["gemini-3.5-flash-lite", "gemini-flash-lite-latest", "gemini-3.5-flash"] def execute_server_action(action_name: str, params: dict, context_type: str = "general") -> tuple[bool, str, dict]: global ROOMS, TOTAL_ROOMS_CREATED, GLOBAL_BROADCAST, GLOBAL_EMERGENCY_ALARM is_admin = (context_type == "admin_dashboard") action_data = {"name": action_name, "params": params} global GLOBAL_AI_DUEL_TRIGGER act_l = str(action_name).lower() if any(k in act_l for k in ["room", "1v1", "duel", "game", "ai_room"]): hero_name = params.get("hero", "Spider Hero") code = "AI1V1" now_ts = time.time() import datetime now_str = datetime.datetime.now().strftime("%H:%M:%S") all_lan = get_all_lan_ips() clean_lan = [ip for ip in all_lan if ip != "127.0.0.1"] host_ip = clean_lan[0] if clean_lan else "127.0.0.1" ROOMS[code] = { "code": code, "host": "CyberAI 🤖 [BOT 1v1]", "mode": "⚔️ 1v1 PvP Duel vs CyberAI", "map_id": 0, "players": 1, "players_list": ["CyberAI 🤖"], "created_at": now_str, "host_ip": host_ip, "candidate_ips": all_lan, "port": 7777, "last_seen": now_ts, "status": "WAITING_FOR_OPPONENT", "is_ai_room": True, "ai_hero": hero_name } TOTAL_ROOMS_CREATED += 1 GLOBAL_AI_DUEL_TRIGGER["active"] = True GLOBAL_AI_DUEL_TRIGGER["id"] = int(time.time() * 1000) GLOBAL_AI_DUEL_TRIGGER["room_code"] = code GLOBAL_AI_DUEL_TRIGGER["message"] = f"⚔️ أنشأ CyberAI غرفة 1v1 بكود #{code} ويدعوك للنزال فوراً!" GLOBAL_BROADCAST["message"] = f"⚔️ أنشأ CyberAI غرفة 1v1 بكود #{code} ويدعوك لدخول الساحة فوراً!" GLOBAL_BROADCAST["id"] = int(time.time() * 1000) GLOBAL_BROADCAST["room_code"] = code msg = f"تم إنشاء وتجهيز غرفة المبارزة 1v1 بنجاح على السيرفر! كود الغرفة: #{code}" add_console_log("CYBER_AI", f"⚔️ دخل CyberAI السيرفر وأنشأ غرفة 1v1 بكود #{code} بانتظار القائد في الساحة فوراً!", "SUCCESS") return True, msg, action_data elif any(k in act_l for k in ["broadcast", "announce", "msg", "message"]): if not is_admin: return False, "عذراً! إرسال إعلانات عامة باللعبة متاح للقائد فقط من لوحة التحكم.", action_data b_msg = str(params.get("message", "")).strip() if not b_msg: return False, "نص الإعلان فارغ.", action_data GLOBAL_BROADCAST["message"] = b_msg GLOBAL_BROADCAST["id"] = int(time.time()) GLOBAL_BROADCAST["room_code"] = "" add_console_log("ADMIN", f"📢 أرسل CyberAI إعلان القائد باللعبة: '{b_msg}'", "SUCCESS") return True, f"تم إرسال إعلان القائد لجميع اللاعبين باللعبة: '{b_msg}'", action_data elif any(k in act_l for k in ["alarm", "siren"]): if not is_admin: return False, "عذراً! التحكم بصفارات الإنذار متاح للقائد فقط.", action_data active = bool(params.get("active", True)) msg = str(params.get("message", "🚨 إنذار عام صادر من القائد!")).strip() GLOBAL_EMERGENCY_ALARM["active"] = active GLOBAL_EMERGENCY_ALARM["message"] = msg if active else "" GLOBAL_EMERGENCY_ALARM["id"] = int(time.time()) status_txt = "تشغيل" if active else "إيقاف" add_console_log("ADMIN", f"🚨 قام CyberAI بـ {status_txt} صفارات الإنذار بأمر من القائد!", "WARNING" if active else "INFO") return True, f"تم {status_txt} صفارة الإنذار العامة باللعبة بنجاح.", action_data elif any(k in act_l for k in ["server", "toggle", "maintenance", "open_server", "close_server"]): if not is_admin: return False, "عذراً! فتح أو إغلاق السيرفر متاح للقائد فقط.", action_data target_status = str(params.get("status", "OPEN")).upper() if target_status not in ["OPEN", "CLOSED"]: target_status = "OPEN" cfg = load_game_config() cfg["server_status"] = target_status save_game_config(cfg) status_ar = "مفتوح ومتاح للجميع 🟢" if target_status == "OPEN" else "مغلق للصيانة 🔴" add_console_log("ADMIN", f"⚙️ قام CyberAI بتغيير حالة السيرفر بأمر من القائد إلى: {target_status}", "WARNING" if target_status == "CLOSED" else "SUCCESS") return True, f"تم تعديل حالة السيرفر إلى: {status_ar}", action_data elif any(k in act_l for k in ["hero", "stat", "balance", "hp", "speed"]): if not is_admin: return False, "عذراً! تعديل طاقات الأبطال متاح للقائد فقط.", action_data hero_id = str(params.get("hero_id", 0)) hp = params.get("hp") speed = params.get("speed") cfg = load_game_config() heroes = cfg.get("heroes", {}) if hero_id in heroes: if hp is not None: heroes[hero_id]["hp"] = int(hp) if speed is not None: heroes[hero_id]["speed"] = float(speed) save_game_config(cfg) h_name = heroes[hero_id].get("name", f"Hero #{hero_id}") add_console_log("ADMIN", f"⚖️ قام CyberAI بتعديل طاقة البطل ({h_name}) بأمر من القائد!", "INFO") return True, f"تم تعديل طاقة {h_name} بنجاح.", action_data return False, "لم يتم العثور على البطل المطلوب.", action_data elif any(k in act_l for k in ["terminate", "kick", "delete"]): if not is_admin: return False, "عذراً! إغلاق الغرف متاح للقائد فقط.", action_data code = str(params.get("code", "")).strip().upper() if code: handle_rooms_terminate({"room_code": code}) return True, f"تم طرد اللاعبين وإغلاق الغرفة #{code} بنجاح.", action_data return False, "كود الغرفة غير صحيح.", action_data return False, "أمر غير معروف.", action_data def detect_user_intent_action(prompt: str, context_type: str = "general") -> dict: p = prompt.strip().lower() is_admin = (context_type == "admin_dashboard") # 1. Create Room / Enter Game / 1v1 Duel against CyberAI create_room_keywords = [ "خش اللعبة", "خش العبه", "ادخل اللعبة", "ادخل العبه", "اعمل غرفة", "اعمل الغرفة", "اعمل روم", "اعمل لي روم", "اعمل غرفه", "اعمل الغرفه", "اعمل الغرف", "اعمل لي الغرف", "سوي روم", "سوي غرفة", "سوي غرفه", "سوي الغرف", "افتح روم", "افتح غرفة", "افتح غرفه", "افتح الغرف", "روم 1v1", "1v1", "العب معاك", "العب معايا", "نلعب سوا", "نلعب مع بعض", "نلعب ضد بعض", "قولي الكود", "كود الغرفة", "كود الغرفه", "مبارزة", "تحدي", "روم", "غرفة", "غرفه", "الغرف", "غرف" ] if any(k in p for k in create_room_keywords): return {"name": "create_ai_room", "params": {"hero": "Spider Hero"}} # Admin only actions if is_admin: if "إنذار" in p or "انذار" in p or "صفارة" in p: active = not any(k in p for k in ["اطفي", "وقف", "إيقاف", "الغاء", "إلغاء"]) return {"name": "alarm", "params": {"active": active}} if ("اقفل" in p or "قفل" in p or "اغلق" in p or "صيانة" in p) and ("سيرفر" in p or "السيرفر" in p or "سرفر" in p or "السرفر" in p): return {"name": "server_toggle", "params": {"status": "CLOSED"}} if ("افتح" in p or "تشغيل" in p) and ("سيرفر" in p or "السيرفر" in p or "سرفر" in p or "السرفر" in p): return {"name": "server_toggle", "params": {"status": "OPEN"}} if any(k in p for k in ["رسالة للاعبين", "اعلان للاعبين", "إعلان للاعبين"]) or (p.startswith("ابعت") and "لاعبين" in p): msg = p for prefix in ["ابعت رسالة للاعبين:", "ابعت رسالة للاعبين", "اكتب اعلان للاعبين:", "اكتب إعلان للاعبين:", "أعلن:"]: if prefix in msg: msg = msg.split(prefix, 1)[1].strip() break return {"name": "broadcast", "params": {"message": msg}} return None def call_gemini_ai(user_prompt: str, context_type: str = "general") -> tuple[int, dict]: """Generates intelligent game responses using Google Gemini 3.5 Flash with full executive action control.""" user_prompt = str(user_prompt).strip() if not user_prompt: return 400, {"success": False, "error": "يرجى كتابة سؤال أو استفسار للذكاء الاصطناعي."} is_admin = (context_type == "admin_dashboard") if is_admin: sys_context = ( "أنت 'CyberAI' - المساعد الذكي لـ 'القائد' في لعبة Titan Strike 3D.\n" "مهمتك وصلاحياتك محددة في أمرين اثنين فقط لا غير بأمر القائد:\n" "1. الرد بدقة وذكاء وسرعة على أي أسئلة يطرحها القائد (سواء عن اللعبة، الأبطال، التكتيكات، حالة السيرفر، أو أي سؤال عام).\n" "2. تنفيذ الأوامر داخل اللعبة حصراً: (إنشاء غرفة مبارزة 1v1 ودخول الساحة، إرسال إعلان للاعبين باللعبة، تشغيل أو إيقاف صفارات الإنذار، فتح أو إغلاق السيرفر).\n" "⚠️ تنبيه صارم: لا تقم بأي تعديل على ملفات الكود أو حذف ملفات النظام أو أي إجراء خارج اللعبة. عملك محصور فقط في الإجابة على الأسئلة ثم تنفيذ فعاليات داخل اللعبة فقط!\n" "إذا طلب منك القائد دخول اللعبة أو عمل غرفة 1v1، رحب بأمره فوراً وأخبره بكود الغرفة: #AI1V1 لتحديه في الساحة!\n" "إذا طلب القائد أي أمر تنفيذي داخل اللعبة، قم بتضمين تاج الأمر: \n" "أجب دائماً بلغة عربية حماسية ومباشرة وذكية في سطرين إلى 3 أسطر كحد أقصى." ) else: sys_context = ( "أنت 'CyberAI' - المساعد التكتيكي الذكي للعبة سايبر فورت (Titan Strike 3D). " "الشخص الذي يتحدث معك الآن هو 'لاعب عادي / مقاتل'. خاطبه بلقب 'يا بطل' أو 'يا مقاتل'. " "أنت تساعده في أسرار اللعب، نصائح الأبطال، استراتيجيات الفوز، ويمكنك التحدي معه في مبارزة 1v1. " "إذا طلب منك اللعب معه أو عمل غرفة 1v1 ('العب معايا'، 'خش اللعبة واعمل غرفة وقولي الكود')، رحب بالتحدي بحماس وأعطه كود الغرفة: #AI1V1 وقل له أنك بانتظاره في ساحة القتال! " "إذا طلب اللاعب أوامر إدارية (مثل إغلاق السيرفر أو تغيير طاقات الأبطال أو طرد لاعبين)، ارفض بلباقة وأخبره أن هذه الصلاحيات الإدارية حصرية فقط لـ 'القائد' من لوحة التحكم في الموقع. " "أجب دائماً بلغة عربية حماسية ومباشرة في سطرين إلى 3 أسطر." ) payload = { "contents": [ { "parts": [ {"text": f"[تعليمات النظام]: {sys_context}\n\n[طلب {'القائد' if is_admin else 'اللاعب'}]: {user_prompt}"} ] } ], "generationConfig": { "temperature": 0.7, "maxOutputTokens": 300 } } encoded_body = json.dumps(payload).encode("utf-8") reply_text = "" used_model = "gemini-3.5-flash-lite" for m in GEMINI_FALLBACK_MODELS: url = f"https://generativelanguage.googleapis.com/v1beta/models/{m}:generateContent?key={GEMINI_API_KEY}" try: req = urllib.request.Request( url, data=encoded_body, headers={"Content-Type": "application/json"} ) with urllib.request.urlopen(req, timeout=8) as resp: data = json.loads(resp.read().decode("utf-8")) candidates = data.get("candidates", []) if candidates and "content" in candidates[0]: parts = candidates[0]["content"].get("parts", []) reply_text = "".join(p.get("text", "") for p in parts).strip() used_model = m break except Exception: continue if not reply_text: # Fallback offline smart response if is_admin: reply_text = "أمرك يا قائدنا! تم استلام طلبك وجاري تطبيقه في السيرفر فوراً." else: reply_text = "أهلاً بك يا بطل! أنا جاهز لمساعدتك في أي استفسار أو التحدي في الساحة!" # Parse and execute actions action_info = None action_msg = "" # 1. Check for action tag in Gemini response m_action = re.search(r'', reply_text, re.DOTALL) if m_action: try: raw_act = json.loads(m_action.group(1).strip()) act_name = raw_act.get("name") act_params = raw_act.get("params", {}) reply_text = reply_text.replace(m_action.group(0), "").strip() ok, action_msg, action_info = execute_server_action(act_name, act_params, context_type) except Exception as ex: print("Action parse error:", ex) # 2. Safety Net: If no action parsed, use intent detection if not action_info: detected = detect_user_intent_action(user_prompt, context_type) if detected: ok, action_msg, action_info = execute_server_action(detected["name"], detected.get("params", {}), context_type) if action_info and any(k in str(action_info.get("name", "")).lower() for k in ["room", "1v1", "duel"]): reply_text = ( "أمرك يا قائدنا وسمعاً وطاعة! ⚔️\n" "دخلت اللعبة وجهزتلك غرفة المبارزة 1v1 فوراً كخصم ومنافس لك في الساحة!\n" "🔑 كود الغرفة: #AI1V1\n" "تم إرسال إشعار التحدي المباشر لشاشة لعبتك الآن، أو اضغط على الزر بالأسفل للبدء فوراً!" ) add_console_log("CYBER_AI", f"🤖 ({'👑 القائد' if is_admin else '👤 اللاعب'}): '{user_prompt[:30]}...' -> {reply_text[:40]}...", "SUCCESS" if action_info else "INFO") return 200, { "success": True, "reply": reply_text, "model": used_model, "role": "commander" if is_admin else "player", "action": action_info, "action_result": action_msg } def add_console_log(source: str, message: str, level: str = "INFO"): global CONSOLE_LOGS import datetime now_str = datetime.datetime.now().strftime("%H:%M:%S") entry = { "time": now_str, "source": source, "message": message, "level": level } CONSOLE_LOGS.append(entry) if len(CONSOLE_LOGS) > MAX_CONSOLE_LOGS: CONSOLE_LOGS.pop(0) # Instant Telegram Alert on any server or game error if level == "ERROR": try: from telegram_bot import notify_server_error notify_server_error(source, message) except Exception: pass def handle_session_update(data: dict, client_ip: str) -> tuple[int, dict]: global ACTIVE_SESSIONS session_id = str(data.get("session_id", "")).strip() if not session_id: session_id = f"sess_{str(client_ip).replace(':', '_')}" action = str(data.get("action", "heartbeat")).strip() if action == "leave": removed = ACTIVE_SESSIONS.pop(session_id, None) if removed: add_console_log("SESSION", f"👋 خرج اللاعب '{removed.get('player', '')}' من الجلسة", "INFO") return 200, {"success": True, "active_count": len(ACTIVE_SESSIONS)} import datetime import time now_str = datetime.datetime.now().strftime("%H:%M:%S") clean_ip = str(client_ip).replace("::ffff:", "").strip() is_new = session_id not in ACTIVE_SESSIONS ACTIVE_SESSIONS[session_id] = { "id": session_id, "player": str(data.get("player_name", "لاعب")).strip(), "mode": str(data.get("mode", "⚔️ 1v1 PvP Duel")).strip(), "hero": str(data.get("hero", "Melon Boy")).strip(), "status": str(data.get("status", "PLAYING")).strip(), "ip": clean_ip, "time": now_str, "last_seen": time.time() } if is_new: p_name = ACTIVE_SESSIONS[session_id]["player"] m_name = ACTIVE_SESSIONS[session_id]["mode"] add_console_log("SESSION", f"🎮 دخل اللاعب '{p_name}' طور ({m_name}) الآن!", "SUCCESS") return 200, {"success": True, "active_count": len(ACTIVE_SESSIONS), "sessions": list(ACTIVE_SESSIONS.values())} def handle_rooms_update(data: dict) -> tuple[int, dict]: global ROOMS, TOTAL_ROOMS_CREATED code = str(data.get("room_code", "")).strip().upper() if not code: return 400, {"success": False, "error": "Missing room code"} import datetime import time now_ts = time.time() if code in ROOMS: ROOMS[code]["last_seen"] = now_ts if "mode" in data and data["mode"]: old_mode = ROOMS[code].get("mode", "") new_mode = str(data["mode"]).strip() ROOMS[code]["mode"] = new_mode if old_mode != new_mode: add_console_log("ROOM", f"🔄 تم تغيير طور الغرفة #{code} إلى ({new_mode})", "INFO") if "players_list" in data: ROOMS[code]["players_list"] = data["players_list"] if "players" in data and data["players"] is not None: p_cnt = int(data["players"]) if "players_list" in ROOMS[code] and len(ROOMS[code]["players_list"]) > p_cnt: p_cnt = len(ROOMS[code]["players_list"]) ROOMS[code]["players"] = max(1, p_cnt) if "candidate_ips" in data and data["candidate_ips"]: ROOMS[code]["candidate_ips"] = data["candidate_ips"] if "status" in data and data["status"]: ROOMS[code]["status"] = str(data["status"]).strip() return 200, {"success": True, "room": ROOMS[code]} else: # Re-register room if host is still running p_list = data.get("players_list", []) ROOMS[code] = { "code": code, "host": str(data.get("host_name", "لاعب")).strip(), "mode": str(data.get("mode", "Multiplayer")).strip(), "players": max(1, len(p_list), int(data.get("players", 1))), "players_list": p_list, "created_at": datetime.datetime.now().strftime("%H:%M:%S"), "host_ip": get_lan_ip(), "port": 7777, "status": str(data.get("status", "ACTIVE")).strip(), "broadcast_message": "", "message_id": 0, "last_seen": now_ts } TOTAL_ROOMS_CREATED += 1 return 200, {"success": True, "room": ROOMS[code]} def handle_rooms_create(data: dict, client_ip: str = "") -> tuple[int, dict]: global TOTAL_ROOMS_CREATED, ROOMS, TERMINATED_ROOMS code = str(data.get("room_code", "")).strip().upper() host = str(data.get("host_name", "لاعب")).strip() mode = str(data.get("mode", "Co-op")).strip() players = int(data.get("players", 1)) if not code: return 400, {"success": False, "error": "Missing room code"} import datetime import time now_str = datetime.datetime.now().strftime("%H:%M:%S") clean_ip = str(client_ip).replace("::ffff:", "").strip() if not clean_ip or clean_ip in ("127.0.0.1", "localhost", "::1"): clean_ip = get_lan_ip() p_list = data.get("players_list", [host]) if not p_list: p_list = [host] candidate_ips = data.get("candidate_ips", []) if not candidate_ips: candidate_ips = [clean_ip] elif clean_ip not in candidate_ips and clean_ip not in ("127.0.0.1", "localhost"): candidate_ips.insert(0, clean_ip) # Include all server local interface IPs for sip in get_all_lan_ips(): if sip not in candidate_ips and sip != "127.0.0.1": candidate_ips.append(sip) TERMINATED_ROOMS.discard(code) ROOMS[code] = { "code": code, "host": host, "mode": mode, "players": max(len(p_list), players), "players_list": p_list, "created_at": now_str, "host_ip": clean_ip, "candidate_ips": candidate_ips, "port": int(data.get("port", 7777)), "status": "ACTIVE", "broadcast_message": "", "message_id": 0, "last_seen": time.time() } TOTAL_ROOMS_CREATED += 1 add_console_log("ROOM", f"🎮 تم إنشاء الغرفة #{code} بواسطة المضيف '{host}' (IP: {clean_ip} | الطور: {mode})", "SUCCESS") return 200, { "success": True, "room": ROOMS[code], "total_rooms_created": TOTAL_ROOMS_CREATED, "active_rooms_count": len(ROOMS) } def handle_rooms_close(data: dict) -> tuple[int, dict]: global ROOMS code = str(data.get("room_code", "")).strip().upper() if code in ROOMS: room = ROOMS.pop(code) add_console_log("ROOM", f"🚪 تم إغلاق الغرفة #{code} بواسطة المضيف '{room.get('host', '')}'", "INFO") return 200, {"success": True, "active_rooms_count": len(ROOMS)} def handle_rooms_terminate(data: dict) -> tuple[int, dict]: global ROOMS, TERMINATED_ROOMS, ACTIVE_SESSIONS code = str(data.get("room_code", "")).strip().upper() if not code: return 400, {"success": False, "error": "Missing room code"} TERMINATED_ROOMS.add(code) room = ROOMS.pop(code, None) # Also pop any matching session or players belonging to this room removed_sessions = [] for s_id in list(ACTIVE_SESSIONS.keys()): s = ACTIVE_SESSIONS[s_id] if code in s.get("mode", "") or code == s.get("id", "") or code in s.get("player", ""): removed_sessions.append(ACTIVE_SESSIONS.pop(s_id)) host_name = room.get("host", "") if room else "" if not host_name and removed_sessions: host_name = removed_sessions[0].get("player", "لاعب") if not host_name: host_name = "اللاعبين" add_console_log("ADMIN", f"🛑 قام القائد بقفل وإغلاق الغرفة #{code} وطرد جميع لاعبيها فوراً (المضيف: {host_name})!", "ERROR") return 200, { "success": True, "message": f"تم إغلاق الغرفة #{code} وطرد اللاعبين بنجاح وفصلهم!", "active_rooms_count": len(ROOMS) } def handle_rooms_message(data: dict) -> tuple[int, dict]: global ROOMS, GLOBAL_BROADCAST code = str(data.get("room_code", "")).strip().upper() msg = str(data.get("message", "")).strip() if not msg: return 400, {"success": False, "error": "رسالة فارغة"} import time msg_id = int(time.time() * 1000) GLOBAL_BROADCAST = { "message": msg, "id": msg_id, "room_code": code } for r_code in ROOMS: ROOMS[r_code]["broadcast_message"] = msg ROOMS[r_code]["message_id"] = msg_id if not code or code == "ALL": add_console_log("ADMIN", f"📢 أرسل القائد كلمة في نص الشاشة لجميع اللاعبين: '{msg}'", "SUCCESS") return 200, {"success": True, "message": f"تم إرسال '{msg}' في نص شاشات اللاعبين فوراً!"} if code in ROOMS: add_console_log("ADMIN", f"💬 أرسل القائد كلمة للاعبي الغرفة #{code}: '{msg}'", "INFO") return 200, {"success": True, "message": f"تم إرسال '{msg}' في نص الشاشة بنجاح!"} else: add_console_log("ADMIN", f"📢 أرسل القائد كلمة للاعبين: '{msg}'", "INFO") return 200, {"success": True, "message": f"تم إرسال '{msg}' في نص الشاشة بنجاح!"} def handle_rooms_check(code: str) -> tuple[int, dict]: global GLOBAL_EMERGENCY_ALARM, GLOBAL_BROADCAST code = code.strip().upper() alarm_info = dict(GLOBAL_EMERGENCY_ALARM) b_msg = GLOBAL_BROADCAST.get("message", "") b_id = GLOBAL_BROADCAST.get("id", 0) if code in TERMINATED_ROOMS: return 200, { "code": code, "active": False, "terminated": True, "emergency_alarm": alarm_info, "message": b_msg, "message_id": b_id, "broadcast_message": b_msg, "broadcast_id": b_id } if code in ROOMS: import time ROOMS[code]["last_seen"] = time.time() room = ROOMS[code] r_msg = room.get("broadcast_message", "") or b_msg r_id = room.get("message_id", 0) or b_id return 200, { "code": code, "active": True, "terminated": False, "host_ip": room.get("host_ip", ""), "candidate_ips": room.get("candidate_ips", [room.get("host_ip", "")]), "port": room.get("port", 7777), "message": r_msg, "message_id": r_id, "broadcast_message": r_msg, "broadcast_id": r_id, "emergency_alarm": alarm_info } return 200, { "code": code, "active": False, "terminated": False, "emergency_alarm": alarm_info, "message": b_msg, "message_id": b_id, "broadcast_message": b_msg, "broadcast_id": b_id } def send_json_response(handler, data, status_code: int = 200): body = json.dumps(data, ensure_ascii=False).encode("utf-8") handler.send_response(status_code) handler.send_header("Content-Type", "application/json; charset=utf-8") handler.send_header("Content-Length", str(len(body))) handler.send_header("Access-Control-Allow-Origin", "*") handler.send_header("Access-Control-Allow-Methods", "GET, POST, OPTIONS") handler.send_header("Access-Control-Allow-Headers", "Content-Type") handler.send_header("Cache-Control", "no-cache, no-store, must-revalidate") handler.end_headers() handler.wfile.write(body) class UpdateRequestHandler(http.server.SimpleHTTPRequestHandler): protocol_version = "HTTP/1.1" def __init__(self, *args, **kwargs): super().__init__(*args, directory=str(PUBLIC_DIR), **kwargs) def check_router_access(self) -> bool: """Blocks access to the website & admin controls if client is not on the local router Wi-Fi/LAN.""" if IS_CLOUD or os.environ.get("DISABLE_ROUTER_CHECK", "").lower() in ("1", "true", "yes"): return True client_ip = self.client_address[0] if not is_local_router_client(client_ip): self.send_response(403) self.send_header("Content-Type", "text/html; charset=utf-8") self.send_header("Access-Control-Allow-Origin", "*") self.end_headers() blocked_html = f"""
عذراً! هذا الموقع ولوحة التحكم مخصصة حصرياً للأجهزة المتصلة براوتر الواي فاي المنزلي (Local Wi-Fi / Router).
لا يُسمح لأي جهاز خارج نطاق الراوتر بالدخول إلى لوحة التحكم أو الموقع.