9bb4f85802
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
130 lines
4.9 KiB
C#
130 lines
4.9 KiB
C#
using System.Text.Json;
|
|
using System.Text.Json.Nodes;
|
|
|
|
namespace CVRManager.Services;
|
|
|
|
public static class CacheGuardService
|
|
{
|
|
const string AssemblyName = "CVRCacheGuard";
|
|
const string AssemblyFile = AssemblyName + ".dll";
|
|
const int UserAssemblyType = 16;
|
|
|
|
static string Source => Path.Combine(AppContext.BaseDirectory, "CacheGuard");
|
|
|
|
static string Managed(string gameDir) => Path.Combine(gameDir, "ChilloutVR_Data", "Managed");
|
|
|
|
public static void Deploy(string gameDir, Action<string> log, string? source = null)
|
|
{
|
|
var managed = Managed(gameDir);
|
|
var scripting = Path.Combine(gameDir, "ChilloutVR_Data", "ScriptingAssemblies.json");
|
|
var init = Path.Combine(gameDir, "ChilloutVR_Data", "RuntimeInitializeOnLoads.json");
|
|
source ??= Source;
|
|
if (!Directory.Exists(source) || !Directory.Exists(managed) || !File.Exists(scripting) || !File.Exists(init)) return;
|
|
|
|
var changed = false;
|
|
var deps = Path.Combine(managed, AssemblyName);
|
|
Directory.CreateDirectory(deps);
|
|
foreach (var file in Directory.EnumerateFiles(source, "*.dll"))
|
|
{
|
|
var name = Path.GetFileName(file);
|
|
var target = name == AssemblyFile ? Path.Combine(managed, name) : Path.Combine(deps, name);
|
|
changed |= CopyIfDifferent(file, target);
|
|
}
|
|
|
|
var scriptingJson = JsonNode.Parse(File.ReadAllText(scripting))!.AsObject();
|
|
var names = scriptingJson["names"]!.AsArray();
|
|
var types = scriptingJson["types"]!.AsArray();
|
|
if (!names.Any(n => n?.GetValue<string>() == AssemblyFile))
|
|
{
|
|
names.Add(AssemblyFile);
|
|
types.Add(UserAssemblyType);
|
|
WriteJson(scripting, scriptingJson);
|
|
changed = true;
|
|
}
|
|
|
|
var initJson = JsonNode.Parse(File.ReadAllText(init))!.AsObject();
|
|
var root = initJson["root"]!.AsArray();
|
|
if (!root.Any(e => e?["assemblyName"]?.GetValue<string>() == AssemblyName))
|
|
{
|
|
root.Add(new JsonObject
|
|
{
|
|
["assemblyName"] = AssemblyName,
|
|
["nameSpace"] = AssemblyName,
|
|
["className"] = "Entry",
|
|
["methodName"] = "Init",
|
|
["loadTypes"] = 2,
|
|
["isUnityClass"] = false,
|
|
});
|
|
WriteJson(init, initJson);
|
|
changed = true;
|
|
}
|
|
if (changed) log("Multi-instance cache guard added to this install.");
|
|
}
|
|
|
|
public static void Remove(string gameDir, Action<string> log)
|
|
{
|
|
var data = Path.Combine(gameDir, "ChilloutVR_Data");
|
|
var scripting = Path.Combine(data, "ScriptingAssemblies.json");
|
|
var init = Path.Combine(data, "RuntimeInitializeOnLoads.json");
|
|
var changed = false;
|
|
|
|
if (File.Exists(scripting))
|
|
{
|
|
var json = JsonNode.Parse(File.ReadAllText(scripting))!.AsObject();
|
|
var names = json["names"]!.AsArray();
|
|
var types = json["types"]!.AsArray();
|
|
for (var i = names.Count - 1; i >= 0; i--)
|
|
if (names[i]?.GetValue<string>() == AssemblyFile)
|
|
{
|
|
names.RemoveAt(i);
|
|
if (i < types.Count) types.RemoveAt(i);
|
|
changed = true;
|
|
}
|
|
if (changed) WriteJson(scripting, json);
|
|
}
|
|
if (File.Exists(init))
|
|
{
|
|
var json = JsonNode.Parse(File.ReadAllText(init))!.AsObject();
|
|
var root = json["root"]!.AsArray();
|
|
var before = root.Count;
|
|
for (var i = root.Count - 1; i >= 0; i--)
|
|
if (root[i]?["assemblyName"]?.GetValue<string>() == AssemblyName) root.RemoveAt(i);
|
|
if (root.Count != before)
|
|
{
|
|
WriteJson(init, json);
|
|
changed = true;
|
|
}
|
|
}
|
|
|
|
var managed = Managed(gameDir);
|
|
try
|
|
{
|
|
File.Delete(Path.Combine(managed, AssemblyFile));
|
|
var deps = Path.Combine(managed, AssemblyName);
|
|
if (Directory.Exists(deps)) Directory.Delete(deps, true);
|
|
}
|
|
catch (Exception e) when (e is IOException or UnauthorizedAccessException) { }
|
|
if (changed) log("Multi-instance cache guard removed from this install.");
|
|
}
|
|
|
|
static bool CopyIfDifferent(string source, string target)
|
|
{
|
|
var s = new FileInfo(source);
|
|
var t = new FileInfo(target);
|
|
if (t.Exists && t.Length == s.Length && t.LastWriteTimeUtc == s.LastWriteTimeUtc) return false;
|
|
try
|
|
{
|
|
File.Copy(source, target, true);
|
|
File.SetLastWriteTimeUtc(target, s.LastWriteTimeUtc);
|
|
return true;
|
|
}
|
|
catch (IOException) when (t.Exists)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static void WriteJson(string path, JsonNode node) =>
|
|
File.WriteAllText(path, node.ToJsonString(new JsonSerializerOptions { WriteIndented = false }), new System.Text.UTF8Encoding(false));
|
|
}
|