Compare commits

..

No commits in common. "9b005529124c8751cf6b8b2cc966594abfd1cf88" and "a057004cd2aac9e59ae2ad5a097afaf15e801418" have entirely different histories.

30 changed files with 119 additions and 609 deletions

View File

@ -7,17 +7,14 @@ BeamingDrive Multiplayer (BeamMP) server compatible with BeamMP clients.
## TODOs ## TODOs
- [ ] Server core - [ ] Server core
- [ ] BEAMP System
- [x] Private access without key
- [ ] Server authentication (For public access)
- [X] Player authentication
- [ ] TCP Server part: - [ ] TCP Server part:
- [x] Handle code - [x] Handle code
- [x] Understanding beamp header - [x] Understanding beamp header
- [X] Authorization
- [ ] Upload mods - [ ] Upload mods
- [x] Connecting to the world - [x] Connecting to the world
- [x] Chat - [x] Chat
- [ ] "ABG:" (compressed data) - [ ] ABG: (compressed data)
- [x] Decompress data - [x] Decompress data
- [ ] Vehicle data - [ ] Vehicle data
- [ ] Players synchronizations - [ ] Players synchronizations
@ -29,12 +26,10 @@ BeamingDrive Multiplayer (BeamMP) server compatible with BeamMP clients.
- [x] Events System - [x] Events System
- [x] Plugins support - [x] Plugins support
- [x] MultiLanguage (i18n support) - [x] MultiLanguage (i18n support)
- [ ] HTTP REST API Server
- [ ] Console: - [ ] Console:
- [x] Tabulation - [x] Tabulation
- [ ] _(Deferred)_ Normal text scroll - [ ] _(Deferred)_ Normal text scroll
- [x] MultiLanguage (i18n support) - [x] [Documentation](docs/readme.md)
- [ ] [Documentation](docs/en/readme.md)
## Installation ## Installation

View File

@ -1,45 +0,0 @@
{
"": "Basic phases",
"hello": "Hello from KuiToi-Server!",
"config_path": "Use {} for config.",
"init_ok": "Initializing ready.",
"start": "Server started!",
"stop": "Goodbye!",
"": "Server auth",
"auth_need_key": "BEAM key needed for starting the server!",
"auth_empty_key": "Key is empty!",
"auth_cannot_open_browser": "Cannot open browser: {}",
"auth_use_link": "Use this link: {}",
"": "GUI phases",
"GUI_yes": "Yes",
"GUI_no": "No",
"GUI_ok": "Ok",
"GUI_cancel": "Cancel",
"GUI_need_key_message": "BEAM key needed for starting the server!\nDo you need to open the web link to obtain the key?",
"GUI_enter_key_message": "Please type your key:",
"GUI_cannot_open_browser": "Cannot open browser.\nUse this link: {}",
"": "Command: man",
"man_message_man": "man - display the manual page for COMMAND.\nUsage: man COMMAND",
"help_message_man": "Display the manual page for COMMAND.",
"man_for": "Manual for command",
"man_message_not_found": "man: Manual message not found.",
"man_command_not_found": "man: command \"{}\" not found!",
"": "Command: help",
"man_message_help": "help - display names and brief descriptions of available commands.\nUsage: help [--raw]\nThe `help` command displays a list of all available commands along with a brief description of each command.",
"help_message_help": "Display names and brief descriptions of available commands",
"help_command": "Command",
"help_message": "Help message",
"help_message_not_found": "No help message found",
"": "Command: stop",
"man_message_stop": "stop - Just shutting down the server.\nUsage: stop",
"help_message_stop": "Server shutdown.",
"": "Command: exit",
"man_message_exit": "exit - Just shutting down the server.\nUsage: stop",
"help_message_exit": "Server shutdown."
}

View File

@ -1,36 +0,0 @@
import KuiToi # Import server object
beam = KuiToi("TestPlugin") # Init plugin with name "TestPlugin"
log = beam.log # Use logger from server
def on_load():
# When plugin initialization Server uses plugin.load() to load plugin.
# def load(): is really needed
log.info(beam.name)
# Events handlers
def on_started():
# Simple event handler
log.info("Server starting...")
# Simple event register
beam.register_event("on_started", on_started)
def any_func(data=None):
# Custom event handler
log.info(f"Data from any_func: {data}")
# Create custom event
beam.register_event("my_event", any_func)
# Call custom event
beam.call_event("my_event")
beam.call_event("my_event", "Some data")
# This will be an error since any_func accepts only one argument at the input
beam.call_event("my_event", "Some data", "Some data1")

View File

@ -1,9 +0,0 @@
# Documentation for KuiToi Server
#### The documentation has not been perfected yet, but one day it will definitely happen
1. Setup and Start server - [here](setup)
2. Plugins and Events system - [here](plugins)
3. MultiLanguage - [here](./multilanguage)
4. RESP API - [here](./web)
5. Something new

View File

@ -1,3 +0,0 @@
# Web RESP API for the Server
In development...

View File

@ -1,6 +1,6 @@
import KuiToi # Import server object import BEAMP # Import server object
beam = KuiToi("TestPlugin") # Init plugin with name "TestPlugin" beam = BEAMP("TestPlugin") # Init plugin with name "TestPlugin"
log = beam.log # Use logger from server log = beam.log # Use logger from server

View File

