diff --git a/bin/server.dart b/bin/server.dart index 286bb33..8c3bbc6 100644 --- a/bin/server.dart +++ b/bin/server.dart @@ -24,12 +24,10 @@ void main() async { PathHelper steamCmd = PathHelper.builder(helper.build()).resolve("steamcmd").mkdir(); PathHelper game = PathHelper.builder(helper.build()).resolve("game").mkdir(); - PathHelper proton = PathHelper(pth: helper.build()).resolve("proton").mkdir(); settings.base_path = helper.build(); settings.game_path = game.build(); settings.steamcmd_path = steamCmd.build(); - settings.proton_path = proton.build(); print("Setup of local system variables completed"); @@ -38,7 +36,11 @@ void main() async { print("Initializing SteamCMD"); await settings.initializeSteamCmd(); - print("Initialized Steamcmd and Proton"); + print("Initialized Steamcmd"); + + print("Running winetricks"); + await settings.initializeWine(); + print("Finished installing needed DLLs"); print("Checking for game server updates..."); await settings.RunUpdate(valid: false); @@ -69,7 +71,17 @@ void main() async { } print("Starting up server manager server wrapper"); - await PacketServer.start(); + 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); print("Server stopping"); } diff --git a/lib/main.dart b/lib/main.dart index 3e0254b..1d21bf8 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -54,7 +54,16 @@ class ServerPage extends StatelessWidget { // Send login packet to server Settings settings = Settings(); settings.client = PacketClient(); - await settings.client!.startConnect(serverIP.text); + int port = 25306; + String ip = serverIP.text; + List ipParts = ip.split(':'); + if (ipParts.length == 2) { + ip = ipParts[0]; + port = int.parse(ipParts[1]); + } + + print("Attempting to connect to FQDN/IP : ${ip} on port ${port}"); + await settings.client!.startConnect(ip, port); C2SLoginPacket login = C2SLoginPacket(); login.username = username.text; diff --git a/lib/pages/ServerSettings.dart b/lib/pages/ServerSettings.dart index efa70f2..e680fe8 100644 --- a/lib/pages/ServerSettings.dart +++ b/lib/pages/ServerSettings.dart @@ -10,25 +10,26 @@ class ServerSettingsPage extends StatefulWidget { } class ServerSettingsState extends State { - bool firstRun = true; String pass = ""; TextEditingController passwordController = TextEditingController(); int rconPort = 0; int gPort = 0; int qPort = 0; + int wPort = 25306; + + @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; + } @override Widget build(BuildContext context) { - if (firstRun) { - var args = ModalRoute.of(context)!.settings.arguments as ServerSettings; - - passwordController.text = args.RconPassword; - rconPort = args.RconPort; - gPort = args.GamePort; - qPort = args.QueryPort; - - firstRun = false; - } return Scaffold( appBar: AppBar( title: Text("Server Settings"), @@ -130,7 +131,8 @@ class ServerSettingsState extends State { RconPassword: passwordController.text, RconPort: rconPort, GamePort: gPort, - QueryPort: qPort)); + QueryPort: qPort, + WrapperPort: wPort)); }, child: Text("Submit")) ], diff --git a/lib/pages/home.dart b/lib/pages/home.dart index 031a9c6..40a8fec 100644 --- a/lib/pages/home.dart +++ b/lib/pages/home.dart @@ -55,11 +55,11 @@ class HomePageState extends State { child: Column( children: [ if (Platform.isLinux) - ListTile( - title: Text("Proton"), - leading: Icon(CupertinoIcons.gear), - subtitle: Text("Linux Proton: ${settings.proton_path}"), - ), // Not yet implemented + SwitchListTile( + value: true, + onChanged: (V) {}, + title: Text("Wine"), + ), ListTile( title: Text("SteamCMD"), leading: Icon(Icons.comment_rounded), diff --git a/lib/statemachine.dart b/lib/statemachine.dart index eecc357..0007c72 100644 --- a/lib/statemachine.dart +++ b/lib/statemachine.dart @@ -4,10 +4,10 @@ import 'dart:io'; import 'package:libac_dart/packets/packets.dart'; import 'package:libac_dart/utils/IOTools.dart'; import 'package:servermanager/game.dart'; -import 'package:servermanager/proton.dart'; import 'package:servermanager/structs/SessionData.dart'; import 'package:servermanager/structs/mod.dart'; import 'package:servermanager/structs/settings.dart'; +import 'package:servermanager/wine.dart'; enum States { Idle, // For when the state machine is waiting for a state change @@ -145,7 +145,7 @@ class StateMachine { conanArgs, workingDirectory: settings.getServerPath()); } else { - runDetachedProton( + runDetachedWine( PathHelper.combine( settings.getServerPath(), "ConanSandboxServer.exe"), conanArgs, diff --git a/lib/structs/serversettings.dart b/lib/structs/serversettings.dart index 9041d93..dbe97aa 100644 --- a/lib/structs/serversettings.dart +++ b/lib/structs/serversettings.dart @@ -7,19 +7,22 @@ class ServerSettings { final int RconPort; final int GamePort; final int QueryPort; + final int WrapperPort; const ServerSettings( {required this.RconPassword, required this.RconPort, required this.GamePort, - required this.QueryPort}); + required this.QueryPort, + required this.WrapperPort}); static ServerSettings deserialize(CompoundTag tag) { return ServerSettings( RconPassword: tag.get(TAG_PASSWORD)?.asString() ?? "", RconPort: tag.get(TAG_RCON_PORT)?.asInt() ?? 25565, GamePort: tag.get(TAG_GAME_PORT)?.asInt() ?? 0, - QueryPort: tag.get(TAG_QUERY_PORT)?.asInt() ?? 0); + QueryPort: tag.get(TAG_QUERY_PORT)?.asInt() ?? 0, + WrapperPort: tag.get(TAG_WRAPPER_PORT)?.asInt() ?? 25306); } CompoundTag serialize() { @@ -28,6 +31,7 @@ class ServerSettings { tag.put(TAG_RCON_PORT, IntTag.valueOf(RconPort)); tag.put(TAG_GAME_PORT, IntTag.valueOf(GamePort)); tag.put(TAG_QUERY_PORT, IntTag.valueOf(QueryPort)); + tag.put(TAG_WRAPPER_PORT, IntTag.valueOf(WrapperPort)); return tag; } @@ -37,4 +41,5 @@ class ServerSettings { static const TAG_RCON_PORT = "rcon"; static const TAG_GAME_PORT = "game"; static const TAG_QUERY_PORT = "query"; + static const TAG_WRAPPER_PORT = "wrapper"; } diff --git a/lib/structs/settings.dart b/lib/structs/settings.dart index 37e83fd..6b3acaa 100644 --- a/lib/structs/settings.dart +++ b/lib/structs/settings.dart @@ -15,8 +15,7 @@ import 'package:servermanager/statemachine.dart'; import 'package:servermanager/structs/credentials.dart'; import 'package:servermanager/structs/mod.dart'; import 'package:servermanager/structs/settingsEntry.dart'; - -import '../proton.dart'; +import 'package:servermanager/wine.dart'; class Settings { final String windows = @@ -27,9 +26,6 @@ class Settings { final String Base2FAPath = "https://github.com/zontreck/steamcmd-2fa/releases/download/0.2.0/steamcmd-2fa"; - final String PROTON_URL = - "https://github.com/GloriousEggroll/proton-ge-custom/releases/download/GE-Proton9-5/GE-Proton9-5.tar.gz"; - Settings._(); static final Settings Instance = Settings._(); @@ -37,7 +33,6 @@ class Settings { String steamcmd_path = ""; String game_path = ""; - String proton_path = ""; String base_path = ""; bool FTS = true; Credentials serverLoginCreds = @@ -56,7 +51,6 @@ class Settings { CompoundTag tag = CompoundTag(); tag.put("steamcmd", StringTag.valueOf(steamcmd_path)); tag.put("game", StringTag.valueOf(game_path)); - tag.put("proton", StringTag.valueOf(proton_path)); tag.put("base", StringTag.valueOf(base_path)); NbtUtils.writeBoolean(tag, "fts", FTS); @@ -79,7 +73,6 @@ class Settings { steamcmd_path = tag.get("steamcmd")!.asString(); game_path = tag.get("game")!.asString(); - proton_path = tag.get("proton")!.asString(); base_path = tag.get("proton")!.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 @@ -170,18 +163,6 @@ class Settings { return PathHelper(pth: base_path).resolve("mods.jail").build(); } - String getProtonPath() { - return PathHelper(pth: base_path).resolve("proton").build(); - } - - String getProtonExecutablePath() { - return PathHelper(pth: base_path) - .resolve("proton") - .resolve("GE-Proton9-5") - .resolve("proton") - .build(); - } - Future createModFolderIfNotExists() async { if (Directory(getModPath()).existsSync()) { return; @@ -269,10 +250,6 @@ class Settings { flush: true, mode: FileMode.writeOnly); } - Future initializeProtonPrefix() async { - runProton("echo", ["hello"]); - } - Future sendRconCommand(String command) async { try { createSocket("127.0.0.1", port: inst!.serverSettings.RconPort); @@ -289,19 +266,13 @@ class Settings { } } - Future initializeProton() async { - Dio dio = Dio(); - print("Downloading proton..."); - final path = PathHelper(pth: getProtonPath()).resolve("proton.tar.gz"); - await dio.download(PROTON_URL, path.build()); - - String oldWD = Directory.current.path; - Directory.current = getProtonPath(); - Process.runSync("tar", ["-xvf", "proton.tar.gz"]); - Process.runSync("rm", ["-f", "proton.tar.gz"]); - - Directory.current = oldWD; // Restore the old working directory - print("Finished!"); + Future initializeWine() async { + await runWinetrick("win10"); + await runWinetrick("vcrun2015"); + await runWinetrick("vcrun2017"); + await runWinetrick("vcrun2019"); + await runWinetrick("vcrun2022"); + await runWinetrick("corefonts"); } Future initializeSteamCmd() async { @@ -377,9 +348,6 @@ class Settings { Process.runSync("touch", ["cxinit"]); Process.runSync("./steamcmd.sh", ["+quit"]); - - print("Completed. Initializing Proton"); - await initializeProton(); } Directory.current = Directory(game_path); diff --git a/lib/structs/settingsEntry.dart b/lib/structs/settingsEntry.dart index 270ec83..1ef91df 100644 --- a/lib/structs/settingsEntry.dart +++ b/lib/structs/settingsEntry.dart @@ -18,7 +18,8 @@ class SettingsEntry { RconPassword: "Password01234", RconPort: 7779, GamePort: 7780, - QueryPort: 7782); + QueryPort: 7782, + WrapperPort: 25306); static SettingsEntry deserialize(CompoundTag tag) { SettingsEntry st = SettingsEntry(); diff --git a/lib/proton.dart b/lib/wine.dart similarity index 56% rename from lib/proton.dart rename to lib/wine.dart index ff210a8..6216c7a 100644 --- a/lib/proton.dart +++ b/lib/wine.dart @@ -4,7 +4,7 @@ import 'package:libac_dart/utils/IOTools.dart'; import 'package:servermanager/statemachine.dart'; import 'package:servermanager/structs/settings.dart'; -Future runProton(String command, List argx) async { +Future runWine(String command, List argx) async { Settings settings = Settings(); Directory dir = Directory(PathHelper.builder(settings.base_path).resolve("pfx").build()); @@ -15,15 +15,14 @@ Future runProton(String command, List argx) async { await dir.create(recursive: true); Map env = Map.from(Platform.environment); - env["STEAM_COMPAT_CLIENT_INSTALL_PATH"] = "~/.steam"; - env["STEAM_COMPAT_DATA_PATH"] = dir.path; + env["WINEPREFIX"] = dir.path; try { - List args = ["run", command]; + List args = [command]; args.addAll(argx); ProcessResult res = await Process.run( - settings.getProtonExecutablePath(), + "wine", args, // Run arbitrary command with arguments environment: env, ); @@ -36,7 +35,37 @@ Future runProton(String command, List argx) async { } } -Future runDetachedProton( +Future runWinetrick(String trick) async { + Settings settings = Settings(); + Directory dir = + Directory(PathHelper.builder(settings.base_path).resolve("pfx").build()); + + if (dir.existsSync()) { + await dir.delete(recursive: true); + } + await dir.create(recursive: true); + + Map env = Map.from(Platform.environment); + env["WINEPREFIX"] = dir.path; + + try { + List args = ["-q", trick]; + + ProcessResult res = await Process.run( + "winetricks", + args, // Run arbitrary command with arguments + environment: env, + ); + + print('Exit code: ${res.exitCode}'); + print('stdout: ${res.stdout}'); + print('stderr: ${res.stderr}'); + } catch (e) { + print('Error executing command: $e'); + } +} + +Future runDetachedWine( String command, List argx, String workingDir) async { Settings settings = Settings(); Directory dir = @@ -48,15 +77,14 @@ Future runDetachedProton( await dir.create(recursive: true); Map env = Map.from(Platform.environment); - env["STEAM_COMPAT_CLIENT_INSTALL_PATH"] = "~/.steam"; - env["STEAM_COMPAT_DATA_PATH"] = dir.path; + env["WINEPREFIX"] = dir.path; try { - List args = ["run", command]; + List args = [command]; args.addAll(argx); - StateMachine.PROC = await Process.start(settings.getProtonExecutablePath(), - args, // Run arbitrary command with arguments + StateMachine.PROC = await Process.start( + "wine", args, // Run arbitrary command with arguments environment: env, workingDirectory: workingDir, mode: ProcessStartMode.normal); diff --git a/pubspec.yaml b/pubspec.yaml index 9567394..72c5a7a 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.22 + version: 1.0.26 dev_dependencies: flutter_test: