285 lines
11 KiB
Dart
285 lines
11 KiB
Dart
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: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<SteamCMD> {
|
|
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<int>;
|
|
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<int>;
|
|
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.inst!.steam_creds);
|
|
if (creds != null) {
|
|
Credentials cred = creds as Credentials;
|
|
setState(() {
|
|
settings.inst!.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;
|
|
},
|
|
));
|
|
}
|
|
}
|