Compare commits

...

8 Commits

Author SHA1 Message Date
4974d48411 0.2.2 -> 0.2.3 2023-07-16 03:07:47 +03:00
3b7842aa50 Update modules version 2023-07-16 03:06:38 +03:00
db6eb361b8 0.2.2 -> 0.2.3 2023-07-16 03:06:22 +03:00
479525a66e Remove nick, roles from protected;
Change _tcp_send -> _send;
Now _send data may be str;
Rewrite to_all handler;
Add chat handler;
2023-07-16 02:55:09 +03:00
6d4bc1e72c Minor update 2023-07-16 02:52:20 +03:00
9b3677de46 Minor update 2023-07-16 02:52:15 +03:00
58137752c5 Add commands plugins, pl 2023-07-16 02:50:25 +03:00
220c6068e4 Minor update 2023-07-16 02:49:58 +03:00
14 changed files with 126 additions and 83 deletions

View File

@ -1,3 +1,9 @@
# Developed by KuiToi Dev
# File core.tcp_server.py
# Written by: SantaSpeen
# Core version: 0.2.3
# Licence: FPA
# (c) kuitoi.su 2023
import asyncio import asyncio
import math import math
import zlib import zlib
@ -18,12 +24,16 @@ class Client:
self._addr = writer.get_extra_info("sockname") self._addr = writer.get_extra_info("sockname")
self._cid = -1 self._cid = -1
self._key = None self._key = None
self._nick = None self.nick = None
self._roles = None self.roles = None
self._guest = True self._guest = True
self._ready = False self._ready = False
self._cars = [] self._cars = []
@property
def _writer(self):
return self.__writer
@property @property
def log(self): def log(self):
return self._log return self._log
@ -40,14 +50,6 @@ class Client:
def key(self): def key(self):
return self._key return self._key
@property
def nick(self):
return self._nick
@property
def roles(self):
return self._roles
@property @property
def guest(self): def guest(self):
return self._guest return self._guest
@ -79,14 +81,14 @@ class Client:
async def kick(self, reason): async def kick(self, reason):
if not self.__alive: if not self.__alive:
self.log.debug(f"Kick({reason}) skipped;") self.log.debug(f"{self.nick}.kick('{reason}') skipped: Not alive;")
return return
# TODO: i18n # TODO: i18n
self.log.info(f"Kicked with reason: \"{reason}\"") self.log.info(f"Kicked with reason: \"{reason}\"")
await self._tcp_send(b"K" + bytes(reason, "utf-8")) await self._send(b"K" + bytes(reason, "utf-8"))
self.__alive = False self.__alive = False
async def _tcp_send(self, data, to_all=False, to_self=True, to_udp=False, writer=None): async def _send(self, data, to_all=False, to_self=True, to_udp=False, writer=None):
# TNetwork.cpp; Line: 383 # TNetwork.cpp; Line: 383
# BeamMP TCP protocol sends a header of 4 bytes, followed by the data. # BeamMP TCP protocol sends a header of 4 bytes, followed by the data.
@ -94,23 +96,26 @@ class Client:
# ^------^^---...-^ # ^------^^---...-^
# size data # size data
if type(data) == str:
data = bytes(data, "utf-8")
if writer is None: if writer is None:
writer = self.__writer writer = self.__writer
if to_all: if to_all:
code = data[:1] code = chr(data[0])
for client in self.__Core.clients: for client in self.__Core.clients:
if not client or (client == self and not to_self): if not client or (client is self and not to_self):
continue continue
if not to_udp or code in [b'W', b'Y', b'V', b'E']: if not to_udp or code in ['V', 'W', 'Y', 'E']:
if code in [b'O', b'T'] or len(data) > 1000: if code in ['O', 'T'] or len(data) > 1000:
# TODO: Compress data # TODO: Compress data
await client._tcp_send(data) await client._send(data)
else: else:
await client._tcp_send(data) await client._send(data)
else: else:
# TODO: UDP send # TODO: UDP send
pass self.log.debug(f"UDP Part not ready: {code}")
return return
header = len(data).to_bytes(4, "little", signed=True) header = len(data).to_bytes(4, "little", signed=True)
@ -198,10 +203,10 @@ class Client:
break break
self.log.debug(f"Mode size: {size}") self.log.debug(f"Mode size: {size}")
if size == -1: if size == -1:
await self._tcp_send(b"CO") await self._send(b"CO")
await self.kick(f"Not allowed mod: " + file) await self.kick(f"Not allowed mod: " + file)
return return
await self._tcp_send(b"AG") await self._send(b"AG")
t = 0 t = 0
while not self._down_rw[0]: while not self._down_rw[0]:
await asyncio.sleep(0.1) await asyncio.sleep(0.1)
@ -236,42 +241,40 @@ class Client:
mod_list = path_list + size_list mod_list = path_list + size_list
self.log.debug(f"Mods List: {mod_list}") self.log.debug(f"Mods List: {mod_list}")
if len(mod_list) == 0: if len(mod_list) == 0:
await self._tcp_send(b"-") await self._send(b"-")
else: else:
await self._tcp_send(bytes(mod_list, "utf-8")) await self._send(bytes(mod_list, "utf-8"))
elif data == b"Done": elif data == b"Done":
await self._tcp_send(b"M/levels/" + bytes(config.Game['map'], 'utf-8') + b"/info.json") await self._send(b"M/levels/" + bytes(config.Game['map'], 'utf-8') + b"/info.json")
break break
return return
async def _looper(self): async def _looper(self):
await self._tcp_send(b"P" + bytes(f"{self.cid}", "utf-8")) # Send clientID await self._send(b"P" + bytes(f"{self.cid}", "utf-8")) # Send clientID
await self._sync_resources() await self._sync_resources()
# TODO: GlobalParser
while self.__alive: while self.__alive:
data = await self._recv() data = await self._recv()
if not data: if not data:
self.__alive = False self.__alive = False
break break
# V to Y
if 89 >= data[0] >= 86: if 89 >= data[0] >= 86:
# TODO: Network.SendToAll await self._send(data, to_all=True, to_self=False)
pass
code = data.decode()[0] code = chr(data[0])
self.log.debug(f"Received code: {code}, data: {data}") self.log.debug(f"Received code: {code}, data: {data}")
match code: match code:
case "H": case "H":
# Client connected # Client connected
ev.call_event("player_join", player=self)
await ev.call_async_event("player_join", player=self)
await self._send(f"Sn{self.nick}", to_all=True) # I don't know for what it
await self._send(f"JWelcome {self.nick}!", to_all=True) # Hello message
self._ready = True self._ready = True
ev.call_event("player_join", self)
await ev.call_async_event("player_join", self)
bnick = bytes(self.nick, "utf-8")
await self._tcp_send(b"Sn" + bnick, to_all=True) # I don't know for what it
await self._tcp_send(b"JWelcome" + bnick + b"!", to_all=True) # Hello message
# TODO: Sync cars # TODO: Sync cars
# for client in self.__Core.clients: # for client in self.__Core.clients:
# for car in client.cars: # for car in client.cars:
@ -279,17 +282,40 @@ class Client:
case "C": case "C":
# Chat # Chat
msg = data[2:].decode() msg = data.decode()[4 + len(self.nick):]
if not msg: if not msg:
self.log.debug("Tried to send an empty event, ignoring") self.log.debug("Tried to send an empty event, ignoring")
continue continue
self.log.info(f"Received message: {msg}") self.log.info(f"Received message: {msg}")
# TODO: Handle chat event # TODO: Handle chat event
ev_data = ev.call_event("chat_receive", msg) to_ev = {"message": msg, "player": self}
d2 = await ev.call_async_event("chat_receive", msg) ev_data_list = ev.call_event("chat_receive", **to_ev)
ev_data.extend(d2) d2 = await ev.call_async_event("chat_receive", **to_ev)
self.log.info(f"TODO: Handle chat event; {ev_data}") ev_data_list.extend(d2)
await self._tcp_send(data, to_all=True) need_send = True
for ev_data in ev_data_list:
try:
message = ev_data["message"]
to_all = ev_data.get("to_all")
if to_all is None:
if need_send:
need_send = False
to_all = True
if to_all:
if need_send:
need_send = False
to_self = ev_data.get("to_self")
if to_self is None:
to_self = True
to_client = ev_data.get("to_client")
writer = None
if to_client:
writer = to_client._writer
await self._send(f"C:{message}", to_all=to_all, to_self=to_self, writer=writer)
except KeyError | AttributeError:
self.log.error(f"Returns invalid data: {ev_data}")
if need_send:
await self._send(data, to_all=True)
case "O": case "O":
# TODO: ParseVehicle # TODO: ParseVehicle

