Created
June 29, 2026 15:59
-
-
Save EncodeTheCode/0d73e061520e00d7d2d010be8ffcb7a7 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import asyncio | |
| import json | |
| import time | |
| # ========================= | |
| # CONFIG | |
| # ========================= | |
| HOST = "0.0.0.0" | |
| PORT = 4445 | |
| TICK_RATE = 20 | |
| PING_INTERVAL = 1.0 | |
| MAX_PACKET_SIZE = 1200 | |
| MAX_PLAYERS = 2000 | |
| # ========================= | |
| # PLAYER STORAGE | |
| # ========================= | |
| players = {} | |
| # ========================= | |
| # CREATE NEW PLAYER | |
| # ========================= | |
| def create_player(addr): | |
| return { | |
| # identity | |
| "addr": str(addr), | |
| # position (3D) | |
| "x": 0.0, | |
| "y": 0.0, | |
| "z": 0.0, | |
| # previous position (for smoothing/interpolation) | |
| "px": 0.0, | |
| "py": 0.0, | |
| "pz": 0.0, | |
| # stats | |
| "health": 100, | |
| "armor": 0, | |
| # weapon system | |
| "weapon_id": 0, | |
| "primary_ammo": 30, | |
| "secondary_ammo": 90, | |
| # movement state | |
| "walking": False, | |
| "running": False, | |
| # networking | |
| "last_seen": time.time(), | |
| "ping": 0.0 | |
| } | |
| # ========================= | |
| # SAFE PARSE | |
| # ========================= | |
| def parse(data): | |
| if len(data) > MAX_PACKET_SIZE: | |
| return None | |
| try: | |
| return json.loads(data) | |
| except: | |
| return None | |
| # ========================= | |
| # APPLY CLIENT DATA | |
| # ========================= | |
| def update_player(addr, msg): | |
| if addr not in players: | |
| players[addr] = create_player(addr) | |
| p = players[addr] | |
| p["last_seen"] = time.time() | |
| msg_type = msg.get("type") | |
| # --------------------- | |
| # POSITION UPDATE | |
| # --------------------- | |
| if msg_type == "update": | |
| # store previous position (for interpolation) | |
| p["px"], p["py"], p["pz"] = p["x"], p["y"], p["z"] | |
| # apply movement | |
| p["x"] += float(msg.get("dx", 0)) | |
| p["y"] += float(msg.get("dy", 0)) | |
| p["z"] += float(msg.get("dz", 0)) | |
| # movement states | |
| p["walking"] = bool(msg.get("walking", False)) | |
| p["running"] = bool(msg.get("running", False)) | |
| # --------------------- | |
| # COMBAT UPDATE | |
| # --------------------- | |
| elif msg_type == "combat": | |
| p["weapon_id"] = int(msg.get("weapon_id", p["weapon_id"])) | |
| p["primary_ammo"] = int(msg.get("primary_ammo", p["primary_ammo"])) | |
| p["secondary_ammo"] = int(msg.get("secondary_ammo", p["secondary_ammo"])) | |
| # --------------------- | |
| # DAMAGE SYSTEM | |
| # --------------------- | |
| elif msg_type == "damage": | |
| dmg = int(msg.get("amount", 0)) | |
| # armor absorbs first | |
| absorbed = min(p["armor"], dmg) | |
| p["armor"] -= absorbed | |
| dmg -= absorbed | |
| p["health"] -= dmg | |
| if p["health"] < 0: | |
| p["health"] = 0 | |
| # --------------------- | |
| # PING SYSTEM | |
| # --------------------- | |
| elif msg_type == "ping": | |
| client_time = float(msg.get("t", time.time())) | |
| p["ping"] = time.time() - client_time | |
| # ========================= | |
| # BUILD WORLD SNAPSHOT | |
| # ========================= | |
| def build_world(): | |
| world = {} | |
| for addr, p in players.items(): | |
| world[str(addr)] = { | |
| # position | |
| "x": p["x"], | |
| "y": p["y"], | |
| "z": p["z"], | |
| # interpolation helper | |
| "px": p["px"], | |
| "py": p["py"], | |
| "pz": p["pz"], | |
| # stats | |
| "health": p["health"], | |
| "armor": p["armor"], | |
| # weapons | |
| "weapon_id": p["weapon_id"], | |
| "primary_ammo": p["primary_ammo"], | |
| "secondary_ammo": p["secondary_ammo"], | |
| # movement | |
| "walking": p["walking"], | |
| "running": p["running"], | |
| # ping (updated every second) | |
| "ping": round(p["ping"], 3) | |
| } | |
| return { | |
| "type": "world", | |
| "players": world | |
| } | |
| # ========================= | |
| # UDP SERVER | |
| # ========================= | |
| class GameServer(asyncio.DatagramProtocol): | |
| def connection_made(self, transport): | |
| self.transport = transport | |
| def datagram_received(self, data, addr): | |
| msg = parse(data) | |
| if not msg: | |
| return | |
| if len(players) < MAX_PLAYERS: | |
| update_player(addr, msg) | |
| # ========================= | |
| # BROADCAST LOOP | |
| # ========================= | |
| async def broadcast(server): | |
| interval = 1.0 / TICK_RATE | |
| while True: | |
| start = time.time() | |
| world = build_world() | |
| packet = json.dumps(world).encode() | |
| dead = [] | |
| for addr in players: | |
| try: | |
| server.transport.sendto(packet, addr) | |
| except: | |
| dead.append(addr) | |
| for d in dead: | |
| players.pop(d, None) | |
| elapsed = time.time() - start | |
| await asyncio.sleep(max(0, interval - elapsed)) | |
| # ========================= | |
| # PING UPDATE LOOP (every 1 second) | |
| # ========================= | |
| async def ping_loop(): | |
| while True: | |
| now = time.time() | |
| for p in players.values(): | |
| # simple timeout detection | |
| if now - p["last_seen"] > 5: | |
| p["health"] = max(0, p["health"] - 1) | |
| await asyncio.sleep(PING_INTERVAL) | |
| # ========================= | |
| # START SERVER | |
| # ========================= | |
| async def main(): | |
| loop = asyncio.get_running_loop() | |
| transport, server = await loop.create_datagram_endpoint( | |
| GameServer, | |
| local_addr=(HOST, PORT) | |
| ) | |
| print(f"Game server running on {HOST}:{PORT}") | |
| await asyncio.gather( | |
| broadcast(server), | |
| ping_loop() | |
| ) | |
| asyncio.run(main()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment