Files

140 lines
8.4 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.IO;
using System.IO.Compression;
using System.Drawing;
using System.Diagnostics;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows.Forms;
internal sealed class Setup : Form
{
Label status;
TextBox destination;
Button install;
ProgressBar progress;
CheckBox shortcut;
bool busy;
string installed;
static readonly Color Mint = Color.FromArgb(119, 223, 199);
[STAThread] static int Main(string[] args)
{
try
{
Application.EnableVisualStyles();
if (args.Length >= 2 && args[0] == "--test")
{
Install(args[1], Console.WriteLine, args.Length > 2 ? args[2] : null);
return 0;
}
using (var form = new Setup())
{
if (args.Length == 2 && args[0] == "--preview")
{
form.Show(); Application.DoEvents();
using (var bmp = new Bitmap(form.Width, form.Height)) { form.DrawToBitmap(bmp, new Rectangle(0, 0, form.Width, form.Height)); bmp.Save(args[1]); }
return 0;
}
Application.Run(form);
}
return 0;
}
catch (Exception ex) { Console.Error.WriteLine(ex); return 1; }
}
Setup()
{
Text = "BLOCKLINE / Setup"; ClientSize = new Size(780, 540);
BackColor = Color.FromArgb(10, 23, 31); ForeColor = Color.White;
Font = new Font("Segoe UI", 10); StartPosition = FormStartPosition.CenterScreen;
FormBorderStyle = FormBorderStyle.FixedSingle; MaximizeBox = false;
AddLabel("B / L • LOCAL OPERATIONS", 35, 28, 12, Mint);
AddLabel("DEIN NÄCHSTES MATCH.\nEINEN KLICK ENTFERNT.", 35, 72, 27, Color.White, 680, 95);
AddLabel("BLOCKLINE / RELAY DISTRICT", 35, 184, 13, Mint);
AddLabel("01 SPIELDATEIEN → 02 ENGINE → 03 SPIELBEREIT", 35, 222, 10, Color.Silver);
AddLabel("INSTALLATIONSORDNER", 35, 268, 9, Mint);
destination = new TextBox { Left = 35, Top = 293, Width = 600, Text = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "BLOCKLINE"), BackColor = Color.FromArgb(31, 50, 59), ForeColor = Color.White, BorderStyle = BorderStyle.FixedSingle };
Controls.Add(destination);
var browse = new Button { Left = 645, Top = 290, Width = 100, Height = 30, Text = "Ändern" };
browse.Click += delegate { using (var dialog = new FolderBrowserDialog()) { if (dialog.ShowDialog() == DialogResult.OK) destination.Text = Path.Combine(dialog.SelectedPath, "BLOCKLINE"); } };
Controls.Add(browse);
shortcut = new CheckBox { Left = 35, Top = 333, Width = 500, Text = "Desktop-Verknüpfung erstellen", Checked = true }; Controls.Add(shortcut);
progress = new ProgressBar { Left = 35, Top = 383, Width = 710, Height = 5 }; Controls.Add(progress);
status = AddLabel("Godot wird automatisch geladen. Danach auch offline spielbar.", 35, 404, 10, Color.Silver);
install = new Button { Left = 475, Top = 455, Width = 270, Height = 48, Text = "INSTALLIEREN →", FlatStyle = FlatStyle.Flat, BackColor = Mint, ForeColor = Color.FromArgb(10, 23, 31) };
install.Click += async delegate
{
if (installed != null) { Process.Start(new ProcessStartInfo(Path.Combine(installed, "Start-Game.exe"), "--local") { WorkingDirectory = installed }); Close(); return; }
busy = true; install.Enabled = false; destination.Enabled = false; browse.Enabled = false; shortcut.Enabled = false;
progress.Style = ProgressBarStyle.Marquee;
try
{
string target = Path.GetFullPath(destination.Text);
await Task.Run(() => Install(target, message => BeginInvoke((Action)(() => status.Text = message)), null));
installed = target;
status.Text = "Bereit für Relay District. Installation erfolgreich.";
if (shortcut.Checked)
{
try { CreateShortcut(target); }
catch { status.Text = "Spiel installiert. Desktop-Link konnte nicht erstellt werden."; }
}
install.Text = "JETZT SPIELEN →"; progress.Style = ProgressBarStyle.Blocks; progress.Value = 100;
}
catch (Exception ex) { status.Text = "Installation fehlgeschlagen. Erneut versuchen."; MessageBox.Show(ex.Message, "BLOCKLINE Setup", MessageBoxButtons.OK, MessageBoxIcon.Error); destination.Enabled = true; browse.Enabled = true; shortcut.Enabled = true; }
finally { busy = false; install.Enabled = true; }
};
Controls.Add(install);
AddLabel("LAN / 28 SPIELER\nKeine Anmeldung erforderlich", 35, 457, 10, Color.Silver, 390, 55);
FormClosing += delegate(object sender, FormClosingEventArgs e) { if (busy) e.Cancel = true; };
}
Label AddLabel(string text, int x, int y, int size, Color color, int width = 710, int height = 32)
{
var label = new Label { Text = text, Left = x, Top = y, Width = width, Height = height, Font = new Font("Segoe UI", size), ForeColor = color }; Controls.Add(label); return label;
}
static void CreateShortcut(string target)
{
dynamic shell = Activator.CreateInstance(Type.GetTypeFromProgID("WScript.Shell"));
dynamic link = shell.CreateShortcut(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), "BLOCKLINE.lnk"));
link.TargetPath = Path.Combine(target, "Start-Game.exe"); link.Arguments = "--local"; link.WorkingDirectory = target; link.Save();
}
internal static void Install(string target, Action<string> status, string archive)
{
target = Path.GetFullPath(target).TrimEnd(Path.DirectorySeparatorChar);
if (Directory.Exists(target) || File.Exists(target)) throw new IOException("Ziel existiert bereits. Bitte einen neuen Installationsordner wählen. Bestehende Dateien bleiben erhalten.");
string parent = Path.GetDirectoryName(target);
Directory.CreateDirectory(parent);
string stage = Path.Combine(parent, ".blockline-setup-" + Guid.NewGuid().ToString("N"));
Directory.CreateDirectory(stage);
try
{
status("Spieldateien werden installiert …");
using (var resource = Assembly.GetExecutingAssembly().GetManifestResourceStream("payload.zip"))
using (var zip = new ZipArchive(resource, ZipArchiveMode.Read))
foreach (var entry in zip.Entries)
{
string path = Path.GetFullPath(Path.Combine(stage, entry.FullName));
if (!path.StartsWith(stage + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase)) throw new InvalidDataException("Ungültiger Paketpfad.");
if (entry.FullName.EndsWith("/")) continue;
Directory.CreateDirectory(Path.GetDirectoryName(path)); entry.ExtractToFile(path);
}
EngineBootstrap.Install(stage, status, archive);
status("Texturen, Modelle und Spielcode werden vorbereitet …");
string logs = Path.Combine(stage, "logs"); Directory.CreateDirectory(logs);
string log = Path.Combine(logs, "setup-import.log");
var info = new ProcessStartInfo(Path.Combine(stage, "tools/godot/Godot_v4.5-stable_win64_console.exe"), "--headless --editor --import --quit --path \"" + stage + "\" --log-file \"" + log + "\"");
info.UseShellExecute = false; info.CreateNoWindow = true; info.WorkingDirectory = stage;
using (var process = Process.Start(info))
{
if (!process.WaitForExit(180000)) { process.Kill(); throw new TimeoutException("Import dauert zu lange."); }
if (process.ExitCode != 0 || !File.Exists(log) || File.ReadAllText(log).Contains("SCRIPT ERROR")) throw new IOException("Spielimport fehlgeschlagen. Installation wurde nicht aktiviert.");
}
Directory.Move(stage, target);
status("Installation abgeschlossen.");
}
finally
{
// Only remove the freshly created staging folder, never an existing install.
if (Path.GetDirectoryName(stage) == parent && Path.GetFileName(stage).StartsWith(".blockline-setup-") && Directory.Exists(stage)) Directory.Delete(stage, true);
}
}
}