View File

@ -1,5 +1,12 @@
# Developed by KuiToi Dev
# File core.tcp_server.py
# Written by: SantaSpeen
# Core version: 0.2.3
# Licence: FPA
# (c) kuitoi.su 2023
import asyncio import asyncio
from asyncio import StreamReader, StreamWriter from asyncio import StreamReader, StreamWriter
from logging import Logger
from typing import Tuple from typing import Tuple
from core import Core, utils from core import Core, utils
@ -17,38 +24,28 @@ class Client:
self.__Core = core self.__Core = core
self._cid: int = -1 self._cid: int = -1
self._key: str = None self._key: str = None
self._nick: str = None self.nick: str = None
self._roles: str = None self.roles: str = None
self._guest = True self._guest = True
self.__alive = True self.__alive = True
self._ready = False self._ready = False
@property @property
def log(self): def _writer(self) -> StreamWriter: ...
return self._log
@property @property
def addr(self): def log(self) -> Logger: ...
return self._addr
@property @property
def cid(self): def addr(self) -> Tuple[str, int]: ...
return self._cid
@property @property
def key(self): def cid(self) -> int: ...
return self._key
@property @property
def nick(self): def key(self) -> str: ...
return self._nick
@property @property
def roles(self): def guest(self) -> bool: ...
return self._roles
@property @property
def guest(self): def ready(self) -> bool: ...
return self._guest
@property
def ready(self):
return self._ready
def is_disconnected(self) -> bool: ... def is_disconnected(self) -> bool: ...
async def kick(self, reason: str) -> None: ... async def kick(self, reason: str) -> None: ...
async def _tcp_send(self, data: bytes, to_all: bool = False, to_self: bool = True, to_udp: bool = False, writer: StreamWriter = None) -> None: ... async def _send(self, data: bytes | str, to_all: bool = False, to_self: bool = True, to_udp: bool = False, writer: StreamWriter = None) -> None: ...
async def _sync_resources(self) -> None: ... async def _sync_resources(self) -> None: ...
async def _recv(self) -> bytes: ... async def _recv(self) -> bytes: ...
async def _split_load(self, start: int, end: int, d_sock: bool, filename: str) -> None: ... async def _split_load(self, start: int, end: int, d_sock: bool, filename: str) -> None: ...

