Skip to content

Commit 824cf7b

Browse files
committed
Merge branch 'development'
2 parents f21a046 + 240dc98 commit 824cf7b

File tree

219 files changed

+5413
-1843
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

219 files changed

+5413
-1843
lines changed

README.md

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ Discord commands, like the Music service. Some services only run on the master n
4545

4646
| Service | Scope | Plugin | Documentation |
4747
|:------------|:----------------------------------------------------------------------------------------------------------|:------------|:------------------------------------------|
48-
| Backup | Backup your bot- and DCS-configuration, your missions, database, etc. | Backup | [README](./services/backup/README.md) |
48+
| Backup | Backup and restore your bot- and DCS-configuration, your missions, database, etc. | Backup | [README](./services/backup/README.md) |
4949
| Bot | The Discord bot handling all discord commands. There is a Discord-free variant available also (see blow)! | | [README](./services/bot/README.md) |
5050
| Cleanup | Cleanup log-files, track-files, etc. from your disk. | | [README](./services/cleanup/README.md) |
5151
| Cron | Schedule tasks based on a cron-like configuration. | | [README](./services/cron/README.md) |
@@ -73,7 +73,7 @@ from time to time, but you as a community member can also create your own plugin
7373
| Cloud | Cloud-based statistics and connection to the [DGSA](#dgsa) global ban system. | yes[^1] | Userstats | [README](./plugins/cloud/README.md) |
7474
| MissionStats | Detailed users statistics / mission statistics. | yes[^1] | Userstats | [README](./plugins/missionstats/README.md) |
7575
| Monitoring | Monitoring and statistics for your DCS servers. | yes[^1] | Userstats | [README](plugins/monitoring/README.md) |
76-
| Backup | Create a backup of your database, server or bot configurations. | yes | | [README](./plugins/backup/README.md) |
76+
| Backup | Backup or restore your database, server or bot configurations. | yes | | [README](./plugins/backup/README.md) |
7777
| Battleground | Support for [DCS Battleground](https://github.com/Frigondin/DCSBattleground) | yes | | [README](./plugins/battleground/README.md) |
7878
| Battleground2 | Support for the new version of [DCS Battleground](https://github.com/Frigondin/DCSBattleground) | yes | | [README](./plugins/battleground2/README.md) |
7979
| Commands | Create custom discord commands. | yes | | [README](./plugins/commands/README.md) |
@@ -88,6 +88,7 @@ from time to time, but you as a community member can also create your own plugin
8888
| Music | Upload and play music over SRS. | yes | | [README](./plugins/music/README.md) |
8989
| ModManager | Install or update mods into your DCS server. | yes | | [README](./plugins/modmanager/README.md) |
9090
| Pretense | Commands for Pretense missions. | yes | | [README](./plugins/pretense/README.md) |
91+
| Profiler | Attaches LUA profilers to DCS (WIP). | yes | | [README](./plugins/profiler/README.md) |
9192
| Punishment | Punish users for team-hits or team-kills. | yes | Mission | [README](./plugins/punishment/README.md) |
9293
| RealWeather | Apply real weather to your missions (also available as an extension). | yes | | [README](./plugins/realweather/README.md) |
9394
| RestAPI | Simple REST-API to query users and statistics (WIP). | yes | Userstats, MissionStats | [README](./plugins/restapi/README.md) |
@@ -152,8 +153,10 @@ You need the following software to run DCSServerBot:
152153
You need to have [Python](https://www.python.org/downloads/) 3.10 - 3.13 installed.
153154
Please make sure that you tick "Add python.exe to PATH" during your Python installation.
154155

155-
> [!IMPORTANT]
156-
> Python 3.14 does not work yet, despite listed differently in the changelog.
156+
> [!WARNING]
157+
> Pythong 3.14 is still very new and many third-party libraries are either not yet or not fully supported yet.
158+
> The bot should install with 3.14 though, but you can not expect the same performance as with 3.13 yet.
159+
> That said - use 3.14 on your own risk.
157160

158161
#### b) PostgreSQL
159162
DCSServerBot needs a database to store information in. I decided to use [PostgreSQL](https://www.postgresql.org/download/), as it has great performance
@@ -200,9 +203,10 @@ you can now install DCSServerBot without the need to use Discord. Select the res
200203
installation, and you will install a variant that works without.
201204

202205
> [!NOTE]
203-
> Please keep in mind that DCSServerBot was originally built for Discord and that there are some functionalities that
204-
> only work with Discord, like statistics graphs, greenieboards, and others.<br>
205-
> You can still use a lot without Discord as in-game chat-commands, automated restarts, etc.
206+
> It's important to note that DCSServerBot was initially designed for integration with Discord, and certain features
207+
> only function properly within that platform, such as statistics graphs, greenieboards, and others.
208+
> However, many aspects of the bot can still be used without Discord, including in-game chat commands, automated
209+
> restarts, etc.
206210

207211
### Download
208212
Best is to use ```git clone https://github.com/Special-K-s-Flightsim-Bots/DCSServerBot.git``` as you then always have
@@ -415,7 +419,6 @@ NODENAME: # this will usually be your hostname
415419
host: 127.0.0.1 # SRS servers local IP (default is 127.0.0.1)
416420
port: 5002 # SRS servers local port (default is 5002). The bot will change this in your SRS configuration if set here!
417421
autostart: true # this will autostart your DCS server with the DCS server start (default: true)
418-
autoupdate: true # This will auto-update your SRS servers. Default is false, you need to run the bot as Administrator to make it work!
419422
Tacview:
420423
show_passwords: false # If you don't want to show the Tacview passwords (default: true)
421424
# instance2: # you can have an unlimited number of instance configurations, but each instance has to have a physical representation on your disk.
@@ -435,10 +438,10 @@ DEFAULT:
435438
messages: # General messages for servers. You can overwrite any in any server.
436439
greeting_message_members: "{player.name}, welcome back to {server.name}!"
437440
greeting_message_unmatched: '{player.name}, please use /linkme in our Discord, if you want to see your user stats!'
438-
message_player_username: Your player name contains invalid characters. # Default message for players with invalid usernames
439-
Please change your name to join our server.
440-
message_player_default_username: Please change your default player name at the top right # Default message for players with default usernames
441-
of the multiplayer selection list to an individual one!
441+
message_player_username: Your player name contains invalid characters.
442+
Please change your name to join our server. # Default message for players with invalid usernames
443+
message_player_default_username: Please change your default player name at the top right
444+
of the multiplayer selection list to an individual one! # Default message for players with default usernames
442445
message_player_inappropriate_username: Your username is inappropriate and needs to be changed to join this server.
443446
message_ban: 'You are banned from this server. Reason: {}' # default message, if a player is banned on the DCS server
444447
message_reserved: 'This server is locked for specific users.\nPlease contact a server admin.' # Message if server requires discord role (optional)
@@ -713,6 +716,29 @@ In these cases, you can run the `repair.cmd` script in the DCSServerBot installa
713716

714717
---
715718

719+
## Backup and Restore
720+
The platform allows you to backup and restore your database, server configurations, or bot settings.
721+
The backup and restore functionality are accessible in the Backup [service](./services/backup/README.md)
722+
and [plugin](./plugins/backup/README.md).
723+
724+
> [!NOTE]
725+
> The bot includes an auto-restore feature that allows you to easily transfer your data.
726+
> To use this feature, copy the appropriate backup file into a folder named restore within the DCSServerBot
727+
> installation directory (make sure to create it first). Upon startup, DCSServerBot will read this file and restore any
728+
> saved information such as:
729+
> * Database backup
730+
> * DCSServerBot configuration backup
731+
> * Instance backup (including missions and configurations; for details, see the backup service)
732+
733+
> [!TIP]
734+
> Utilizing the auto-restore feature can be helpful when moving your database from one computer to another.
735+
> After installing DCSServerBot on the new system, place the appropriate db_*.tar file in a `restore` folder within the
736+
> bot's installation directory and ensure the node's nodes.yaml file points to the newly created database.
737+
> Then launch the bot and allow the restoration process to complete.
738+
>
739+
> _Please be prepared to provide the new PostgreSQL master password when prompted._
740+
---
741+
716742
## How to use DCSServerBot in Missions?
717743

718744
### How to talk to the Bot from inside Missions

Scripts/net/DCSServerBot/DCSServerBot.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ end
3434

3535
dcsbot.sendBotTable = dcsbot.sendBotTable or function (tbl, channel)
3636
tbl.server_name = cfg.name
37-
tbl.channel = channel or "-1"
37+
tbl.channel = tostring(channel or "-1")
3838
socket.try(dcsbot.UDPSendSocket:sendto(net.lua2json(tbl), config.BOT_HOST, config.BOT_PORT))
3939
end
4040

Scripts/net/DCSServerBot/DCSServerBotUtils.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ function sendBotTable(tbl, channel)
3333
server_name = loadSettingsRaw().name
3434
end
3535
tbl.server_name = server_name
36-
tbl.channel = channel or "-1"
36+
tbl.channel = tostring(channel or "-1")
3737
socket.try(UDPSendSocket:sendto(net.lua2json(tbl), config.BOT_HOST, config.BOT_PORT))
3838
end
3939

core/commandline.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,14 @@
1919
parser.add_argument('-n', '--node', help='Node name', default=platform.node())
2020
parser.add_argument('-x', '--noupdate', action='store_true', help='Do not autoupdate')
2121
parser.add_argument('-s', '--secret', action='store_true', help='Reveal all stored passwords')
22+
parser.add_argument('-a', '--restarted', action='store_true', help='Indicates if the bot was restarted')
2223
elif program == 'update.py':
2324
parser.add_argument('-n', '--node', help='Node name', default=platform.node())
2425
parser.add_argument('-r', '--no-restart', action='store_true', default=False,
2526
help="don't start DCSServerBot after the update")
2627
parser.add_argument('-i', '--install', action='store_true', default=False,
2728
help='Install requirements.txt only')
29+
parser.add_argument('-a', '--restarted', action='store_true', help='Indicates if the bot was restarted')
2830
elif program == 'install.py':
2931
parser.add_argument('-n', '--node', help='Node name', default=platform.node())
3032
parser.add_argument('-u', '--user', help='Database username', default='dcsserverbot')
@@ -33,6 +35,8 @@
3335
parser.add_argument('-m', '--mizfile', help='Mission to patch', required=True)
3436
parser.add_argument('-p', '--preset', help='Preset to use, can be comma-separated')
3537
parser.add_argument('-f', '--presets-file', help='Presets file', default='presets.yaml')
38+
elif program == 'recover.py':
39+
parser.add_argument('-n', '--node', help='Node name', default=platform.node())
3640
elif program == 'testdriver.py':
3741
parser.add_argument('-n', '--node', help='Node name', default='TestNode')
3842
COMMAND_LINE_ARGS = parser.parse_args()

core/data/const.py

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
"Side",
55
"Status",
66
"Coalition",
7-
"Channel"
7+
"Channel",
8+
"PortType",
9+
"Port",
810
]
911

1012

@@ -44,3 +46,42 @@ class Channel(Enum):
4446
COALITION_BLUE_EVENTS = 'blue_events'
4547
COALITION_RED_CHAT = 'red'
4648
COALITION_RED_EVENTS = 'red_events'
49+
50+
51+
class PortType(Enum):
52+
TCP = 'tcp'
53+
UDP = 'udp'
54+
BOTH = 'tcp+udp'
55+
56+
57+
class Port:
58+
59+
def __init__(self, port: int, typ: PortType, *, public: bool = False):
60+
self.port = port
61+
self.typ = typ
62+
self.public = public
63+
64+
def __repr__(self):
65+
return f'{self.port}/{self.typ.value}'
66+
67+
def __str__(self):
68+
return str(self.port)
69+
70+
def __int__(self):
71+
return self.port
72+
73+
def __index__(self):
74+
return self.port
75+
76+
def __hash__(self):
77+
return hash(self.port)
78+
79+
def __eq__(self, other):
80+
if isinstance(other, Port):
81+
return self.port == other.port
82+
elif isinstance(other, int):
83+
return self.port == other
84+
return False
85+
86+
def type(self):
87+
return self.typ

core/data/dataobject.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import logging
44

5+
from abc import ABC
56
from configparser import ConfigParser
67
from dataclasses import dataclass, field
78
from typing import TYPE_CHECKING, Callable, Type, TypeVar, Generic, ClassVar, Any
@@ -18,7 +19,7 @@
1819

1920

2021
@dataclass
21-
class DataObject:
22+
class DataObject(ABC):
2223
name: str
2324
node: Node = field(compare=False, repr=False)
2425
pool: ConnectionPool = field(compare=False, repr=False, init=False)
@@ -36,6 +37,11 @@ def __post_init__(self):
3637
def __hash__(self):
3738
return hash(self.name)
3839

40+
def __eq__(self, other):
41+
if isinstance(other, DataObject):
42+
return self.name == other.name
43+
return False
44+
3945

4046
T = TypeVar("T", bound=DataObject)
4147

core/data/impl/instanceimpl.py

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from core.utils.helper import SettingsDict
1010
from dataclasses import dataclass
1111
from typing import TYPE_CHECKING
12+
from typing_extensions import override
1213

1314
if TYPE_CHECKING:
1415
from core import Server
@@ -20,6 +21,7 @@
2021
@DataObjectFactory.register()
2122
class InstanceImpl(Instance):
2223

24+
@override
2325
def __post_init__(self):
2426
super().__post_init__()
2527
self.is_remote = False
@@ -57,8 +59,7 @@ def __post_init__(self):
5759
# dirty |= True
5860
if dirty:
5961
autoexec.net = net
60-
61-
server_name = None
62+
self._server_name = None
6263
settings_path = os.path.join(self.home, 'Config', 'serverSettings.lua')
6364
if os.path.exists(settings_path):
6465
settings = SettingsDict(self, settings_path, root='cfg')
@@ -67,25 +68,33 @@ def __post_init__(self):
6768
settings['port'] = dcs_port
6869
else:
6970
self.locals['dcs_port'] = settings.get('port', 10308)
70-
server_name = settings.get('name', 'DCS Server') if settings else None
71-
if server_name == 'n/a':
72-
server_name = None
73-
self.update_instance(server_name)
71+
self._server_name = settings.get('name', 'DCS Server') if settings else None
72+
if self._server_name == 'n/a':
73+
self._server_name = None
74+
self.update_instance()
75+
76+
@property
77+
def server_name(self) -> str:
78+
if self.server:
79+
return self.server.name
80+
else:
81+
return self._server_name
7482

75-
def update_instance(self, server_name: str | None = None):
83+
def update_instance(self):
7684
try:
7785
with self.pool.connection() as conn:
7886
with conn.transaction():
7987
conn.execute("""
80-
INSERT INTO instances (node, instance, port, server_name)
81-
VALUES (%s, %s, %s, %s)
88+
INSERT INTO instances (node, instance, port)
89+
VALUES (%s, %s, %s)
8290
ON CONFLICT (node, instance) DO UPDATE
83-
SET port=excluded.port, server_name=excluded.server_name
84-
""", (self.node.name, self.name, self.locals.get('bot_port', 6666), server_name))
91+
SET port=excluded.port
92+
""", (self.node.name, self.name, self.locals.get('bot_port', 6666)))
8593
except psycopg.errors.UniqueViolation:
8694
self.log.error(f"bot_port {self.locals.get('bot_port', 6666)} is already in use on node {self.node.name}!")
8795
raise
8896

97+
@override
8998
@property
9099
def home(self) -> str:
91100
return os.path.expandvars(self.locals.get('home', os.path.join(SAVED_GAMES, self.name)))
@@ -98,6 +107,7 @@ def update_server(self, server: Server | None = None):
98107
WHERE node = %s AND instance = %s
99108
""", (server.name if server and server.name != 'n/a' else None, self.node.name, self.name))
100109

110+
@override
101111
def set_server(self, server: Server | None):
102112
if self._server and self._server.status not in [Status.UNREGISTERED, Status.SHUTDOWN]:
103113
raise InstanceBusyError()
@@ -107,12 +117,12 @@ def set_server(self, server: Server | None):
107117
settings_path = os.path.join(self.home, 'Config', 'serverSettings.lua')
108118
if os.path.exists(settings_path):
109119
os.remove(settings_path)
110-
self.prepare()
120+
self._prepare()
111121
if server and server.name:
112122
server.instance = self
113123
self.update_server(server)
114124

115-
def prepare(self):
125+
def _prepare(self):
116126
if 'DCS' not in self.node.locals:
117127
return
118128
# desanitisation of Slmod (if there)

0 commit comments

Comments
 (0)