diff --git a/.gitignore b/.gitignore index c529332..9968405 100644 --- a/.gitignore +++ b/.gitignore @@ -52,4 +52,7 @@ build *.g.dart out -RELEASE \ No newline at end of file +RELEASE + +*.DEPS +*.dat \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 5d06e41..9ca3b19 100644 --- a/Dockerfile +++ b/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 \ No newline at end of file diff --git a/bin/server.dart b/bin/server.dart index 8c3bbc6..97a9475 100644 --- a/bin/server.dart +++ b/bin/server.dart @@ -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); diff --git a/compile.sh b/compile.sh index 66894e1..4222198 100755 --- a/compile.sh +++ b/compile.sh @@ -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 diff --git a/docker_images/builddeps/Dockerfile b/docker_images/builddeps/Dockerfile index b1443d9..d1ec045 100644 --- a/docker_images/builddeps/Dockerfile +++ b/docker_images/builddeps/Dockerfile @@ -1,4 +1,4 @@ -FROM debian:latest +FROM ghcr.io/parkervcp/yolks:debian WORKDIR / diff --git a/docker_images/latest/Dockerfile b/docker_images/latest/Dockerfile deleted file mode 100644 index 52fb5aa..0000000 --- a/docker_images/latest/Dockerfile +++ /dev/null @@ -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"] \ No newline at end of file diff --git a/docker_images/latest/entrypoint.sh b/docker_images/latest/entrypoint.sh deleted file mode 100644 index f3f1ffb..0000000 --- a/docker_images/latest/entrypoint.sh +++ /dev/null @@ -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} \ No newline at end of file diff --git a/docker_images/runtimedeps/Dockerfile b/docker_images/runtimedeps/Dockerfile deleted file mode 100644 index 677e55f..0000000 --- a/docker_images/runtimedeps/Dockerfile +++ /dev/null @@ -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 \ No newline at end of file diff --git a/lib/game.dart b/lib/game.dart index 6c4408e..09bca0c 100644 --- a/lib/game.dart +++ b/lib/game.dart @@ -18,6 +18,7 @@ Future 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> doScanMods(bool jail) async { List 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( diff --git a/lib/pages/GameServerPage.dart b/lib/pages/GameServerPage.dart index 8153c9f..557af0f 100644 --- a/lib/pages/GameServerPage.dart +++ b/lib/pages/GameServerPage.dart @@ -73,7 +73,7 @@ class GameServerPageState extends State { 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; diff --git a/lib/pages/ModManager.dart b/lib/pages/ModManager.dart index 8bed01d..4be66b3 100644 --- a/lib/pages/ModManager.dart +++ b/lib/pages/ModManager.dart @@ -54,7 +54,8 @@ class ModManagerState extends State { 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 { 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 { } } -class ModPage extends StatelessWidget { - bool initDone = false; +class ModPage extends StatefulWidget { + @override + State createState() => ModPageState(); +} + +class ModPageState extends State { TextEditingController id = TextEditingController(); TextEditingController name = TextEditingController(); String instance = ""; @@ -109,23 +115,25 @@ class ModPage extends StatelessWidget { bool willDelete = false; String pak = "Not initialized"; String hash = ""; + bool enabled = false; + + @override + void didChangeDependencies() { + final args = ModalRoute.of(context)!.settings.arguments as Mod?; + + if (args != null) { + id.text = args.mod_id.toString(); + name.text = args.mod_name; + isNewMod = args.newMod; + instance = args.mod_instance_id(); + pak = args.mod_pak; + hash = args.mod_hash; + enabled = args.enabled; + } + } @override Widget build(BuildContext context) { - 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; - isNewMod = args.newMod; - instance = args.mod_instance_id(); - pak = args.mod_pak; - hash = args.mod_hash; - } - } - 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") ], - )) + )), ]), ), ); diff --git a/lib/pages/ServerSettings.dart b/lib/pages/ServerSettings.dart index e680fe8..eadc2ed 100644 --- a/lib/pages/ServerSettings.dart +++ b/lib/pages/ServerSettings.dart @@ -12,20 +12,21 @@ class ServerSettingsPage extends StatefulWidget { class ServerSettingsState extends State { 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 { 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 { 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 { 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 { 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")) ], diff --git a/lib/statemachine.dart b/lib/statemachine.dart index 0007c72..30665ae 100644 --- a/lib/statemachine.dart +++ b/lib/statemachine.dart @@ -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 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 diff --git a/lib/structs/SessionData.dart b/lib/structs/SessionData.dart index 38f6f47..0451acf 100644 --- a/lib/structs/SessionData.dart +++ b/lib/structs/SessionData.dart @@ -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); diff --git a/lib/structs/mod.dart b/lib/structs/mod.dart index 7eeb08c..bea0266 100644 --- a/lib/structs/mod.dart +++ b/lib/structs/mod.dart @@ -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")); } } diff --git a/lib/structs/settings.dart b/lib/structs/settings.dart index 6b3acaa..e270003 100644 --- a/lib/structs/settings.dart +++ b/lib/structs/settings.dart @@ -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 RunUpdate({bool valid = true}) { return Process.run(getSteamCmd(), [ "+@sSteamCmdForcePlatformType", @@ -228,6 +231,7 @@ class Settings { List 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 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 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 initializeSteamCmd() async { diff --git a/lib/wine.dart b/lib/wine.dart index 6216c7a..2c84124 100644 --- a/lib/wine.dart +++ b/lib/wine.dart @@ -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 runWine(String command, List 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 runWine(String command, List argx) async { Future 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 runWinetrick(String trick) async { await dir.create(recursive: true); Map env = Map.from(Platform.environment); - env["WINEPREFIX"] = dir.path; + //env["WINEPREFIX"] = dir.path; try { List args = ["-q", trick]; @@ -77,7 +76,7 @@ Future runDetachedWine( await dir.create(recursive: true); Map env = Map.from(Platform.environment); - env["WINEPREFIX"] = dir.path; + //env["WINEPREFIX"] = dir.path; try { List args = [command]; @@ -87,7 +86,16 @@ Future 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) { diff --git a/pubspec.yaml b/pubspec.yaml index 72c5a7a..5143645 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -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: diff --git a/scripts/rcon.py b/scripts/rcon.py new file mode 100644 index 0000000..764a7e4 --- /dev/null +++ b/scripts/rcon.py @@ -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])) \ No newline at end of file