140 lines
8.4 KiB
C#
140 lines
8.4 KiB
C#
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 / 2–8 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);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|