View File

@ -2,7 +2,7 @@
# File core.__init__.py # File core.__init__.py
# Written by: SantaSpeen # Written by: SantaSpeen
# Version 1.3 # Version 1.3
# Core version: 0.2.2 # Core version: 0.2.3
# Licence: FPA # Licence: FPA
# (c) kuitoi.su 2023 # (c) kuitoi.su 2023
# Special thanks to: AI Sage(https://poe.com/Sage), AI falcon-40b-v7(https://OpenBuddy.ai) # Special thanks to: AI Sage(https://poe.com/Sage), AI falcon-40b-v7(https://OpenBuddy.ai)
@ -10,8 +10,8 @@
__title__ = 'KuiToi-Server' __title__ = 'KuiToi-Server'
__description__ = 'BeamingDrive Multiplayer server compatible with BeamMP clients.' __description__ = 'BeamingDrive Multiplayer server compatible with BeamMP clients.'
__url__ = 'https://github.com/kuitoi/kuitoi-Server' __url__ = 'https://github.com/kuitoi/kuitoi-Server'
__version__ = '0.2.2' __version__ = '0.2.3'
__build__ = 1176 # Я это считаю лог файлами __build__ = 1208 # Я это считаю лог файлами
__author__ = 'SantaSpeen' __author__ = 'SantaSpeen'
__author_email__ = 'admin@kuitoi.su' __author_email__ = 'admin@kuitoi.su'
__license__ = "FPA" __license__ = "FPA"

