import 'dart:io'; import 'package:archive/archive_io.dart'; import 'package:dio/dio.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:hive_flutter/adapters.dart'; import 'package:servermanager/credentials.dart'; import 'package:servermanager/dialogbox.dart'; import 'package:servermanager/settings.dart'; class SteamCMD extends StatefulWidget { Settings settings; SteamCMD({super.key, required this.settings}); @override SteamCMDState createState() => SteamCMDState(settings: settings); } class SteamCMDState extends State { final String windows = "https://steamcdn-a.akamaihd.net/client/installer/steamcmd.zip"; final String linux = "https://steamcdn-a.akamaihd.net/client/installer/steamcmd_linux.tar.gz"; final String Base2FAPath = "https://github.com/zontreck/steamcmd-2fa/releases/download/0.2.0/steamcmd-2fa"; Settings settings = Settings(); SteamCMDState({required this.settings}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Conan Exiles Server Manager - Steam Command"), backgroundColor: Color.fromARGB(255, 100, 0, 0), ), body: SingleChildScrollView( child: Column( children: [ ListTile( title: Text("Download/Initialize SteamCmd"), leading: Icon(CupertinoIcons.cloud_download), subtitle: Text( "Creates the steamcmd folder, and downloads the steamcmd bootstrap. Then performs the initial update."), onTap: () { showDialog( context: context, builder: (X) => InputBox( "", promptText: "This action will delete any existing copy of SteamCMD and download a fresh copy. \nAre you sure?", changed: (X) {}, onSubmit: () async { // Yes, Proceed var x = Directory(settings.steamcmd_path); try { await x.delete(recursive: true); } catch (e) {} await x.create(recursive: true); Directory.current = Directory(settings.steamcmd_path); final dio = Dio(); Process proc; if (Platform.isWindows) { // Download zip file final path = settings.steamcmd_path + Platform.pathSeparator + "windows.zip"; final reply = await dio.download(windows, path); final bytes = File(path).readAsBytesSync(); final arc = ZipDecoder().decodeBytes(bytes); for (final file in arc) { final name = file.name; if (file.isFile) { final data = file.content as List; File(name) ..createSync(recursive: true) ..writeAsBytesSync(data); } else { Directory(name).create(recursive: true); } } Process.runSync("echo", ["X", ">", "cxinit"]); proc = await Process.start("steamcmd.exe", ["+quit"]); } else { // Download tgz file final path = settings.steamcmd_path + Platform.pathSeparator + "linux.tgz"; final reply = await dio.download(linux, path); final bytes = File(path).readAsBytesSync(); final arc = GZipDecoder().decodeBytes(bytes); final arc2 = TarDecoder().decodeBytes(arc); for (final file in arc2) { final name = file.name; if (file.isFile) { final data = file.content as List; File(name) ..createSync(recursive: true) ..writeAsBytesSync(data); } else { Directory(name).create(recursive: true); } } Process.runSync("chmod", ["+x", "steamcmd.sh"]); Process.runSync( "chmod", ["+x", "linux32/steamcmd"]); Process.runSync("touch", ["cxinit"]); proc = await Process.start("./steamcmd.sh", ["+quit"]); } Directory.current = Directory(settings.game_path); }, onCancel: () {}, isDefault: false, hasInputField: false, )); }, ), ListTile( title: Text("Download SteamCmd-2fa"), leading: Icon(CupertinoIcons.lock_shield_fill), subtitle: Text( "Downloads a modified version of steamcmd-2fa from https://github.com/zontreck/steamcmd-2fa"), onTap: () async { final dio = Dio(); await dio.download( Base2FAPath + (Platform.isWindows ? ".exe" : ""), settings.steamcmd_path + Platform.pathSeparator + (Platform.isWindows ? "steamcmd-2fa.exe" : "steamcmd-2fa")); if (!Platform.isWindows) var proc = await Process.start("chmod", [ "+x", settings.steamcmd_path + Platform.pathSeparator + "steamcmd-2fa" ]); }), ListTile( title: Text("Credentials"), leading: Icon(Icons.key_sharp), subtitle: Text("Steam Credentials"), onTap: () async { var creds = await Navigator.pushNamed(context, "/steamcmd/creds", arguments: settings.steam_creds); if (creds != null) { Credentials cred = creds as Credentials; setState(() { settings.steam_creds = cred; settings.Write(); }); } }, ), ], )), ); } } // Returns a Credentials Object class CredentialsPrompt extends StatelessWidget { TextEditingController username = TextEditingController(); TextEditingController password = TextEditingController(); TextEditingController secret = TextEditingController(); bool initialInitDone = false; @override Widget build(BuildContext context) { final args = ModalRoute.of(context)!.settings.arguments as Credentials?; if (args != null) { if (!initialInitDone) { username.text = args.username; password.text = args.password; secret.text = args.secret; initialInitDone = true; } } return Scaffold( appBar: AppBar( title: Text("Conan Exiles Server Manager - Steam Command - Credentials"), backgroundColor: Color.fromARGB(255, 100, 0, 0), ), body: WillPopScope( child: SingleChildScrollView( padding: EdgeInsets.all(16), child: Column( children: [ Row( children: [ SizedBox( width: 150, child: Row( children: [ Icon(Icons.person), Text("Username:"), ], )), Expanded( child: TextField( controller: username, decoration: InputDecoration( border: OutlineInputBorder( borderRadius: BorderRadius.circular(4))), ), ) ], ), SizedBox( height: 16, ), Row( children: [ SizedBox( width: 150, child: Row( children: [ Icon(Icons.key), Text("Password:"), ], )), Expanded( child: TextField( controller: password, keyboardType: TextInputType.visiblePassword, decoration: InputDecoration( border: OutlineInputBorder( borderRadius: BorderRadius.circular(4))), ), ) ], ), SizedBox( height: 16, ), Row( children: [ SizedBox( width: 150, child: Row( children: [ Icon(Icons.dangerous), Text("Secret:"), ], )), Expanded( child: TextField( controller: secret, keyboardType: TextInputType.visiblePassword, decoration: InputDecoration( border: OutlineInputBorder( borderRadius: BorderRadius.circular(4)), hintText: "2FA Shared Secret Code (Do Not Share With Others!)"), )) ], ) ], )), onWillPop: () async { Navigator.pop( context, Credentials( username: username.text, password: password.text, secret: secret.text)); return true; }, )); } }