Get wrapper working
This commit is contained in:
parent
0ae098318a
commit
26434a9123
19 changed files with 211 additions and 255 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -53,3 +53,6 @@ build
|
|||
|
||||
out
|
||||
RELEASE
|
||||
|
||||
*.DEPS
|
||||
*.dat
|
29
Dockerfile
29
Dockerfile
|
@ -7,9 +7,36 @@ WORKDIR /app
|
|||
RUN rm RELEASE
|
||||
RUN PATH=$PATH:/flutter/bin /bin/bash /app/compile.sh
|
||||
|
||||
FROM git.zontreck.com/ariascreations/conanservermanager:runtimedeps
|
||||
FROM git.zontreck.com/ariascreations/conanservermanager:builddeps AS RCONBUILD
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN apt-get -y install build-essential git
|
||||
RUN git clone https://github.com/Tiiffi/mcrcon
|
||||
|
||||
WORKDIR /app/mcrcon
|
||||
|
||||
RUN make
|
||||
|
||||
|
||||
FROM ghcr.io/parkervcp/yolks:wine_latest
|
||||
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY --from=BUILDER /app/out/server /app/server
|
||||
COPY --from=RCONBUILD /app/mcrcon/mcrcon /app/rcon
|
||||
|
||||
|
||||
EXPOSE 25306/tcp
|
||||
EXPOSE 7779/tcp
|
||||
EXPOSE 7779/udp
|
||||
EXPOSE 7780/udp
|
||||
EXPOSE 7780/tcp
|
||||
EXPOSE 7781/udp
|
||||
EXPOSE 7781/tcp
|
||||
EXPOSE 7782/udp
|
||||
EXPOSE 7782/tcp
|
||||
|
||||
|
||||
USER container
|
|
@ -39,7 +39,8 @@ void main() async {
|
|||
print("Initialized Steamcmd");
|
||||
|
||||
print("Running winetricks");
|
||||
await settings.initializeWine();
|
||||
//if (!Directory(settings.getWinePrefixPath()).existsSync())
|
||||
// await settings.initializeWine();
|
||||
print("Finished installing needed DLLs");
|
||||
|
||||
print("Checking for game server updates...");
|
||||
|
@ -71,15 +72,6 @@ void main() async {
|
|||
}
|
||||
|
||||
print("Starting up server manager server wrapper");
|
||||
File logFile = File(PathHelper.builder(settings.getServerPath())
|
||||
.resolve("ConanSandbox")
|
||||
.resolve("Saved")
|
||||
.resolve("Logs")
|
||||
.resolve("ConanSandbox.log")
|
||||
.build());
|
||||
await logFile.create(recursive: true);
|
||||
|
||||
tailAndPrint(logFile);
|
||||
|
||||
await PacketServer.start(settings.inst?.serverSettings.WrapperPort ?? 25306);
|
||||
|
||||
|
|
|
@ -18,18 +18,12 @@ then
|
|||
docker build -t git.zontreck.com/ariascreations/conanservermanager:builddeps docker_images/builddeps
|
||||
docker push git.zontreck.com/ariascreations/conanservermanager:builddeps
|
||||
|
||||
docker build -t git.zontreck.com/ariascreations/conanservermanager:runtimedeps docker_images/runtimedeps
|
||||
docker push git.zontreck.com/ariascreations/conanservermanager:runtimedeps
|
||||
|
||||
rm RELEASE.DEPS
|
||||
fi
|
||||
|
||||
docker build -t git.zontreck.com/ariascreations/conanservermanager:stable $(pwd)
|
||||
docker push git.zontreck.com/ariascreations/conanservermanager:stable
|
||||
|
||||
docker build -t git.zontreck.com/ariascreations/conanservermanager:latest docker_images/latest
|
||||
docker push git.zontreck.com/ariascreations/conanservermanager:latest
|
||||
|
||||
docker build -t git.zontreck.com/ariascreations/conanservermanager:installer docker_images/installer
|
||||
docker push git.zontreck.com/ariascreations/conanservermanager:installer
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
FROM debian:latest
|
||||
FROM ghcr.io/parkervcp/yolks:debian
|
||||
|
||||
|
||||
WORKDIR /
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
FROM debian:latest
|
||||
RUN apt-get update -y
|
||||
RUN apt-get upgrade -y
|
||||
RUN apt-get install -y gnupg2 numactl tzdata software-properties-common libntlm0 winbind xvfb xauth python3 libncurses5:i386 libncurses6:i386 libsdl2-2.0-0 libsdl2-2.0-0:i386
|
||||
|
||||
FROM git.zontreck.com/ariascreations/conanservermanager:stable
|
||||
|
||||
COPY ./entrypoint.sh /entrypoint.sh
|
||||
|
||||
EXPOSE 25306/tcp
|
||||
EXPOSE 7779/tcp
|
||||
EXPOSE 7779/udp
|
||||
EXPOSE 7780/udp
|
||||
EXPOSE 7780/tcp
|
||||
EXPOSE 7781/udp
|
||||
EXPOSE 7781/tcp
|
||||
EXPOSE 7782/udp
|
||||
EXPOSE 7782/tcp
|
||||
|
||||
ENTRYPOINT ["/bin/bash", "/entrypoint.sh"]
|
|
@ -1,60 +0,0 @@
|
|||
#!/bin/bash
|
||||
# Copied the entrypoint and slightly altered, from parkervcp's dart yolk.
|
||||
|
||||
cd /home/container
|
||||
|
||||
# Information output
|
||||
echo "Running on Debian $(cat /etc/debian_version)"
|
||||
echo "Current timezone: $(cat /etc/timezone)"
|
||||
wine --version
|
||||
|
||||
|
||||
if [[ $XVFB == 1 ]]; then
|
||||
Xvfb :0 -screen 0 ${DISPLAY_WIDTH}x${DISPLAY_HEIGHT}x${DISPLAY_DEPTH} &
|
||||
fi
|
||||
|
||||
# Install necessary to run packages
|
||||
echo "First launch will throw some errors. Ignore them"
|
||||
|
||||
mkdir -p $WINEPREFIX
|
||||
|
||||
# Check if wine-gecko required and install it if so
|
||||
|
||||
echo "Installing Gecko"
|
||||
WINETRICKS_RUN=${WINETRICKS_RUN/gecko}
|
||||
|
||||
if [ ! -f "$WINEPREFIX/gecko_x86.msi" ]; then
|
||||
wget -q -O $WINEPREFIX/gecko_x86.msi http://dl.winehq.org/wine/wine-gecko/2.47.4/wine_gecko-2.47.4-x86.msi
|
||||
fi
|
||||
|
||||
if [ ! -f "$WINEPREFIX/gecko_x86_64.msi" ]; then
|
||||
wget -q -O $WINEPREFIX/gecko_x86_64.msi http://dl.winehq.org/wine/wine-gecko/2.47.4/wine_gecko-2.47.4-x86_64.msi
|
||||
fi
|
||||
|
||||
wine msiexec /i $WINEPREFIX/gecko_x86.msi /qn /quiet /norestart /log $WINEPREFIX/gecko_x86_install.log
|
||||
wine msiexec /i $WINEPREFIX/gecko_x86_64.msi /qn /quiet /norestart /log $WINEPREFIX/gecko_x86_64_install.log
|
||||
|
||||
# Check if wine-mono required and install it if so
|
||||
|
||||
echo "Installing mono"
|
||||
WINETRICKS_RUN=${WINETRICKS_RUN/mono}
|
||||
|
||||
if [ ! -f "$WINEPREFIX/mono.msi" ]; then
|
||||
wget -q -O $WINEPREFIX/mono.msi https://dl.winehq.org/wine/wine-mono/9.1.0/wine-mono-9.1.0-x86.msi
|
||||
fi
|
||||
|
||||
wine msiexec /i $WINEPREFIX/mono.msi /qn /quiet /norestart /log $WINEPREFIX/mono_install.log
|
||||
|
||||
# List and install other packages
|
||||
for trick in $WINETRICKS_RUN; do
|
||||
echo "Installing $trick"
|
||||
winetricks -q $trick
|
||||
done
|
||||
|
||||
|
||||
# Replace startup variables
|
||||
MODIFIED_STARTUP=$(echo -e ${STARTUP} | sed -e 's/{{/${/g' -e 's/}}/}/g')
|
||||
echo ":/home/container$ ${MODIFIED_STARTUP}"
|
||||
|
||||
# Run the server
|
||||
eval ${MODIFIED_STARTUP}
|
|
@ -1,53 +0,0 @@
|
|||
FROM debian:latest
|
||||
|
||||
RUN dpkg --add-architecture i386 \
|
||||
&& apt-get update \
|
||||
&& apt-get upgrade -y \
|
||||
&& apt-get install -y tar curl gcc g++ lib32gcc-s1 libgcc-12-dev libgcc-11-dev libcurl4-gnutls-dev:i386 libssl-dev:i386 libcurl4:i386 lib32tinfo6 libtinfo6:i386 lib32z1 lib32stdc++6 libncurses5:i386 libcurl3-gnutls:i386 libsdl2-2.0-0:i386 libsdl2-2.0-0 iproute2 gdb libsdl1.2debian libfontconfig1 telnet net-tools netcat-traditional tzdata numactl xvfb wget tini \
|
||||
&& useradd -m -d /home/container container
|
||||
|
||||
## install rcon
|
||||
RUN cd /tmp/ \
|
||||
&& curl -sSL https://github.com/gorcon/rcon-cli/releases/download/v0.10.3/rcon-0.10.3-amd64_linux.tar.gz > rcon.tar.gz \
|
||||
&& tar xvf rcon.tar.gz \
|
||||
&& mv rcon-0.10.3-amd64_linux/rcon /usr/local/bin/
|
||||
|
||||
# Temp fix for things that still need libssl1.1
|
||||
RUN if [ "$(uname -m)" = "x86_64" ]; then \
|
||||
wget http://archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.0g-2ubuntu4_amd64.deb && \
|
||||
dpkg -i libssl1.1_1.1.0g-2ubuntu4_amd64.deb && \
|
||||
rm libssl1.1_1.1.0g-2ubuntu4_amd64.deb; \
|
||||
fi
|
||||
|
||||
# Merge wine dockerfiles
|
||||
## install required packages
|
||||
RUN dpkg --add-architecture i386 \
|
||||
&& apt update -y \
|
||||
&& apt install -y --no-install-recommends gnupg2 numactl tzdata software-properties-common libntlm0 winbind xvfb xauth python3 libncurses5:i386 libncurses6:i386 libsdl2-2.0-0 libsdl2-2.0-0:i386
|
||||
|
||||
# Install wine with recommends
|
||||
RUN mkdir -pm755 /etc/apt/keyrings
|
||||
RUN wget -O /etc/apt/keyrings/winehq-archive.key https://dl.winehq.org/wine-builds/winehq.key
|
||||
RUN wget -NP /etc/apt/sources.list.d/ https://dl.winehq.org/wine-builds/debian/dists/bookworm/winehq-bookworm.sources
|
||||
RUN apt update
|
||||
RUN apt install --install-recommends winehq-stable cabextract wine-binfmt -y
|
||||
|
||||
# Set up Winetricks
|
||||
RUN wget -q -O /usr/sbin/winetricks https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks \
|
||||
&& chmod +x /usr/sbin/winetricks
|
||||
|
||||
ENV HOME=/home/container
|
||||
ENV WINEPREFIX=/home/container/.wine
|
||||
ENV WINETRICKS_RUN="vcrun2013 vcrun2015 corefonts"
|
||||
ENV WINEDLLOVERRIDES="mscoree,mshtml="
|
||||
ENV DISPLAY=:0
|
||||
ENV DISPLAY_WIDTH=1024
|
||||
ENV DISPLAY_HEIGHT=768
|
||||
ENV DISPLAY_DEPTH=16
|
||||
ENV XVFB=1
|
||||
|
||||
USER container
|
||||
ENV USER=container HOME=/home/container
|
||||
WORKDIR /home/container
|
||||
|
||||
STOPSIGNAL SIGINT
|
|
@ -18,6 +18,7 @@ Future<void> doDownloadMods(bool jail) async {
|
|||
"anonymous",
|
||||
];
|
||||
for (Mod M in settings.inst!.mods) {
|
||||
if (!M.enabled) continue;
|
||||
manifest.add("+workshop_download_item");
|
||||
manifest.add("440900");
|
||||
manifest.add("${M.mod_id}");
|
||||
|
@ -42,6 +43,11 @@ Future<List<Mod>> doScanMods(bool jail) async {
|
|||
List<Mod> ret = [];
|
||||
|
||||
for (Mod M in settings.inst!.mods.toList()) {
|
||||
if (!M.enabled) {
|
||||
ret.add(M);
|
||||
continue;
|
||||
}
|
||||
|
||||
var index = settings.inst!.mods.indexOf(M);
|
||||
// Assemble final path.
|
||||
String modsPath = PathHelper.builder(
|
||||
|
|
|
@ -73,7 +73,7 @@ class GameServerPageState extends State<GameServerPage> {
|
|||
context, "/server/ports",
|
||||
arguments: settings.inst!.serverSettings);
|
||||
|
||||
if (reply != null) return; // If null, no change.
|
||||
if (reply == null) return; // If null, no change.
|
||||
|
||||
setState(() {
|
||||
settings.inst!.serverSettings = reply as ServerSettings;
|
||||
|
|
|
@ -54,7 +54,8 @@ class ModManagerState extends State<ModManager> {
|
|||
padding: EdgeInsets.all(12),
|
||||
child: ListTile(
|
||||
title: Text(mod.mod_name),
|
||||
subtitle: Text("ID: ${mod.mod_id}\nLoad Order: ${idx}"),
|
||||
subtitle: Text(
|
||||
"ID: ${mod.mod_id}\nLoad Order: ${idx}\nEnabled: ${mod.enabled}"),
|
||||
onTap: () async {
|
||||
final reply = await Navigator.pushNamed(
|
||||
context, "/server/mods/edit",
|
||||
|
@ -63,7 +64,8 @@ class ModManagerState extends State<ModManager> {
|
|||
mod_name: mod.mod_name,
|
||||
mod_pak: mod.mod_pak,
|
||||
mod_hash: mod.mod_hash,
|
||||
newMod: false));
|
||||
newMod: false,
|
||||
enabled: mod.enabled));
|
||||
|
||||
if (reply != null) {
|
||||
if (reply is bool) {
|
||||
|
@ -100,8 +102,12 @@ class ModManagerState extends State<ModManager> {
|
|||
}
|
||||
}
|
||||
|
||||
class ModPage extends StatelessWidget {
|
||||
bool initDone = false;
|
||||
class ModPage extends StatefulWidget {
|
||||
@override
|
||||
State<StatefulWidget> createState() => ModPageState();
|
||||
}
|
||||
|
||||
class ModPageState extends State<ModPage> {
|
||||
TextEditingController id = TextEditingController();
|
||||
TextEditingController name = TextEditingController();
|
||||
String instance = "";
|
||||
|
@ -109,13 +115,12 @@ class ModPage extends StatelessWidget {
|
|||
bool willDelete = false;
|
||||
String pak = "Not initialized";
|
||||
String hash = "";
|
||||
bool enabled = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
void didChangeDependencies() {
|
||||
final args = ModalRoute.of(context)!.settings.arguments as Mod?;
|
||||
|
||||
if (!initDone) {
|
||||
initDone = true;
|
||||
if (args != null) {
|
||||
id.text = args.mod_id.toString();
|
||||
name.text = args.mod_name;
|
||||
|
@ -123,9 +128,12 @@ class ModPage extends StatelessWidget {
|
|||
instance = args.mod_instance_id();
|
||||
pak = args.mod_pak;
|
||||
hash = args.mod_hash;
|
||||
enabled = args.enabled;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text("Mod Editor"),
|
||||
|
@ -142,8 +150,13 @@ class ModPage extends StatelessWidget {
|
|||
if (willDelete) {
|
||||
Navigator.pop(context, true);
|
||||
} else {
|
||||
Navigator.pop(context,
|
||||
Mod(mod_id: idVal, mod_name: name.text, newMod: false));
|
||||
Navigator.pop(
|
||||
context,
|
||||
Mod(
|
||||
mod_id: idVal,
|
||||
mod_name: name.text,
|
||||
newMod: false,
|
||||
enabled: enabled));
|
||||
}
|
||||
},
|
||||
),
|
||||
|
@ -202,6 +215,16 @@ class ModPage extends StatelessWidget {
|
|||
title: Text("Mod Hash"),
|
||||
subtitle: Text(hash),
|
||||
),
|
||||
SwitchListTile(
|
||||
value: enabled,
|
||||
onChanged: (V) {
|
||||
setState(() {
|
||||
enabled = V;
|
||||
});
|
||||
},
|
||||
title: Text("Enabled"),
|
||||
subtitle: Text("Whether mod is enabled or not"),
|
||||
),
|
||||
if (!isNewMod)
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
|
@ -216,7 +239,7 @@ class ModPage extends StatelessWidget {
|
|||
),
|
||||
Text("Remove Mod")
|
||||
],
|
||||
))
|
||||
)),
|
||||
]),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -12,20 +12,21 @@ class ServerSettingsPage extends StatefulWidget {
|
|||
class ServerSettingsState extends State<ServerSettingsPage> {
|
||||
String pass = "";
|
||||
TextEditingController passwordController = TextEditingController();
|
||||
int rconPort = 0;
|
||||
int gPort = 0;
|
||||
int qPort = 0;
|
||||
int wPort = 25306;
|
||||
TextEditingController rconPortController = TextEditingController();
|
||||
TextEditingController qPortController = TextEditingController();
|
||||
TextEditingController wrapperPortController = TextEditingController();
|
||||
|
||||
TextEditingController gPortController = TextEditingController();
|
||||
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
var args = ModalRoute.of(context)!.settings.arguments as ServerSettings;
|
||||
|
||||
passwordController.text = args.RconPassword;
|
||||
rconPort = args.RconPort;
|
||||
gPort = args.GamePort;
|
||||
qPort = args.QueryPort;
|
||||
wPort = args.WrapperPort;
|
||||
rconPortController.text = "${args.RconPort}";
|
||||
gPortController.text = "${args.GamePort}";
|
||||
qPortController.text = "${args.QueryPort}";
|
||||
wrapperPortController.text = "${args.WrapperPort}";
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -61,20 +62,9 @@ class ServerSettingsState extends State<ServerSettingsPage> {
|
|||
width: 256,
|
||||
child: ListTile(
|
||||
title: Text("Rcon Port"),
|
||||
subtitle: Text("$rconPort"),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Slider(
|
||||
value: rconPort.toDouble(),
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
rconPort = value.toInt();
|
||||
});
|
||||
},
|
||||
min: 5000,
|
||||
max: 8000,
|
||||
))
|
||||
Expanded(child: TextField(controller: rconPortController))
|
||||
],
|
||||
),
|
||||
Row(
|
||||
|
@ -83,20 +73,9 @@ class ServerSettingsState extends State<ServerSettingsPage> {
|
|||
width: 256,
|
||||
child: ListTile(
|
||||
title: Text("Game Port"),
|
||||
subtitle: Text("$gPort"),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Slider(
|
||||
value: gPort.toDouble(),
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
gPort = value.toInt();
|
||||
});
|
||||
},
|
||||
min: 5000,
|
||||
max: 8000,
|
||||
))
|
||||
Expanded(child: TextField(controller: gPortController))
|
||||
],
|
||||
),
|
||||
Row(
|
||||
|
@ -105,22 +84,28 @@ class ServerSettingsState extends State<ServerSettingsPage> {
|
|||
width: 256,
|
||||
child: ListTile(
|
||||
title: Text("Query Port"),
|
||||
subtitle: Text("$qPort"),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Slider(
|
||||
value: qPort.toDouble(),
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
qPort = value.toInt();
|
||||
});
|
||||
},
|
||||
min: 5000,
|
||||
max: 8000,
|
||||
child: TextField(
|
||||
controller: qPortController,
|
||||
))
|
||||
],
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 256,
|
||||
child: ListTile(
|
||||
title: Text("Wrapper Port"),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: wrapperPortController,
|
||||
)),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
ElevatedButton(
|
||||
|
@ -129,10 +114,11 @@ class ServerSettingsState extends State<ServerSettingsPage> {
|
|||
context,
|
||||
ServerSettings(
|
||||
RconPassword: passwordController.text,
|
||||
RconPort: rconPort,
|
||||
GamePort: gPort,
|
||||
QueryPort: qPort,
|
||||
WrapperPort: wPort));
|
||||
RconPort: int.parse(rconPortController.text),
|
||||
GamePort: int.parse(gPortController.text),
|
||||
QueryPort: int.parse(qPortController.text),
|
||||
WrapperPort:
|
||||
int.parse(wrapperPortController.text)));
|
||||
},
|
||||
child: Text("Submit"))
|
||||
],
|
||||
|
|
|
@ -3,6 +3,7 @@ import 'dart:io';
|
|||
|
||||
import 'package:libac_dart/packets/packets.dart';
|
||||
import 'package:libac_dart/utils/IOTools.dart';
|
||||
import 'package:libac_dart/utils/TimeUtils.dart';
|
||||
import 'package:servermanager/game.dart';
|
||||
import 'package:servermanager/structs/SessionData.dart';
|
||||
import 'package:servermanager/structs/mod.dart';
|
||||
|
@ -81,11 +82,20 @@ class StateMachine {
|
|||
}
|
||||
|
||||
static Future<void> monitorProcess() async {
|
||||
try {
|
||||
int code = await PROC!.exitCode;
|
||||
DeadProcKillswitch.complete();
|
||||
} catch (E) {
|
||||
DeadProcKillswitch.complete();
|
||||
Settings settings = Settings();
|
||||
// Ping RCON. If we can connect, the server is alive.
|
||||
// Only start pinging once a minute, after the first 10 minutes.
|
||||
if (SessionData.operating_time.getTotalSeconds() >
|
||||
Time(minutes: 10, hours: 0, seconds: 0).getTotalSeconds() &&
|
||||
!SessionData.canPingServer) {
|
||||
SessionData.canPingServer = true;
|
||||
}
|
||||
|
||||
if (SessionData.canPingServer) {
|
||||
SessionData.timeSinceLastPing.tickUp();
|
||||
if (SessionData.timeSinceLastPing.getTotalSeconds() > 60) {
|
||||
SessionData.timeSinceLastPing.apply(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,6 +124,7 @@ class StateMachine {
|
|||
print("Sending killswitch to server");
|
||||
|
||||
PROC!.kill(ProcessSignal.sigkill);
|
||||
PacketServer.socket!.close();
|
||||
});
|
||||
|
||||
changeState(States.Inactive);
|
||||
|
@ -138,20 +149,34 @@ class StateMachine {
|
|||
"-console"
|
||||
];
|
||||
// Start the server now
|
||||
String executable = PathHelper.builder(settings.getServerPath())
|
||||
.resolve("ConanSandbox")
|
||||
.resolve("Binaries")
|
||||
.resolve("Win64")
|
||||
.resolve("ConanSandboxServer-Win64-Shipping.exe")
|
||||
.build();
|
||||
|
||||
if (Platform.isWindows) {
|
||||
PROC = await Process.start(
|
||||
PathHelper.combine(
|
||||
settings.getServerPath(), "ConanSandboxServer.exe"),
|
||||
conanArgs,
|
||||
PROC = await Process.start(executable, conanArgs,
|
||||
workingDirectory: settings.getServerPath());
|
||||
} else {
|
||||
runDetachedWine(
|
||||
PathHelper.combine(
|
||||
settings.getServerPath(), "ConanSandboxServer.exe"),
|
||||
conanArgs,
|
||||
settings.getServerPath());
|
||||
runDetachedWine(executable, conanArgs, settings.getServerPath());
|
||||
}
|
||||
|
||||
Timer.periodic(Duration(seconds: 20), (timer) async {
|
||||
File logFile = File(PathHelper.builder(settings.getServerPath())
|
||||
.resolve("ConanSandbox")
|
||||
.resolve("Saved")
|
||||
.resolve("Logs")
|
||||
.resolve("ConanSandbox.log")
|
||||
.build());
|
||||
await logFile.create(recursive: true);
|
||||
|
||||
tailAndPrint(logFile);
|
||||
|
||||
timer.cancel();
|
||||
});
|
||||
|
||||
changeState(States.Idle);
|
||||
} else if (currentState == States.PreStart) {
|
||||
// Perform Backup Task
|
||||
|
|
|
@ -18,6 +18,9 @@ class SessionData {
|
|||
|
||||
static Time mod_update_check_tracker = Time(hours: 0, minutes: 0, seconds: 0);
|
||||
static bool enableRestartTimer = false;
|
||||
static bool canPingServer = false;
|
||||
|
||||
static Time timeSinceLastPing = Time(hours: 0, minutes: 0, seconds: 0);
|
||||
|
||||
static void resetModUpdateChecker() {
|
||||
mod_update_check_tracker = Time(hours: 0, minutes: 0, seconds: 0);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:libac_dart/nbt/NbtUtils.dart';
|
||||
import 'package:libac_dart/nbt/impl/CompoundTag.dart';
|
||||
import 'package:libac_dart/nbt/impl/LongTag.dart';
|
||||
import 'package:libac_dart/nbt/impl/StringTag.dart';
|
||||
|
@ -8,6 +9,7 @@ class Mod {
|
|||
int mod_id = 0;
|
||||
String mod_pak = "";
|
||||
String mod_hash = "";
|
||||
bool enabled = true;
|
||||
|
||||
bool newMod = false;
|
||||
UUID _id = UUID.ZERO;
|
||||
|
@ -24,7 +26,8 @@ class Mod {
|
|||
this.mod_id = 0,
|
||||
this.newMod = false,
|
||||
this.mod_pak = "Not Initialized",
|
||||
this.mod_hash = ""});
|
||||
this.mod_hash = "",
|
||||
this.enabled = true});
|
||||
|
||||
CompoundTag serialize() {
|
||||
CompoundTag tag = CompoundTag();
|
||||
|
@ -32,6 +35,7 @@ class Mod {
|
|||
tag.put("id", LongTag.valueOf(mod_id));
|
||||
tag.put("pak", StringTag.valueOf(mod_pak));
|
||||
tag.put("hash", StringTag.valueOf(mod_hash));
|
||||
NbtUtils.writeBoolean(tag, "enabled", enabled);
|
||||
|
||||
return tag;
|
||||
}
|
||||
|
@ -43,6 +47,7 @@ class Mod {
|
|||
mod_name: ct.get("name")!.asString(),
|
||||
mod_id: ct.get("id")!.asLong(),
|
||||
mod_pak: ct.get("pak")!.asString(),
|
||||
mod_hash: ct.get("hash")!.asString());
|
||||
mod_hash: ct.get("hash")!.asString(),
|
||||
enabled: NbtUtils.readBoolean(tag, "enabled"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ import 'package:libac_dart/nbt/impl/CompoundTag.dart';
|
|||
import 'package:libac_dart/nbt/impl/StringTag.dart';
|
||||
import 'package:libac_dart/packets/packets.dart';
|
||||
import 'package:libac_dart/utils/IOTools.dart';
|
||||
import 'package:libac_dart/utils/rcon/rcon_api.dart';
|
||||
import 'package:libac_dart/utils/uuid/NbtUUID.dart';
|
||||
import 'package:libac_dart/utils/uuid/UUID.dart';
|
||||
import 'package:servermanager/statemachine.dart';
|
||||
|
@ -73,7 +72,7 @@ class Settings {
|
|||
|
||||
steamcmd_path = tag.get("steamcmd")!.asString();
|
||||
game_path = tag.get("game")!.asString();
|
||||
base_path = tag.get("proton")!.asString();
|
||||
base_path = tag.get("base")!.asString();
|
||||
FTS = NbtUtils.readBoolean(tag, "fts"); // First Time Setup.
|
||||
// FTS should be disabled by the client when sending it back to the server in a C2SApplySettingsPacket
|
||||
|
||||
|
@ -185,6 +184,10 @@ class Settings {
|
|||
.existsSync();
|
||||
}
|
||||
|
||||
String getWinePrefixPath() {
|
||||
return PathHelper.builder(base_path).resolve("pfx").build();
|
||||
}
|
||||
|
||||
Future<ProcessResult> RunUpdate({bool valid = true}) {
|
||||
return Process.run(getSteamCmd(), [
|
||||
"+@sSteamCmdForcePlatformType",
|
||||
|
@ -228,6 +231,7 @@ class Settings {
|
|||
|
||||
List<String> paths = [];
|
||||
for (Mod mod in inst!.mods) {
|
||||
if (!mod.enabled) continue;
|
||||
var pth = PathHelper(pth: getModPath())
|
||||
.resolve("steamapps")
|
||||
.resolve("workshop")
|
||||
|
@ -252,27 +256,35 @@ class Settings {
|
|||
|
||||
Future<bool> sendRconCommand(String command) async {
|
||||
try {
|
||||
createSocket("127.0.0.1", port: inst!.serverSettings.RconPort);
|
||||
|
||||
if (inst!.serverSettings.RconPassword.isNotEmpty)
|
||||
login(inst!.serverSettings.RconPassword);
|
||||
|
||||
return sendCommand(command);
|
||||
Process.run("/app/rcon", [
|
||||
"-H",
|
||||
"127.0.0.1",
|
||||
"-p",
|
||||
inst!.serverSettings.RconPassword,
|
||||
"-P",
|
||||
"${inst!.serverSettings.RconPort}",
|
||||
command
|
||||
]);
|
||||
return true;
|
||||
} catch (E) {
|
||||
// Sending rcon failed
|
||||
return false;
|
||||
} finally {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> initializeWine() async {
|
||||
await runWinetrick("win10");
|
||||
await runWinetrick("w_workaround_wine_bug-50894");
|
||||
await runWinetrick("cmd");
|
||||
await runWinetrick("vcrun2013");
|
||||
await runWinetrick("vcrun2015");
|
||||
await runWinetrick("vcrun2017");
|
||||
await runWinetrick("vcrun2019");
|
||||
await runWinetrick("vcrun2022");
|
||||
await runWinetrick("corefonts");
|
||||
await runWinetrick("andale");
|
||||
await runWinetrick("allfonts");
|
||||
await runWinetrick("gdiplus");
|
||||
await runWinetrick("dxsdk_jun2010");
|
||||
}
|
||||
|
||||
Future<void> initializeSteamCmd() async {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:libac_dart/utils/IOTools.dart';
|
||||
|
@ -6,8 +7,7 @@ import 'package:servermanager/structs/settings.dart';
|
|||
|
||||
Future<void> runWine(String command, List<String> argx) async {
|
||||
Settings settings = Settings();
|
||||
Directory dir =
|
||||
Directory(PathHelper.builder(settings.base_path).resolve("pfx").build());
|
||||
Directory dir = Directory(settings.getWinePrefixPath());
|
||||
|
||||
if (dir.existsSync()) {
|
||||
await dir.delete(recursive: true);
|
||||
|
@ -37,8 +37,7 @@ Future<void> runWine(String command, List<String> argx) async {
|
|||
|
||||
Future<void> runWinetrick(String trick) async {
|
||||
Settings settings = Settings();
|
||||
Directory dir =
|
||||
Directory(PathHelper.builder(settings.base_path).resolve("pfx").build());
|
||||
Directory dir = Directory(settings.getWinePrefixPath());
|
||||
|
||||
if (dir.existsSync()) {
|
||||
await dir.delete(recursive: true);
|
||||
|
@ -46,7 +45,7 @@ Future<void> runWinetrick(String trick) async {
|
|||
await dir.create(recursive: true);
|
||||
|
||||
Map<String, String> env = Map.from(Platform.environment);
|
||||
env["WINEPREFIX"] = dir.path;
|
||||
//env["WINEPREFIX"] = dir.path;
|
||||
|
||||
try {
|
||||
List<String> args = ["-q", trick];
|
||||
|
@ -77,7 +76,7 @@ Future<void> runDetachedWine(
|
|||
await dir.create(recursive: true);
|
||||
|
||||
Map<String, String> env = Map.from(Platform.environment);
|
||||
env["WINEPREFIX"] = dir.path;
|
||||
//env["WINEPREFIX"] = dir.path;
|
||||
|
||||
try {
|
||||
List<String> args = [command];
|
||||
|
@ -87,7 +86,16 @@ Future<void> runDetachedWine(
|
|||
"wine", args, // Run arbitrary command with arguments
|
||||
environment: env,
|
||||
workingDirectory: workingDir,
|
||||
mode: ProcessStartMode.normal);
|
||||
mode: ProcessStartMode.detachedWithStdio);
|
||||
|
||||
StateMachine.PROC!.stdout
|
||||
.transform(utf8.decoder)
|
||||
.transform(LineSplitter())
|
||||
.forEach((line) {});
|
||||
StateMachine.PROC!.stderr
|
||||
.transform(utf8.decoder)
|
||||
.transform(LineSplitter())
|
||||
.forEach((line) {});
|
||||
|
||||
StateMachine.monitorProcess();
|
||||
} catch (e) {
|
||||
|
|
|
@ -40,7 +40,7 @@ dependencies:
|
|||
crypto:
|
||||
libac_dart:
|
||||
hosted: https://git.zontreck.com/api/packages/AriasCreations/pub/
|
||||
version: 1.0.26
|
||||
version: 1.0.30
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
|
5
scripts/rcon.py
Normal file
5
scripts/rcon.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
from mcrcon import MCRcon
|
||||
import sys
|
||||
|
||||
with MCRcon(sys.argv[1], sys.argv[2], sys.argv[3]) as mcr:
|
||||
print(mcr.command(sys.argv[4]))
|
Loading…
Reference in a new issue