View File

@ -1,7 +1,7 @@
# Developed by KuiToi Dev # Developed by KuiToi Dev
# File core.core.py # File core.core.py
# Written by: SantaSpeen # Written by: SantaSpeen
# Version: 0.2.2 # Version: 0.2.3
# Licence: FPA # Licence: FPA
# (c) kuitoi.su 2023 # (c) kuitoi.su 2023
import asyncio import asyncio
@ -104,7 +104,7 @@ class Core:
if not client.ready: if not client.ready:
client.is_disconnected() client.is_disconnected()
continue continue
await client._tcp_send(bytes(ca, "utf-8")) await client._send(bytes(ca, "utf-8"))
@staticmethod @staticmethod
def start_web(): def start_web():

View File

@ -1,7 +1,7 @@
# Developed by KuiToi Dev # Developed by KuiToi Dev
# File core.core.pyi # File core.core.pyi
# Written by: SantaSpeen # Written by: SantaSpeen
# Version 0.2.2 # Version 0.2.3
# Licence: FPA # Licence: FPA
# (c) kuitoi.su 2023 # (c) kuitoi.su 2023
import asyncio import asyncio

View File

@ -1,7 +1,7 @@
# Developed by KuiToi Dev # Developed by KuiToi Dev
# File core.tcp_server.py # File core.tcp_server.py
# Written by: SantaSpeen # Written by: SantaSpeen
# Core version: 0.2.2 # Core version: 0.2.3
# Licence: FPA # Licence: FPA
# (c) kuitoi.su 2023 # (c) kuitoi.su 2023
import asyncio import asyncio
@ -32,7 +32,7 @@ class TCPServer:
await client.kick("Outdated Version.") await client.kick("Outdated Version.")
return False, client return False, client
else: else:
await client._tcp_send(b"S") # Accepted client version await client._send(b"S") # Accepted client version
data = await client._recv() data = await client._recv()
self.log.debug(f"Key: {data}") self.log.debug(f"Key: {data}")
@ -41,7 +41,7 @@ class TCPServer:
await client.kick("Invalid Key (too long)!") await client.kick("Invalid Key (too long)!")
return False, client return False, client
client._key = data.decode("utf-8") client._key = data.decode("utf-8")
ev.call_event("auth_sent_key", client) ev.call_event("auth_sent_key", player=client)
try: try:
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
url = 'https://auth.beammp.com/pkToUser' url = 'https://auth.beammp.com/pkToUser'
@ -71,7 +71,7 @@ class TCPServer:
await client.kick('Stale Client (replaced by new client)') await client.kick('Stale Client (replaced by new client)')
return False, client return False, client
ev.call_event("auth_ok", client) ev.call_event("auth_ok", player=client)
if len(self.Core.clients_by_id) > config.Game["players"]: if len(self.Core.clients_by_id) > config.Game["players"]:
# TODO: i18n # TODO: i18n

View File

@ -1,7 +1,7 @@
# Developed by KuiToi Dev # Developed by KuiToi Dev
# File core.tcp_server.pyi # File core.tcp_server.pyi
# Written by: SantaSpeen # Written by: SantaSpeen
# Core version: 0.2.2 # Core version: 0.2.3
# Licence: FPA # Licence: FPA
# (c) kuitoi.su 2023 # (c) kuitoi.su 2023
import asyncio import asyncio
@ -9,7 +9,7 @@ from asyncio import StreamWriter, StreamReader
from typing import Tuple from typing import Tuple
from core import utils, Core from core import utils, Core
from core.core import Client from core.Client import Client
class TCPServer: class TCPServer:

View File

@ -1,7 +1,7 @@
# Developed by KuiToi Dev # Developed by KuiToi Dev
# File core.udp_server.py # File core.udp_server.py
# Written by: SantaSpeen # Written by: SantaSpeen
# Core version: 0.2.2 # Core version: 0.2.3
# Licence: FPA # Licence: FPA
# (c) kuitoi.su 2023 # (c) kuitoi.su 2023
import asyncio import asyncio

View File

