mirror of
https://github.com/kuitoi/kuitoi-Server.git
synced 2026-04-24 00:56:36 +00:00
Compare commits
10 Commits
0.4.6-beta
...
0.4.7-beta
| Author | SHA1 | Date | |
|---|---|---|---|
| b2a608d369 | |||
| c12a91bf86 | |||
| 209004c9cb | |||
| 2af4681082 | |||
| f1f80cc94c | |||
| 06942e8a71 | |||
| 51867d526d | |||
| ff58e2a994 | |||
| 4c6a240f96 | |||
| 666a76201e |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -142,4 +142,5 @@ logs/
|
||||
*.toml
|
||||
|
||||
/win-ver_info.txt
|
||||
/output/
|
||||
/output/
|
||||
pip-packets/
|
||||
|
||||
@@ -130,7 +130,7 @@ class Client:
|
||||
if not message:
|
||||
message = "no message"
|
||||
to_all = False
|
||||
await self._send(f"C:{message!r}", to_all=to_all)
|
||||
await self._send(f"C:{message}", to_all=to_all)
|
||||
|
||||
async def send_event(self, event_name, event_data, to_all=True):
|
||||
if isinstance(event_data, (list, tuple, dict)):
|
||||
@@ -504,10 +504,10 @@ class Client:
|
||||
pass
|
||||
|
||||
if cid == self.cid or allow or admin_allow:
|
||||
if car['snowman']:
|
||||
if car['unicycle']:
|
||||
unicycle_id = self._unicycle['id']
|
||||
self._unicycle['id'] = -1
|
||||
self.log.debug(f"Delete snowman")
|
||||
self.log.debug(f"Delete unicycle")
|
||||
await self._send(f"Od:{self.cid}-{unicycle_id}", to_all=True, to_self=True)
|
||||
self._cars[unicycle_id] = None
|
||||
else:
|
||||
@@ -521,10 +521,11 @@ class Client:
|
||||
self.log.debug(f"Invalid car: car_id={car_id}")
|
||||
|
||||
async def reset_car(self, car_id, x, y, z, rot=None):
|
||||
# TODO: reset_car
|
||||
self.log.debug(f"Resetting car from plugin")
|
||||
if rot is None:
|
||||
rot = {"y": 0, "w": 0, "x": 0, "z": 0}
|
||||
self.log.debug(f"Resetting car from plugin {x, y, z}; {rot=}")
|
||||
jpkt = {"pos": {"y": float(y), "x": float(x), "z": float(z)}, "rot": {"y": 0, "w": 0, "x": 0, "z": 0}}
|
||||
if rot:
|
||||
jpkt['rot'] = rot
|
||||
await self._send(f"Or:{self.cid}-{car_id}:{json.dumps(jpkt)}", True)
|
||||
|
||||
async def _reset_car(self, raw_data):
|
||||
cid, car_id = self._get_cid_vid(raw_data)
|
||||
@@ -545,6 +546,7 @@ class Client:
|
||||
async def _handle_car_codes(self, raw_data):
|
||||
if len(raw_data) < 6:
|
||||
return
|
||||
self.log.debug(f"[car] {raw_data}")
|
||||
sub_code = raw_data[1]
|
||||
data = raw_data[3:]
|
||||
match sub_code:
|
||||
@@ -602,6 +604,8 @@ class Client:
|
||||
|
||||
self.log.info(i18n.client_sync_time.format(round(time.monotonic() - self._connect_time, 2)))
|
||||
self._ready = True
|
||||
ev.call_event("onPlayerReady", player=self)
|
||||
await ev.call_async_event("onPlayerReady", player=self)
|
||||
|
||||
async def _chat_handler(self, data):
|
||||
sup = data.find(":", 2)
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
__title__ = 'KuiToi-Server'
|
||||
__description__ = 'BeamingDrive Multiplayer server compatible with BeamMP clients.'
|
||||
__url__ = 'https://github.com/kuitoi/kuitoi-Server'
|
||||
__version__ = '0.4.6'
|
||||
__build__ = 2421 # Я это считаю лог файлами
|
||||
__version__ = '0.4.7'
|
||||
__build__ = 2469 # Я это считаю лог файлами
|
||||
__author__ = 'SantaSpeen'
|
||||
__author_email__ = 'admin@kuitoi.su'
|
||||
__license__ = "FPA"
|
||||
|
||||
@@ -54,7 +54,7 @@ class Core:
|
||||
ev.register("_get_player", lambda x: self.get_client(**x['kwargs']))
|
||||
|
||||
def get_client(self, cid=None, nick=None):
|
||||
if cid is None and nick is None:
|
||||
if (cid, nick) == (None, None):
|
||||
return None
|
||||
if cid is not None:
|
||||
if cid == -1:
|
||||
@@ -160,11 +160,16 @@ class Core:
|
||||
BEAM_backend = ["backend.beammp.com", "backup1.beammp.com", "backup2.beammp.com"]
|
||||
_map = config.Game['map'] if "/" in config.Game['map'] else f"/levels/{config.Game['map']}/info.json"
|
||||
tags = config.Server['tags'].replace(", ", ";").replace(",", ";")
|
||||
self.log.debug(f"[heartbeat] {_map=}")
|
||||
self.log.debug(f"[heartbeat] {tags=}")
|
||||
if tags and tags[-1:] != ";":
|
||||
tags += ";"
|
||||
modlist = "".join(f"/{os.path.basename(mod['path'])};" for mod in self.mods_list[1:])
|
||||
modstotalsize = self.mods_list[0]
|
||||
modstotal = len(self.mods_list) - 1
|
||||
self.log.debug(f"[heartbeat] {modlist=}")
|
||||
self.log.debug(f"[heartbeat] {modstotalsize=}")
|
||||
self.log.debug(f"[heartbeat] {modstotal=}")
|
||||
while self.run:
|
||||
playerslist = "".join(f"{client.nick};" for client in self.clients if client and client.alive)
|
||||
data = {
|
||||
|
||||
@@ -35,12 +35,11 @@ class TCPServer:
|
||||
await client.kick(i18n.core_player_kick_outdated)
|
||||
return False, client
|
||||
else:
|
||||
# await client._send(b"S") # Accepted client version
|
||||
await client._send(b"A") # Accepted client version
|
||||
|
||||
data = await client._recv(True)
|
||||
self.log.debug(f"Key: {data}")
|
||||
if len(data) > 50:
|
||||
if not data or len(data) > 50:
|
||||
await client.kick(i18n.core_player_kick_bad_key)
|
||||
return False, client
|
||||
client._key = data.decode("utf-8")
|
||||
@@ -89,6 +88,10 @@ class TCPServer:
|
||||
return False, client
|
||||
|
||||
ev.call_event("onPlayerAuthenticated", player=client)
|
||||
await ev.call_async_event("onPlayerAuthenticated", player=client)
|
||||
if not client.alive:
|
||||
await client.kick("Not accepted.")
|
||||
return False, client
|
||||
|
||||
if len(self.Core.clients_by_id) > config.Game["players"]:
|
||||
await client.kick(i18n.core_player_kick_server_full)
|
||||
|
||||
@@ -36,7 +36,7 @@ class UDPServer(asyncio.DatagramTransport):
|
||||
client = self._core.get_client(cid=cid)
|
||||
if client:
|
||||
if not client.alive:
|
||||
self.log.debug(f"{client.nick}:{cid} still sending UDP data: {data}")
|
||||
client.log.debug(f"Still sending UDP data: {data}")
|
||||
match code:
|
||||
case "p": # Ping packet
|
||||
ev.call_event("onSentPing")
|
||||
@@ -45,7 +45,6 @@ class UDPServer(asyncio.DatagramTransport):
|
||||
if client._udp_sock != (self.transport, addr):
|
||||
client._udp_sock = (self.transport, addr)
|
||||
self.log.debug(f"Set UDP Sock for CID: {cid}")
|
||||
ev.call_event("onChangePosition", data=data)
|
||||
sub = data.find("{", 1)
|
||||
last_pos = data[sub:]
|
||||
try:
|
||||
@@ -54,6 +53,7 @@ class UDPServer(asyncio.DatagramTransport):
|
||||
last_pos = json.loads(last_pos)
|
||||
client._last_position = last_pos
|
||||
client._cars[car_id]['pos'] = last_pos
|
||||
ev.call_event("onChangePosition", data, player=client, pos=last_pos)
|
||||
except Exception as e:
|
||||
self.log.warning(f"Cannot parse position packet: {e}")
|
||||
self.log.debug(f"data: '{data}', sup: {sub}")
|
||||
@@ -62,7 +62,7 @@ class UDPServer(asyncio.DatagramTransport):
|
||||
case "X":
|
||||
await client._send(data, to_all=True, to_self=False, to_udp=True)
|
||||
case _:
|
||||
self.log.warning(f" UDP [{cid}] Unknown code: {code}; {data}")
|
||||
self.log.warning(f"UDP [{cid}] Unknown code: {code}; {data}")
|
||||
else:
|
||||
self.log.debug(f"[{cid}] Client not found.")
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ class EventsSystem:
|
||||
"onPlayerSentKey": [], # Only sync, no handler
|
||||
"onPlayerAuthenticated": [], # (!) Only sync, With handler
|
||||
"onPlayerJoin": [], # (!) With handler
|
||||
"onPlayerReady": [], # No handler
|
||||
"onChatReceive": [], # (!) With handler
|
||||
"onCarSpawn": [], # (!) With handler
|
||||
"onCarDelete": [], # (!) With handler (admin allow)
|
||||
@@ -41,6 +42,7 @@ class EventsSystem:
|
||||
self.__async_events = {
|
||||
"onServerStarted": [],
|
||||
"onPlayerJoin": [],
|
||||
"onPlayerReady": [],
|
||||
"onChatReceive": [],
|
||||
"onCarSpawn": [],
|
||||
"onCarDelete": [],
|
||||
|
||||
@@ -9,8 +9,11 @@
|
||||
import asyncio
|
||||
import inspect
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import types
|
||||
from contextlib import contextmanager
|
||||
from pathlib import Path
|
||||
from threading import Thread
|
||||
|
||||
from core import get_logger
|
||||
@@ -24,8 +27,8 @@ class KuiToi:
|
||||
raise AttributeError("KuiToi: Name is required")
|
||||
self.__log = get_logger(f"Plugin | {name}")
|
||||
self.__name = name
|
||||
self.__dir = os.path.join(self._plugins_dir, self.__name)
|
||||
if not os.path.exists(self.__dir):
|
||||
self.__dir = Path(self._plugins_dir) / self.__name
|
||||
if not self.__dir.exists():
|
||||
os.mkdir(self.__dir)
|
||||
|
||||
@property
|
||||
@@ -42,7 +45,9 @@ class KuiToi:
|
||||
|
||||
@contextmanager
|
||||
def open(self, file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None):
|
||||
path = os.path.join(self.__dir, file)
|
||||
path = self.__dir / file
|
||||
if str(self.__dir) in str(file):
|
||||
path = file
|
||||
self.log.debug(f'Trying to open "{path}" with mode "{mode}"')
|
||||
# Really need?
|
||||
# if not os.path.exists(path):
|
||||
@@ -97,6 +102,7 @@ class KuiToi:
|
||||
|
||||
|
||||
class PluginsLoader:
|
||||
_pip_dir = str(Path("pip-packets").resolve())
|
||||
|
||||
def __init__(self, plugins_dir):
|
||||
self.loop = asyncio.get_event_loop()
|
||||
@@ -110,6 +116,21 @@ class PluginsLoader:
|
||||
ev.register("_plugins_get", lambda x: list(self.plugins.keys()))
|
||||
console.add_command("plugins", lambda x: self.loaded_str[:-2])
|
||||
console.add_command("pl", lambda x: self.loaded_str[:-2])
|
||||
sys.path.append(self._pip_dir)
|
||||
os.makedirs(self._pip_dir, exist_ok=True)
|
||||
console.add_command("install", self._pip_install)
|
||||
|
||||
def _pip_install(self, x):
|
||||
self.log.debug(f"_pip_install {x}")
|
||||
if len(x) > 0:
|
||||
try:
|
||||
subprocess.check_call(['pip', 'install', *x, '--target', self._pip_dir])
|
||||
return "Success"
|
||||
except subprocess.CalledProcessError as e:
|
||||
self.log.debug(f"error: {e}")
|
||||
return f"Failed to install packages"
|
||||
else:
|
||||
return "Invalid syntax"
|
||||
|
||||
async def load(self):
|
||||
self.log.debug("Loading plugins...")
|
||||
|
||||
Reference in New Issue
Block a user