-
Notifications
You must be signed in to change notification settings - Fork 38
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Finished automatic swinfo generation
- Loading branch information
1 parent
cf7bd58
commit 0b661fd
Showing
4 changed files
with
247 additions
and
93 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
using System; | ||
using System.IO; | ||
using System.Linq; | ||
using System.Reflection; | ||
using BepInEx; | ||
using BepInEx.Logging; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CSharp; | ||
using Newtonsoft.Json.Linq; | ||
|
||
namespace SpaceWarpPatcher; | ||
|
||
internal static class PathsGenerator | ||
{ | ||
|
||
|
||
|
||
private static (string name, string path) GetNameAndPath(FileInfo jsonFile) | ||
{ | ||
var path = '"' + jsonFile.Directory.FullName.Replace("\"","\\\"").Replace("\\","\\\\") + '"'; | ||
var obj = JObject.Parse(File.ReadAllText(jsonFile.FullName)); | ||
var id = obj["mod_id"].Value<string>(); | ||
var replaced = id.Replace(".", "_").Replace(" ", "_"); | ||
return (replaced, path); | ||
} | ||
private static bool IsDisabled(FileInfo jsonFile, string[] allDisabled) | ||
{ | ||
var obj = JObject.Parse(File.ReadAllText(jsonFile.FullName)); | ||
if (!obj.ContainsKey("spec")) return false; | ||
if (obj["spec"].Value<string>() is "1.2" or "1.0") return false; | ||
return !allDisabled.Contains(obj["mod_id"].Value<string>()); | ||
} | ||
internal static void GenerateSpaceWarpPathsDLL(bool changed, ManualLogSource trueLogger) | ||
{ | ||
var cacheLocation = Path.Combine(Paths.BepInExRootPath, "AssemblyCache"); | ||
|
||
try | ||
{ | ||
var addressablePaths = Path.Combine(cacheLocation, "SpaceWarpPaths.dll"); | ||
if (changed || !File.Exists(addressablePaths)) | ||
{ | ||
// Preload newtonsoft.json | ||
try | ||
{ | ||
Assembly.LoadFile(Path.Combine(Paths.ManagedPath, "Newtonsoft.Json.dll")); | ||
} | ||
catch (Exception e) | ||
{ | ||
trueLogger.LogError(e); | ||
} | ||
|
||
var disabledPluginsFilepath = Path.Combine(Paths.BepInExRootPath, "disabled_plugins.cfg"); | ||
var allDisabled = File.ReadAllText(disabledPluginsFilepath) | ||
.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); | ||
var allSwinfos = | ||
new DirectoryInfo(Path.Combine(Paths.BepInExRootPath, "plugins")) | ||
.EnumerateFiles("swinfo.json", SearchOption.AllDirectories).Where(x => IsDisabled(x, allDisabled)).Concat(new DirectoryInfo(Path.Combine(Paths.GameRootPath,"GameData","Mods")).EnumerateFiles("swinfo.json",SearchOption.AllDirectories)).Select(GetNameAndPath); | ||
// Now we build the dll | ||
var dll = "public static class SpaceWarpPaths {\n"; | ||
foreach (var swinfo in allSwinfos) | ||
{ | ||
dll += $"public static string {swinfo.name} = {swinfo.path};\n"; | ||
} | ||
|
||
dll += "}"; | ||
trueLogger.LogInfo($"Compiling:\n{dll}"); | ||
var tree = CSharpSyntaxTree.ParseText(dll); | ||
var references = AppDomain.CurrentDomain.GetAssemblies().Where(x => !x.IsDynamic && x.Location.Length > 0) | ||
.Select(x => MetadataReference.CreateFromFile(x.Location)).ToList(); | ||
var compilation = CSharpCompilation.Create("SpaceWarpPaths.dll", new[] { tree },references, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); | ||
var result = compilation.Emit(addressablePaths); | ||
foreach (var diagnostic in result.Diagnostics) | ||
{ | ||
if (diagnostic.WarningLevel == 0) | ||
{ | ||
trueLogger.LogError(diagnostic.Location + ": " + diagnostic); | ||
} | ||
else | ||
{ | ||
trueLogger.LogInfo(diagnostic.Location + ": " + diagnostic); | ||
} | ||
} | ||
|
||
if (!result.Success) | ||
{ | ||
try | ||
{ | ||
File.Delete(addressablePaths); | ||
} | ||
catch | ||
{ | ||
//Ignored | ||
} | ||
|
||
} | ||
} | ||
|
||
Assembly.LoadFile(addressablePaths); | ||
} | ||
catch (Exception e) | ||
{ | ||
trueLogger.LogError(e); | ||
//ignored | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
using System.IO; | ||
using System.Linq; | ||
using System.Security.Cryptography; | ||
using System.Text; | ||
using BepInEx; | ||
using Newtonsoft.Json.Linq; | ||
|
||
namespace SpaceWarpPatcher; | ||
|
||
internal static class SwinfoTransformer | ||
{ | ||
|
||
internal static JObject TransformSwinfo(JObject swinfo, string hash, DirectoryInfo directoryInfo) | ||
{ | ||
var addressables = Path.Combine(directoryInfo.FullName, "addressables"); | ||
string catalog = null; | ||
if (Directory.Exists(addressables)) | ||
{ | ||
var toBecomeCatalog = Path.Combine(addressables, "catalog.json"); | ||
if (File.Exists(toBecomeCatalog)) | ||
{ | ||
catalog = toBecomeCatalog; | ||
} | ||
} | ||
|
||
string entryPoint = swinfo.TryGetValue("EntryPoint", out var value) ? value.Value<string>() : null; | ||
if (entryPoint != null) { | ||
var dll = directoryInfo.EnumerateFiles("*.dll", SearchOption.TopDirectoryOnly).FirstOrDefault(); | ||
if (dll != null) | ||
{ | ||
entryPoint = dll.FullName; | ||
} | ||
} | ||
|
||
JObject target = new JObject(); | ||
if (catalog == null) | ||
{ | ||
if (entryPoint == null) | ||
{ | ||
target["APIVersion"] = "0.0.1.1"; | ||
target["ModVersion"] = swinfo["version"]; | ||
target["ModName"] = swinfo["name"]; | ||
target["ModAuthor"] = swinfo["author"]; | ||
target["ModDescription"] = swinfo["description"]; | ||
target["Hash"] = hash; | ||
} | ||
else | ||
{ | ||
target["APIVersion"] = "0.0.1.1"; | ||
target["ModVersion"] = swinfo["version"]; | ||
target["ModName"] = swinfo["name"]; | ||
target["ModAuthor"] = swinfo["author"]; | ||
target["ModDescription"] = swinfo["description"]; | ||
target["EntryPoint"] = entryPoint; | ||
target["Hash"] = hash; | ||
} | ||
} | ||
else | ||
{ | ||
if (entryPoint == null) | ||
{ | ||
target["APIVersion"] = "0.0.1.1"; | ||
target["ModVersion"] = swinfo["version"]; | ||
target["ModName"] = swinfo["name"]; | ||
target["ModAuthor"] = swinfo["author"]; | ||
target["ModDescription"] = swinfo["description"]; | ||
target["Catalog"] = catalog; | ||
target["Hash"] = hash; | ||
} | ||
else | ||
{ | ||
target["APIVersion"] = "0.0.1.1"; | ||
target["ModVersion"] = swinfo["version"]; | ||
target["ModName"] = swinfo["name"]; | ||
target["ModAuthor"] = swinfo["author"]; | ||
target["ModDescription"] = swinfo["description"]; | ||
target["EntryPoint"] = entryPoint; | ||
target["Catalog"] = catalog; | ||
target["Hash"] = hash; | ||
} | ||
} | ||
|
||
return target; | ||
} | ||
|
||
private static byte[] GetHash(string inputString) | ||
{ | ||
using (HashAlgorithm algorithm = SHA256.Create()) | ||
return algorithm.ComputeHash(Encoding.UTF8.GetBytes(inputString)); | ||
} | ||
|
||
private static string GetHashString(string inputString) | ||
{ | ||
StringBuilder sb = new StringBuilder(); | ||
foreach (byte b in GetHash(inputString)) | ||
sb.Append(b.ToString("X2")); | ||
|
||
return sb.ToString(); | ||
} | ||
|
||
internal static void TransformModSwinfos() | ||
{ | ||
var allSwinfos = | ||
new DirectoryInfo(Path.Combine(Paths.GameRootPath, "GameData", "Mods")).EnumerateFiles("swinfo.json", | ||
SearchOption.AllDirectories); | ||
foreach (var swinfo in allSwinfos) | ||
{ | ||
var directory = swinfo.Directory!; | ||
var target = Path.Combine(directory.FullName, "modinfo.json"); | ||
var swinfoText = File.ReadAllText(swinfo.FullName); | ||
var swinfoData = JObject.Parse(swinfoText); | ||
var hash = GetHashString(swinfoText); | ||
var toCompareHash = ""; | ||
if (File.Exists(target)) | ||
{ | ||
var targetModInfo = JObject.Parse(File.ReadAllText(target)); | ||
if (targetModInfo.ContainsKey("Hash")) | ||
{ | ||
toCompareHash = (string)(targetModInfo.GetValue("Hash") as JValue)?.Value; | ||
} | ||
else | ||
{ | ||
toCompareHash = hash; | ||
} | ||
} | ||
if (hash == toCompareHash) continue; | ||
File.WriteAllText(target,TransformSwinfo(swinfoData,hash, directory).ToString()); | ||
} | ||
} | ||
} |