@ -1,7 +1,7 @@
# Developed by KuiToi Dev # Developed by KuiToi Dev
# File core.udp_server.py # File core.udp_server.py
# Written by: SantaSpeen # Written by: SantaSpeen
# Core version: 0.2.2 # Core version: 0.2.3
# Licence: FPA # Licence: FPA
# (c) kuitoi.su 2023 # (c) kuitoi.su 2023
import asyncio import asyncio

View File

@ -2,7 +2,7 @@
# File core.utils.py # File core.utils.py
# Written by: SantaSpeen # Written by: SantaSpeen
# Version 1.1 # Version 1.1
# Core version: 0.2.2 # Core version: 0.2.3
# Licence: FPA # Licence: FPA
# (c) kuitoi.su 2023 # (c) kuitoi.su 2023
import datetime import datetime

View File

@ -1,9 +1,9 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Developed by KuiToi Dev # Developed by KuiToi Dev
# File core.config_provider.py # File modules.ConsoleSystem.console_system.py
# Written by: SantaSpeen # Written by: SantaSpeen
# Version 1.1 # Version 1.2
# Licence: FPA # Licence: FPA
# (c) kuitoi.su 2023 # (c) kuitoi.su 2023
import builtins import builtins
@ -87,7 +87,7 @@ class Console:
print() print()
raw = True raw = True
message = str() message = "\n"
max_len = self.__get_max_len(self.__func.keys()) max_len = self.__get_max_len(self.__func.keys())
if max_len < 7: if max_len < 7:
max_len = 7 max_len = 7

View File

@ -1,7 +1,14 @@
# -*- coding: utf-8 -*-
# Developed by KuiToi Dev
# File modules.EventsSystem.events_system.py
# Written by: SantaSpeen
# Version 1.0
# Licence: FPA
# (c) kuitoi.su 2023
import asyncio import asyncio
import builtins import builtins
import inspect import inspect
import time
from core import get_logger from core import get_logger

View File

@ -1,3 +1,11 @@
# -*- coding: utf-8 -*-
# Developed by KuiToi Dev
# File modules.PluginsLoader.plugins_loader.py
# Written by: SantaSpeen
# Version 1.0
# Licence: FPA
# (c) kuitoi.su 2023
import asyncio import asyncio
import inspect import inspect
import os import os
@ -72,8 +80,11 @@ class PluginsLoader:
self.plugins_tasks = [] self.plugins_tasks = []
self.plugins_dir = plugins_dir self.plugins_dir = plugins_dir
self.log = get_logger("PluginsLoader") self.log = get_logger("PluginsLoader")
self.loaded_str = "Plugins: "
ev.register_event("_plugins_start", self.start) ev.register_event("_plugins_start", self.start)
ev.register_event("_plugins_unload", self.unload) ev.register_event("_plugins_unload", self.unload)
console.add_command("plugins", lambda x: self.loaded_str[:-2])
console.add_command("pl", lambda x: self.loaded_str[:-2])
async def load(self): async def load(self):
self.log.debug("Loading plugins...") self.log.debug("Loading plugins...")
@ -147,9 +158,11 @@ class PluginsLoader:
th = Thread(target=plugin.load, name=f"{pl_name}.load()") th = Thread(target=plugin.load, name=f"{pl_name}.load()")
th.start() th.start()
th.join() th.join()
self.loaded_str += f"{pl_name}:ok, "
self.log.debug(f"Plugin loaded: {file}. Settings: {self.plugins[pl_name]}") self.log.debug(f"Plugin loaded: {file}. Settings: {self.plugins[pl_name]}")
except Exception as e: except Exception as e:
# TODO: i18n # TODO: i18n
self.loaded_str += f"{file}:no, "
self.log.error(f"Error while loading plugin: {file}; Error: {e}") self.log.error(f"Error while loading plugin: {file}; Error: {e}")
self.log.exception(e) self.log.exception(e)

View File

@ -3,7 +3,7 @@
# Developed by KuiToi Dev # Developed by KuiToi Dev
# File modules.i18n.i18n.py # File modules.i18n.i18n.py
# Written by: SantaSpeen # Written by: SantaSpeen
# Version 1.0 # Version 1.3
# Licence: FPA # Licence: FPA
# (c) kuitoi.su 2023 # (c) kuitoi.su 2023
import builtins import builtins