Kursach_StealthAction/Assets/Tremble/Utils/TrenchBroomUtil.cs
2026-10-11 19:16:11 +03:00

237 lines
6.5 KiB
C#

//
// This file is part of the Tremble package by Tiny Goose.
// Copyright (c) 2024-2026 TinyGoose Ltd., All Rights Reserved.
//
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace TinyGoose.Tremble
{
public static class TrenchBroomUtil
{
private static string TrenchBroomPathFromPrefs
{
#if UNITY_EDITOR
get => EditorPrefs.GetString("Tremble_TBPath", null);
set => EditorPrefs.SetString("Tremble_TBPath", value);
#else
get => PlayerPrefs.GetString("Tremble_TBPath", null);
set => PlayerPrefs.SetString("Tremble_TBPath", value);
#endif
}
public static string TrenchBroomPath
{
get
{
// First look for a running Trenchbroom
Process[] procs = Process.GetProcessesByName("trenchbroom");
if (procs.Length > 0 && procs[0].MainModule != null)
{
TrenchBroomPathFromPrefs = procs[0].MainModule.FileName;
return procs[0].MainModule.FileName;
}
// Not running - try a path we previously knew about
string path = TrenchBroomPathFromPrefs;
if (path != null && File.Exists(path))
return path;
return null;
}
private set => TrenchBroomPathFromPrefs = value;
}
public static bool IsTrenchBroomRunning
{
get
{
Process proc = Process.GetProcessesByName("trenchbroom").FirstOrDefault();
if (proc == null)
return false;
TrenchBroomPath = proc.MainModule.FileName;
return true;
}
}
public static bool DoesEnginePathExistInTrenchBroomPrefs()
{
string preferencesFile = Path.Combine(GetTrenchBroomConfigFolder(), "Preferences.json");
string key = $"Games/{TrembleConsts.GAME_NAME}/Path";
if (!File.Exists(preferencesFile))
return false;
// Read in current config
foreach (string line in File.ReadLines(preferencesFile))
{
string trimmedLine = line.Trim(' ', ',');
// Ignore braces and empty lines
if (trimmedLine.IsNullOrEmpty() || trimmedLine is "{" or "}")
continue;
// Existing path? - patch it!
if (trimmedLine.StartsWith($"\"{key}\""))
return true;
}
return false;
}
public static async Task<bool> WriteEnginePathIntoTrenchBroomPrefs()
{
// I didn't want to import a JSON library so - this is it.
// Read each line into an array (ignore the braces) and remove the commas.
// Find if there's a current path - if so, patch it up.
// if not, add a new one at the end.
string preferencesFile = Path.Combine(GetTrenchBroomConfigFolder(), "Preferences.json");
string key = $"Games/{TrembleConsts.GAME_NAME}/Path";
string projectFolderUnix = Directory.GetCurrentDirectory().Replace('\\', '/');
string entry = $"\"{key}\": \"{projectFolderUnix}\"";
bool wasPatched = false;
List<string> configLines = new();
if (File.Exists(preferencesFile))
{
// Read in current config
foreach (string line in File.ReadLines(preferencesFile))
{
string trimmedLine = line.Trim(' ', ',');
// Ignore braces and empty lines
if (trimmedLine.IsNullOrEmpty() || trimmedLine is "{" or "}")
continue;
// Existing path? - patch it!
if (trimmedLine.StartsWith($"\"{key}\""))
{
configLines.Add(entry);
wasPatched = true;
continue;
}
configLines.Add(trimmedLine);
}
}
if (!wasPatched)
{
// We didn't find the game - append to the end (before close brace)
configLines.Add(entry);
}
// Write out new config
for (int lineIdx = 0; lineIdx < configLines.Count; lineIdx++)
{
// Indent
configLines[lineIdx] = $" {configLines[lineIdx]}";
// Add commas (not on the last one!)
if (lineIdx < configLines.Count - 1)
{
configLines[lineIdx] += ",";
}
}
configLines.Insert(0, "{");
configLines.Add("}");
DirectoryUtil.CreateAllDirectories(preferencesFile);
await File.WriteAllLinesAsync(preferencesFile, configLines);
return !wasPatched;
}
private static string GetTrenchBroomConfigFolder() =>
Application.platform switch
{
RuntimePlatform.OSXEditor or RuntimePlatform.OSXPlayer
=> Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Library", "Application Support", "TrenchBroom"),
RuntimePlatform.WindowsEditor or RuntimePlatform.WindowsPlayer
=> Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "TrenchBroom"),
RuntimePlatform.LinuxEditor or RuntimePlatform.LinuxPlayer
=> Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".TrenchBroom"),
_ => throw new ArgumentOutOfRangeException(nameof(Application.platform), "Unknown platform!")
};
public static string GetGameFolder() => Path.Combine(GetTrenchBroomConfigFolder(), "games", "Unity", Application.productName);
public static void OpenWithTrenchBroom(string mapFile)
{
switch (Application.platform)
{
case RuntimePlatform.OSXEditor:
case RuntimePlatform.OSXPlayer:
RunCommand($"open -a TrenchBroom '{mapFile}'");
break;
case RuntimePlatform.WindowsEditor:
case RuntimePlatform.WindowsPlayer:
// Sad. On Windows, TB is mostly portable so we may have to just show the file in Explorer, lol
if (TrenchBroomPath != null)
{
RunCommand($"\"{TrenchBroomPath}\" \"{mapFile}\"", useShell: false);
}
else
{
#if UNITY_EDITOR
EditorUtility.DisplayDialog(
title: "Where's TrenchBroom?",
message: "Tremble could not find TrenchBroom. Ensure TrenchBroom is installed and " +
"running, and Tremble will make a note of where it's installed for next time." +
" For now, I'll show your map in Explorer.", "Okay");
#endif
RunCommand($"explorer /select, \"{mapFile}\"");
}
break;
case RuntimePlatform.LinuxEditor:
case RuntimePlatform.LinuxPlayer:
RunCommand($"/usr/bin/trenchbroom '{mapFile}'");
break;
}
}
private static void RunCommand(string command, bool useShell = true)
{
command.Split(' ', out string exe, out string args);
#if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN
// Windows Command Prompt
if (useShell)
{
args = $"/c \"{exe} {args}\"";
exe = "cmd.exe";
}
#else
// Under macOS and Linux we assume /bin/sh is a thing
if (useShell)
{
args = $"-c \"{exe} {args}\"";
exe = "/bin/sh";
}
#endif
Process.Start(new ProcessStartInfo(exe, args) { WorkingDirectory = Directory.GetCurrentDirectory() });
}
}
}