@ -1,19 +1,20 @@
# Plugins System # Plugins System
## Install ## Install
###### (Lib can't ready to use)
[//]: # (TODO: BEAM LIB)
Lib can't ready to use
* From pip:\ * From pip:\
`$ pip install KuiToi` `$ pip install ...`
* From source:\ * From source:\
`git clone https://github.com/KuiToi/KuiToi-PyLib` `git clone https://github.com/kuitoi/...`
## Example ## Example
```python ```python
import KuiToi import BEAMP
beam = KuiToi("TestPlugin") beam = BEAMP("TestPlugin")
logger = beam.log logger = beam.log
def load(): # Plugins load from here def load(): # Plugins load from here

View File

@ -1,4 +1,5 @@
# Choose your language # Documentation for KuiToi Server
### [English](./en) 1. Setup and Start server - [here](./setup)
### [Русский](./ru) 2. Plugins and Events system - [here](./plugins)
3. Something new

View File

@ -1,45 +0,0 @@
{
"": "Basic phases",
"hello": "Привет из KuiToi-Server!",
"config_path": "Используя {} для настройки.",
"init_ok": "Инициализация окончена.",
"start": "Сервер запущен!",
"stop": "Сервер остановлен!",
"": "Server auth",
"auth_need_key": "Нужен BEAMP ключ для запуска!",
"auth_empty_key": "BEAMP ключ пустой!",
"auth_cannot_open_browser": "Не получилось открыть браузер: {}",
"auth_use_link": "Используй эту ссылку: {}",
"": "GUI phases",
"GUI_yes": "Да",
"GUI_no": "Нет",
"GUI_ok": "Окей",
"GUI_cancel": "Отмена",
"GUI_need_key_message": "Нужен BEAMP ключ для запуска!\nХотите открыть ссылку в браузере для получения ключа?",
"GUI_enter_key_message": "Пожалуйста введите ключ:",
"GUI_cannot_open_browser": "Не получилось открыть браузер.\nИспользуй эту ссылку: {}",
"": "Command: man",
"man_message_man": "man - Показывает страничку помощи для COMMAND.\nИспользование: man COMMAND",
"help_message_man": "Показывает страничку помощи для COMMAND.",
"man_for": "Страничка помощи для",
"man_message_not_found": "man: Страничка помощи не найдена.",
"man_command_not_found": "man: Команда \"{}\" не найдена!",
"": "Command: help",
"man_message_help": "help - Показывает названия и краткое описание команд.\nИспользование: help [--raw]\nКоманда `help` выводит список всех доступных команд, и краткое описание для каждой команды.",
"help_message_help": "Показывает названия и краткое описание команд",
"help_command": "Команда",
"help_message": "Текст",
"help_message_not_found": "Нет текста",
"": "Command: stop",
"man_message_stop": "stop - Выключает сервер.\nИспользование: stop",
"help_message_stop": "Выключает сервер.",
"": "Command: exit",
"man_message_exit": "exit - Выключает сервер.\nИспользование: exit",
"help_message_exit": "Выключает сервер."
}

View File

@ -1,35 +0,0 @@
# Система плагинов
## Установка библиотеки с "Заглушками"
###### (Это значит, что не будет работать без сервера, но IDE подскажет API)
###### (Библиотека ещё в разработке)
* Используя pip:\
`$ pip install KuiToi`
* Из исходников:\
`git clone https://github.com/KuiToi/KuiToi-PyLib`
## Пример
```python
import KuiToi
beam = KuiToi("TestPlugin")
logger = beam.log
def load(): # Plugins load from here
print(beam.name)
def on_started():
logger.info("Server starting...")
beam.register_event("on_started", on_started)
```
Так же более обширный пример можно найти в [example.py](./example.py)
* Базовые ивенты: ['on_started', 'on_auth, 'on_stop']
* Создание своего ивента : `beam.register_event("my_event", my_event_function)`
* Вызов ивента: `beam.call_event("my_event")`
* Вызов ивента с данными: `beam.call_event("my_event", data, data2)`
* Вызовы с указанием переменой _**не поддерживаются**_: `beam.call_event("my_event", data=data)`

View File

@ -1,9 +0,0 @@
# Документация для KuiToi Server
### Документация ещё не доведена до совершенства, но однажды обязательно это случится
1. Настройка и Запуск сервера - [тута](./setup)
2. Плагины и Ивент система - [тута](./plugins)
3. Мультиязычность - [тута](./multilanguage)
4. RESP API - [тута](./web)
5. Тут будет что-то ново....

View File

@ -1,49 +0,0 @@
# Привет из KuiToi Server
## Что ж, начнём
###### _(Тут команды для linux)_
* Для запуска необходим **Python 3.10.x**! Именно этот, на Python 3.11 не запустится...
* Проверить версию твоего питончика(здесь надо смеяться) можно вот так:
```bash
python3 --version # Python 3.10.6
```
* Клонируем репозиторий и переходим в него
* Устанавливаем всё необходимое
* Далее, используя мой "скриптик" удаляем всё лишнее и перемещаемся к исходникам ядра
```bash
git clone -b Stable https://github.com/kuitoi/KuiToi-Server.git && cd KuiToi-Server
pip install -r requirements.txt
mv ./src/ $HOME/ktsrc/ && rm -rf ./* && mv $HOME/ktsrc/* . && rm -rf $HOME/ktsrc
```
* Вот так можно глянуть инфу о сервер и запустить его:)
```bash
python3 main.py --help # Покажет все доступные команды
python3 main.py # Запустит сервер
```
## Настройка
* После запуска создастся `kuitoi.yaml`
* По умолчанию он выглядит вот так:
```yaml
!!python/object:modules.ConfigProvider.config_provider.Config
Auth:
key: null
private: true
Game:
map: gridmap_v2
max_cars: 1
players: 8
Server:
debug: false
description: This server uses KuiToi!
name: KuiToi-Server
server_ip: 0.0.0.0
server_port: 30814
```
* Если поставить `private: false` и не установить `key`, то сервер запросит BEAMP ключ, без него не запустится.
* Введя BEAMP ключ сервер появится в списке лаунчера.
* Взять ключ можно тут: [https://beammp.com/k/keys](https://beammp.com/k/keys)

View File

@ -1,3 +0,0 @@
# Web RESP API для сервера
В разработке

View File

@ -1,7 +1,7 @@
# Developed by KuiToi Dev # Developed by KuiToi Dev
# File core.__init__.py # File core.__init__.py
# Written by: SantaSpeen # Written by: SantaSpeen
# Version 1.2 # Version 1.1
# 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)
@ -9,8 +9,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.1.6' __version__ = '0.1.5'
__build__ = 458 __build__ = 411
__author__ = 'SantaSpeen' __author__ = 'SantaSpeen'
__author_email__ = 'admin@kuitoi.su' __author_email__ = 'admin@kuitoi.su'
__license__ = "FPA" __license__ = "FPA"
@ -28,7 +28,7 @@ import builtins
import os import os
import webbrowser import webbrowser
import prompt_toolkit.shortcuts as shortcuts from prompt_toolkit.shortcuts import input_dialog, yes_no_dialog
from .utils import get_logger from .utils import get_logger
from modules import ConfigProvider, EventsSystem, PluginsLoader from modules import ConfigProvider, EventsSystem, PluginsLoader
@ -46,57 +46,42 @@ if args.config:
config_path = args.config config_path = args.config
config_provider = ConfigProvider(config_path) config_provider = ConfigProvider(config_path)
config = config_provider.open_config() config = config_provider.open_config()
log.info("Use %s for config." % config_path)
if config.Server['debug'] is True: if config.Server['debug'] is True:
utils.set_debug_status() utils.set_debug_status()
log.info("Debug enabled!") log.info("Getting new logging with DEBUG level!")
log = get_logger("init") log = get_logger("init")
log.debug("Debug mode enabled!") log.debug("Debug mode enabled!")
log.debug(f"Server config: {config}") log.debug("Use %s for config." % config)
# i18n init # i18n init
log.debug("Initializing i18n...") log.debug("Initializing i18n...")
ml = MultiLanguage() ml = MultiLanguage()
ml.set_language(args.language or config.Server['language']) ml.set_language(args.language)
ml.builtins_hook() ml.builtins_hook()
log.debug("Initializing EventsSystem...") log.info(i18n.hello)
ev = EventsSystem() ev = EventsSystem()
ev.builtins_hook() ev.builtins_hook()
log.info(i18n.hello)
log.info(i18n.config_path.format(config_path))
log.debug("Initializing BEAMP Server system...")
# Key handler.. # Key handler..
private = ((config.Auth['key'] is None or config.Auth['key'] == "") and config.Auth['private']) if not config.Auth['key']:
if not private: log.warn("Key needed for starting the server!")
log.warn(i18n.auth_need_key)
url = "https://beammp.com/k/keys" url = "https://beammp.com/k/keys"
if shortcuts.yes_no_dialog( if yes_no_dialog(
title='BEAMP Server Key', title='BEAMP Server Key',
text=i18n.GUI_need_key_message, text='Key needed for starting the server!\n'
yes_text=i18n.GUI_yes, 'Do you need to open the web link to obtain the key?').run():
no_text=i18n.GUI_no).run(): webbrowser.open(url, new=2)
try:
log.debug("Opening browser...")
webbrowser.open(url, new=2)
except Exception as e:
log.error(i18n.auth_cannot_open_browser.format(e))
log.info(i18n.auth_use_link.format(url))
shortcuts.message_dialog(
title='BEAMP Server Key',
text=i18n.GUI_cannot_open_browser.format(url),
ok_text=i18n.GUI_ok).run()
config.Auth['key'] = shortcuts.input_dialog( config.Auth['key'] = input_dialog(
title='BEAMP Server Key', title='BEAMP Server Key',
text=i18n.GUI_enter_key_message, text='Please type your key:').run()
ok_text=i18n.GUI_ok,
cancel_text=i18n.GUI_cancel).run()
config_provider.save_config() config_provider.save_config()
if not private: if not config.Auth['key']:
log.error(i18n.auth_empty_key) log.error("Key is empty!")
log.info(i18n.stop) log.error("Server stopped!")
exit(1) exit(1)
builtins.config = config builtins.config = config
@ -105,16 +90,14 @@ log.debug("Initializing console...")
console = Console() console = Console()
console.builtins_hook() console.builtins_hook()
# console.logger_hook() # console.logger_hook()
console.add_command("stop", console.stop, i18n.man_message_stop, i18n.help_message_stop) console.add_command("stop", console.stop, "stop - Just shutting down the server.\nUsage: stop", "Server shutdown.")
console.add_command("exit", console.stop, i18n.man_message_exit, i18n.help_message_exit) console.add_command("exit", console.stop, "stop - Just shutting down the server.\nUsage: stop", "Server shutdown.")
if not os.path.exists("mods"): if not os.path.exists("mods"):
os.mkdir("mods") os.mkdir("mods")
log.debug("Initializing PluginsLoader...")
if not os.path.exists("plugins"): if not os.path.exists("plugins"):
os.mkdir("plugins") os.mkdir("plugins")
pl = PluginsLoader("plugins") pl = PluginsLoader("plugins")
pl.load_plugins() pl.load_plugins()
@ -124,4 +107,4 @@ builtins.MB = KB * 1024
builtins.GB = MB * 1024 builtins.GB = MB * 1024
builtins.TB = GB * 1024 builtins.TB = GB * 1024
log.info(i18n.init_ok) log.info(i18n.init)

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.1.6 # Version 0.1.5
# Licence: FPA # Licence: FPA
# (c) kuitoi.su 2023 # (c) kuitoi.su 2023
import asyncio import asyncio
@ -14,13 +14,12 @@ from .udp_server import UDPServer
class Client: class Client:
def __init__(self, reader, writer, core): def __init__(self, reader, writer):
self.reader = reader self.reader = reader
self.writer = writer self.writer = writer
self.log = utils.get_logger("client(None:0)") self.log = utils.get_logger("client(None:0)")
self.addr = writer.get_extra_info("sockname") self.addr = writer.get_extra_info("sockname")
self.loop = asyncio.get_event_loop() self.loop = asyncio.get_event_loop()
self.Core = core
self.cid = 0 self.cid = 0
self.key = None self.key = None
self.nick = None self.nick = None
@ -138,11 +137,11 @@ class Core:
def __init__(self): def __init__(self):
self.log = utils.get_logger("core") self.log = utils.get_logger("core")
self.loop = asyncio.get_event_loop()
self.clients = {} self.clients = {}
self.clients_counter = 0 self.clients_counter = 0
self.server_ip = config.Server["server_ip"] self.server_ip = config.Server["server_ip"]
self.server_port = config.Server["server_port"] self.server_port = config.Server["server_port"]
self.loop = asyncio.get_event_loop()
self.tcp = TCPServer self.tcp = TCPServer
self.udp = UDPServer self.udp = UDPServer
@ -153,16 +152,14 @@ class Core:
return self.clients.get(sock.getsockname()) return self.clients.get(sock.getsockname())
def insert_client(self, client): def insert_client(self, client):
self.log.debug(f"Inserting client: {client.cid}")
self.clients.update({client.cid: client, client.nick: client}) self.clients.update({client.cid: client, client.nick: client})
def create_client(self, *args, **kwargs): def create_client(self, *args, **kwargs):
client = Client(*args, **kwargs) cl = Client(*args, **kwargs)
self.clients_counter += 1 self.clients_counter = self.clients_counter + 1
client.id = self.clients_counter cl.id = self.clients_counter
client._update_logger() cl._update_logger()
self.log.debug(f"Create client: {client.cid}; clients_counter: {self.clients_counter}") return cl
return client
async def check_alive(self): async def check_alive(self):
await asyncio.sleep(5) await asyncio.sleep(5)
@ -177,8 +174,7 @@ class Core:
self.udp = self.udp(self, self.server_ip, self.server_port) self.udp = self.udp(self, self.server_ip, self.server_port)
tasks = [self.tcp.start(), self.udp.start(), console.start()] # self.check_alive() tasks = [self.tcp.start(), self.udp.start(), console.start()] # self.check_alive()
t = asyncio.wait(tasks, return_when=asyncio.FIRST_EXCEPTION) t = asyncio.wait(tasks, return_when=asyncio.FIRST_EXCEPTION)
self.log.info(i18n.start) self.log.info(i18n.ready)
# TODO: Server auth
ev.call_event("on_started") ev.call_event("on_started")
await t await t
# while True: # while True:
@ -197,5 +193,5 @@ class Core:
asyncio.run(self.main()) asyncio.run(self.main())
def stop(self): def stop(self):
self.log.info(i18n.stop) self.log.info("Goodbye!")
exit(0) exit(0)

View File

@ -1,26 +1,25 @@
# Developed by KuiToi Dev # Developed by KuiToi Dev
# File core.core.pyi # File core.core.pyi
# Written by: SantaSpeen # Written by: SantaSpeen
# Version 0.1.6 # Version 0.1.2
# Licence: FPA # Licence: FPA
# (c) kuitoi.su 2023 # (c) kuitoi.su 2023
import asyncio import asyncio
from asyncio import StreamWriter, StreamReader import socket
from asyncio import StreamWriter, AbstractEventLoop, StreamReader
from asyncio.trsock import TransportSocket
from core import utils from core import utils
from .tcp_server import TCPServer from .tcp_server import TCPServer
from .udp_server import UDPServer from .udp_server import UDPServer
class Client: class Client:
def __init__(self, reader: StreamReader, writer: StreamWriter, core: Core) -> "Client": def __init__(self, reader: StreamReader, writer: StreamWriter):
self.reader = reader self.reader = reader
self.writer = writer self.writer = writer
self.log = utils.get_logger("client(id: )") self.log = utils.get_logger("client(id: )")
self.addr = writer.get_extra_info("sockname") self.addr = writer.get_extra_info("sockname")
self.loop = asyncio.get_event_loop() self.loop = asyncio.get_event_loop()
self.Core = core
self.cid = 0 self.cid = 0
self.key: str = None self.key: str = None
self.nick: str = None self.nick: str = None
@ -33,7 +32,6 @@ class Client:
async def sync_resources(self) -> None: ... async def sync_resources(self) -> None: ...
async def recv(self) -> bytes: ... async def recv(self) -> bytes: ...
async def last_handle(self) -> bytes: ... async def last_handle(self) -> bytes: ...
def _update_logger(self) -> None: ...
class Core: class Core:

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
# Version 0.1.6 # Version 0.1.2
# 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.pyi # File core.tcp_server.pyi
# Written by: SantaSpeen # Written by: SantaSpeen
# Version 0.1.6 # Version 0.1.2
# 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.utils.py # File core.utils.py
# Written by: SantaSpeen # Written by: SantaSpeen
# Version 0.1.6 # Version 0.1.0
# Licence: FPA # Licence: FPA
# (c) kuitoi.su 2023 # (c) kuitoi.su 2023

View File

@ -12,7 +12,7 @@ import argparse
parser = argparse.ArgumentParser(description='KuiToi-Server - BeamingDrive server compatible with BeamMP clients!') parser = argparse.ArgumentParser(description='KuiToi-Server - BeamingDrive server compatible with BeamMP clients!')
parser.add_argument('-v', '--version', action="store_true", help='Print version and exit.', default=False) parser.add_argument('-v', '--version', action="store_true", help='Print version and exit.', default=False)
parser.add_argument('--config', help='Patch to config file.', nargs='?', default=None, type=str) parser.add_argument('--config', help='Patch to config file.', nargs='?', default=None, type=str)
parser.add_argument('--language', help='Setting localisation.', nargs='?', default=None, type=str) parser.add_argument('--language', help='Setting localisation.', nargs='?', default="en", type=str)
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -7,19 +7,17 @@
# Licence: FPA # Licence: FPA
# (c) kuitoi.su 2023 # (c) kuitoi.su 2023
import os import os
import secrets
import yaml import yaml
class Config: class Config:
def __init__(self, auth=None, game=None, server=None, web=None): def __init__(self, auth=None, game=None, server=None):
self.Auth = auth or {"key": None, "private": True} self.Auth = auth or {"key": None, "private": True}
self.Game = game or {"map": "gridmap_v2", "players": 8, "max_cars": 1} self.Game = game or {"map": "gridmap_v2", "players": 8, "max_cars": 1}
self.Server = server or {"name": "KuiToi-Server", "description": "Welcome to KuiToi Server!", "language": "en", self.Server = server or {"name": "KuiToi-Server",
"server_ip": "0.0.0.0", "server_port": 30814, "debug": False} "description": "This server uses KuiToi!",
# self.WebAPI = web or {"enabled": False, "server_ip": "127.0.0.1", "server_port": 8433, "server_port": 30814, "server_ip": "0.0.0.0", "debug": False}
# "secret_key": secrets.token_hex(16)}
def __repr__(self): def __repr__(self):
return "%s(Auth=%r, Game=%r, Server=%r)" % (self.__class__.__name__, self.Auth, self.Game, self.Server) return "%s(Auth=%r, Game=%r, Server=%r)" % (self.__class__.__name__, self.Auth, self.Game, self.Server)
@ -27,16 +25,16 @@ class Config:
class ConfigProvider: class ConfigProvider:
def __init__(self, config_path): def __init__(self, config_patch):
self.config_path = config_path self.config_patch = config_patch
self.config = Config() self.config = Config()
def open_config(self): def open_config(self):
if not os.path.exists(self.config_path): if not os.path.exists(self.config_patch):
with open(self.config_path, "w", encoding="utf-8") as f: with open(self.config_patch, "w", encoding="utf-8") as f:
yaml.dump(self.config, f) yaml.dump(self.config, f)
try: try:
with open(self.config_path, "r", encoding="utf-8") as f: with open(self.config_patch, "r", encoding="utf-8") as f:
self.config = yaml.load(f.read(), yaml.Loader) self.config = yaml.load(f.read(), yaml.Loader)
except yaml.YAMLError: except yaml.YAMLError:
print("You have errors in the YAML syntax.") print("You have errors in the YAML syntax.")
@ -46,5 +44,5 @@ class ConfigProvider:
return self.config return self.config
def save_config(self): def save_config(self):
with open(self.config_path, "w", encoding="utf-8") as f: with open(self.config_patch, "w", encoding="utf-8") as f:
yaml.dump(self.config, f) yaml.dump(self.config, f)

View File

@ -6,6 +6,7 @@
# Version 1.1 # Version 1.1
# Licence: FPA # Licence: FPA
# (c) kuitoi.su 2023 # (c) kuitoi.su 2023
import asyncio
import builtins import builtins
import logging import logging
from typing import AnyStr from typing import AnyStr
@ -36,9 +37,14 @@ class Console:
self.__man = dict() self.__man = dict()
self.__desc = dict() self.__desc = dict()
self.__print_logger = get_logger("print") self.__print_logger = get_logger("print")
self.add_command("man", self.__create_man_message, i18n.man_message_man, i18n.help_message_man, self.add_command("man", self.__create_man_message, "man - display the manual page.\n"
"Usage: man COMMAND", "Display the manual page",
custom_completer={"man": {}}) custom_completer={"man": {}})
self.add_command("help", self.__create_help_message, i18n.man_message_help, i18n.help_message_help, self.add_command("help", self.__create_help_message,
"help - display names and brief descriptions of available commands.\n"
"Usage: help [--raw]\n"
"The `help` command displays a list of all available commands along with a brief description "
"of each command.", "Display names and brief descriptions of available commands.",
custom_completer={"help": {"--raw": None}}) custom_completer={"help": {"--raw": None}})
self.completer = NestedCompleter.from_nested_dict(self.__alias) self.completer = NestedCompleter.from_nested_dict(self.__alias)
@ -62,19 +68,16 @@ class Console:
return i return i
def __create_man_message(self, argv: list) -> AnyStr: def __create_man_message(self, argv: list) -> AnyStr:
if len(argv) == 0:
return self.__man.get("man")
x = argv[0] x = argv[0]
if self.__alias.get(x) is None: if x in ['']:
return i18n.man_command_not_found.format(x) return "man COMMAND"
man_message = self.__man.get(x) man_message = self.__man.get(x)
if man_message is None:
return "man: Manual message not found."
if man_message: if man_message:
return man_message return man_message
else: return f'man: command "{x}" not found'
return i18n.man_message_not_found
# noinspection PyStringFormat
def __create_help_message(self, argv: list) -> AnyStr: def __create_help_message(self, argv: list) -> AnyStr:
self.__debug("creating help message") self.__debug("creating help message")
raw = False raw = False
@ -92,7 +95,7 @@ class Console:
if raw: if raw:
message += f"%-{max_len}s; %-{max_len_v}s; %s\n" % ("Key", "Function", "Description") message += f"%-{max_len}s; %-{max_len_v}s; %s\n" % ("Key", "Function", "Description")
else: else:
message += f" %-{max_len}s : %s\n" % (i18n.help_command, i18n.help_message) message += f" %-{max_len}s : %s\n" % ("Command", "Help message")
for k, v in self.__func.items(): for k, v in self.__func.items():
doc = self.__desc.get(k) doc = self.__desc.get(k)
@ -102,7 +105,7 @@ class Console:
else: else:
if doc is None: if doc is None:
doc = i18n.help_message_not_found doc = "No help message found"
message += f" %-{max_len}s : %s\n" % (k, doc) message += f" %-{max_len}s : %s\n" % (k, doc)
return message return message
@ -119,7 +122,7 @@ class Console:
self.__alias.update(custom_completer or {key: None}) self.__alias.update(custom_completer or {key: None})
self.__alias["man"].update({key: None}) self.__alias["man"].update({key: None})
self.__func.update({key: {"f": func}}) self.__func.update({key: {"f": func}})
self.__man.update({key: f'html<seagreen>{i18n.man_for} <b>{key}</b>\n{man}</seagreen>' if man else None}) self.__man.update({key: f'html<seagreen>Manual for command <b>{key}</b>\n{man}</seagreen>' if man else None})
self.__desc.update({key: desc}) self.__desc.update({key: desc})
self.__update_completer() self.__update_completer()
return self.__alias.copy() return self.__alias.copy()

View File

@ -4,7 +4,7 @@ import types
from core import get_logger from core import get_logger
class KuiToi: class BEAMP:
def __init__(self, name=None): def __init__(self, name=None):
if name is None: if name is None:
@ -24,6 +24,7 @@ class KuiToi:
ev.call_event(event_name, *data) ev.call_event(event_name, *data)
class PluginsLoader: class PluginsLoader:
def __init__(self, plugins_dir): def __init__(self, plugins_dir):
@ -39,7 +40,7 @@ class PluginsLoader:
try: try:
self.log.debug(f"Loading plugin: {file}") self.log.debug(f"Loading plugin: {file}")
plugin = types.ModuleType('plugin') plugin = types.ModuleType('plugin')
plugin.KuiToi = KuiToi plugin.BEAMP = BEAMP
plugin.print = print plugin.print = print
file = os.path.join(self.__plugins_dir, file) file = os.path.join(self.__plugins_dir, file)
with open(f'{file}', 'r') as f: with open(f'{file}', 'r') as f:

View File

@ -1,45 +1,8 @@
{ {
"": "Basic phases",
"hello": "Hello from KuiToi-Server!", "hello": "Hello from KuiToi-Server!",
"config_path": "Use {} for config.", "config_file": "Use %s for config.",
"init_ok": "Initializing ready.", "debug": "Getting new logging with DEBUG level!",
"start": "Server started!", "config_info": "Server config: %s",
"stop": "Goodbye!", "init": "Initializing ready.",
"ready": "Server started!"
"": "Server auth",
"auth_need_key": "BEAM key needed for starting the server!",
"auth_empty_key": "Key is empty!",
"auth_cannot_open_browser": "Cannot open browser: {}",
"auth_use_link": "Use this link: {}",
"": "GUI phases",
"GUI_yes": "Yes",
"GUI_no": "No",
"GUI_ok": "Ok",
"GUI_cancel": "Cancel",
"GUI_need_key_message": "BEAM key needed for starting the server!\nDo you need to open the web link to obtain the key?",
"GUI_enter_key_message": "Please type your key:",
"GUI_cannot_open_browser": "Cannot open browser.\nUse this link: {}",
"": "Command: man",
"man_message_man": "man - display the manual page for COMMAND.\nUsage: man COMMAND",
"help_message_man": "Display the manual page for COMMAND.",
"man_for": "Manual for command",
"man_message_not_found": "man: Manual message not found.",
"man_command_not_found": "man: command \"{}\" not found!",
"": "Command: help",
"man_message_help": "help - display names and brief descriptions of available commands.\nUsage: help [--raw]\nThe `help` command displays a list of all available commands along with a brief description of each command.",
"help_message_help": "Display names and brief descriptions of available commands",
"help_command": "Command",
"help_message": "Help message",
"help_message_not_found": "No help message found",
"": "Command: stop",
"man_message_stop": "stop - Just shutting down the server.\nUsage: stop",
"help_message_stop": "Server shutdown.",
"": "Command: exit",
"man_message_exit": "exit - Just shutting down the server.\nUsage: stop",
"help_message_exit": "Server shutdown."
} }

View File

@ -1,45 +1,8 @@
{ {
"": "Basic phases",
"hello": "Привет из KuiToi-Server!", "hello": "Привет из KuiToi-Server!",
"config_path": "Используя {} для настройки.", "config_file": "Используй %s для настройки.",
"init_ok": "Инициализация окончена.", "debug": "Начата новая сессия логирования с уровнем DEBUG!",
"start": "Сервер запущен!", "config_info": "Конфиг сервера: %s",
"stop": "Сервер остановлен!", "init": "Инициализация окончена.",
"ready": "Сервер запущен!"
"": "Server auth",
"auth_need_key": "Нужен BEAMP ключ для запуска!",
"auth_empty_key": "BEAMP ключ пустой!",
"auth_cannot_open_browser": "Не получилось открыть браузер: {}",
"auth_use_link": "Используй эту ссылку: {}",
"": "GUI phases",
"GUI_yes": "Да",
"GUI_no": "Нет",
"GUI_ok": "Окей",
"GUI_cancel": "Отмена",
"GUI_need_key_message": "Нужен BEAMP ключ для запуска!\nХотите открыть ссылку в браузере для получения ключа?",
"GUI_enter_key_message": "Пожалуйста введите ключ:",
"GUI_cannot_open_browser": "Не получилось открыть браузер.\nИспользуй эту ссылку: {}",
"": "Command: man",
"man_message_man": "man - Показывает страничку помощи для COMMAND.\nИспользование: man COMMAND",
"help_message_man": "Показывает страничку помощи для COMMAND.",
"man_for": "Страничка помощи для",
"man_message_not_found": "man: Страничка помощи не найдена.",
"man_command_not_found": "man: Команда \"{}\" не найдена!",
"": "Command: help",
"man_message_help": "help - Показывает названия и краткое описание команд.\nИспользование: help [--raw]\nКоманда `help` выводит список всех доступных команд, и краткое описание для каждой команды.",
"help_message_help": "Показывает названия и краткое описание команд",
"help_command": "Команда",
"help_message": "Текст",
"help_message_not_found": "Нет текста",
"": "Command: stop",
"man_message_stop": "stop - Выключает сервер.\nИспользование: stop",
"help_message_stop": "Выключает сервер.",
"": "Command: exit",
"man_message_exit": "exit - Выключает сервер.\nИспользование: exit",
"help_message_exit": "Выключает сервер."
} }

View File

@ -1,90 +1,10 @@
class i18n: class i18n:
# Basic phases hello: str = "Hello from KuiToi-Server!"
hello: str = data["hello"] config_file: str = "Use kuitoi.yml for config."
config_path: str = data["config_path"] debug: str = "Getting new logging with DEBUG level!"
init_ok: str = data["init_ok"] config_info: str = "Server config: %s"
start: str = data["start"] init: str = "Initializing ready."
stop: str = data["stop"] ready: str = "Server started!"
i18n_data = {"hello":"Hello from KuiToi-Server!","config_file":"Use kuitoi.yml for config.",
# Server auth "debug":"Getting new logging with DEBUG level!","config_info":"Server config: %s",
auth_need_key: str = data["auth_need_key"] "init":"Initializing ready.","ready":"Server started!"}
auth_empty_key: str = data["auth_empty_key"]
auth_cannot_open_browser: str = data["auth_cannot_open_browser"]
auth_use_link: str = data["auth_use_link"]
# GUI phases
GUI_yes: str = data["GUI_yes"]
GUI_no: str = data["GUI_no"]
GUI_ok: str = data["GUI_ok"]
GUI_cancel: str = data["GUI_cancel"]
GUI_need_key_message: str = data["GUI_need_key_message"]
GUI_enter_key_message: str = data["GUI_enter_key_message"]
GUI_cannot_open_browser: str = data["GUI_cannot_open_browser"]
# Command: man
man_message_man: str = data["man_message_man"]
help_message_man: str = data["help_message_man"]
man_for: str = data["man_for"]
man_message_not_found: str = data["man_message_not_found"]
man_command_not_found: str = data["man_command_not_found"]
# Command: help
man_message_help: str = data["man_message_help"]
help_message_help: str = data["help_message_help"]
help_command: str = data["help_command"]
help_message: str = data["help_message"]
help_message_not_found: str = data["help_message_not_found"]
# Command: stop
man_message_stop: str = data["man_message_stop"]
help_message_stop: str = data["help_message_stop"]
# Command: exit
man_message_exit: str = data["man_message_exit"]
help_message_exit: str = data["help_message_exit"]
data = {
"": "Basic phases",
"hello": "Hello from KuiToi-Server!",
"config_path": "Use {} for config.",
"init_ok": "Initializing ready.",
"start": "Server started!",
"stop": "Goodbye!",
"": "Server auth",
"auth_need_key": "BEAM key needed for starting the server!",
"auth_empty_key": "Key is empty!",
"auth_cannot_open_browser": "Cannot open browser: {}",
"auth_use_link": "Use this link: {}",
"": "GUI phases",
"GUI_yes": "Yes",
"GUI_no": "No",
"GUI_ok": "Ok",
"GUI_cancel": "Cancel",
"GUI_need_key_message": "BEAM key needed for starting the server!\nDo you need to open the web link to obtain the key?",
"GUI_enter_key_message": "Please type your key:",
"GUI_cannot_open_browser": "Cannot open browser.\nUse this link: {}",
"": "Command: man",
"man_message_man": "man - display the manual page for COMMAND.\nUsage: man COMMAND",
"help_message_man": "Display the manual page for COMMAND.",
"man_for": "Manual for command",
"man_message_not_found": "man: Manual message not found.",
"man_command_not_found": "man: command \"{}\" not found!",
"": "Command: help",
"man_message_help": "help - display names and brief descriptions of available commands.\nUsage: help [--raw]\nThe `help` command displays a list of all available commands along with a brief description of each command.",
"help_message_help": "Display names and brief descriptions of available commands",
"help_command": "Command",
"help_message": "Help message",
"help_message_not_found": "No help message found",
"": "Command: stop",
"man_message_stop": "stop - Just shutting down the server.\nUsage: stop",
"help_message_stop": "Server shutdown.",
"": "Command: exit",
"man_message_exit": "exit - Just shutting down the server.\nUsage: stop",
"help_message_exit": "Server shutdown."
}

View File

@ -16,51 +16,12 @@ from core.utils import get_logger
class i18n: class i18n:
def __init__(self, data): def __init__(self, data):
# Basic phases
self.hello: str = data["hello"] self.hello: str = data["hello"]
self.config_path: str = data["config_path"] self.config_file: str = data["config_file"]
self.init_ok: str = data["init_ok"] self.debug: str = data["debug"]
self.start: str = data["start"] self.config_info: str = data["config_info"]
self.stop: str = data["stop"] self.init: str = data["init"]
self.ready: str = data["ready"]
# Server auth
self.auth_need_key: str = data["auth_need_key"]
self.auth_empty_key: str = data["auth_empty_key"]
self.auth_cannot_open_browser: str = data["auth_cannot_open_browser"]
self.auth_use_link: str = data["auth_use_link"]
# GUI phases
self.GUI_yes: str = data["GUI_yes"]
self.GUI_no: str = data["GUI_no"]
self.GUI_ok: str = data["GUI_ok"]
self.GUI_cancel: str = data["GUI_cancel"]
self.GUI_need_key_message: str = data["GUI_need_key_message"]
self.GUI_enter_key_message: str = data["GUI_enter_key_message"]
self.GUI_cannot_open_browser: str = data["GUI_cannot_open_browser"]
# Command: man
self.man_message_man: str = data["man_message_man"]
self.help_message_man: str = data["help_message_man"]
self.man_for: str = data["man_for"]
self.man_message_not_found: str = data["man_message_not_found"]
self.man_command_not_found: str = data["man_command_not_found"]
# Command: help
self.man_message_help: str = data["man_message_help"]
self.help_message_help: str = data["help_message_help"]
self.help_command: str = data["help_command"]
self.help_message: str = data["help_message"]
self.help_message_not_found: str = data["help_message_not_found"]
# Command: help
self.man_message_stop: str = data["man_message_stop"]
self.help_message_stop: str = data["help_message_stop"]
# Command: exit
self.man_message_exit: str = data["man_message_exit"]
self.help_message_exit: str = data["help_message_exit"]
self.data = data
class MultiLanguage: class MultiLanguage:
@ -78,57 +39,19 @@ class MultiLanguage:
def set_language(self, language): def set_language(self, language):
if language is None: if language is None:
language = "en" return
self.log.debug(f"set_language({language})") self.log.debug(f"set_language({language})")
self.language = language self.language = language
if language != "en": if language != "en":
self.open_file() self.open_file()
else: else:
# noinspection PyDictDuplicateKeys
self.__data = { self.__data = {
"": "Basic phases",
"hello": "Hello from KuiToi-Server!", "hello": "Hello from KuiToi-Server!",
"config_path": "Use {} for config.", "config_file": "Use %s for config.",
"init_ok": "Initializing ready.", "debug": "Getting new logging with DEBUG level!",
"start": "Server started!", "config_info": "Server config: %s",
"stop": "Goodbye!", "init": "Initializing ready.",
"ready": "Server started!"
"": "Server auth",
"auth_need_key": "BEAM key needed for starting the server!",
"auth_empty_key": "Key is empty!",
"auth_cannot_open_browser": "Cannot open browser: {}",
"auth_use_link": "Use this link: {}",
"": "GUI phases",
"GUI_yes": "Yes",
"GUI_no": "No",
"GUI_ok": "Ok",
"GUI_cancel": "Cancel",
"GUI_need_key_message": "BEAM key needed for starting the server!\nDo you need to open the web link to obtain the key?",
"GUI_enter_key_message": "Please type your key:",
"GUI_cannot_open_browser": "Cannot open browser.\nUse this link: {}",
"": "Command: man",
"man_message_man": "man - display the manual page for COMMAND.\nUsage: man COMMAND",
"help_message_man": "Display the manual page for COMMAND.",
"man_for": "Manual for command",
"man_message_not_found": "man: Manual message not found.",
"man_command_not_found": "man: command \"{}\" not found!",
"": "Command: help",
"man_message_help": "help - display names and brief descriptions of available commands.\nUsage: help [--raw]\nThe `help` command displays a list of all available commands along with a brief description of each command.",
"help_message_help": "Display names and brief descriptions of available commands",
"help_command": "Command",
"help_message": "Help message",
"help_message_not_found": "No help message found",
"": "Command: stop",
"man_message_stop": "stop - Just shutting down the server.\nUsage: stop",
"help_message_stop": "Server shutdown.",
"": "Command: exit",
"man_message_exit": "exit - Just shutting down the server.\nUsage: stop",
"help_message_exit": "Server shutdown."
} }
self.__i18n = i18n(self.__data) self.__i18n = i18n(self.__data)
@ -140,8 +63,7 @@ class MultiLanguage:
self.__data.update(json.load(f)) self.__data.update(json.load(f))
return return
except JSONDecodeError: except JSONDecodeError:
self.log.error( self.log.error(f"Localisation \"{self.language}.json\" have JsonDecodeError. Using default localisation: en.")
f"Localisation \"{self.language}.json\" have JsonDecodeError. Using default localisation: en.")
except FileNotFoundError: except FileNotFoundError:
self.log.warning(f"Localisation \"{self.language}.json\" not found; Using default localisation: en.") self.log.warning(f"Localisation \"{self.language}.json\" not found; Using default localisation: en.")
self.set_language("en") self.set_language("en")