diff --git a/App.config b/Src/PlanetbaseFramework/App.config similarity index 100% rename from App.config rename to Src/PlanetbaseFramework/App.config diff --git a/Utils.cs b/Src/PlanetbaseFramework/Common/Utils.cs similarity index 97% rename from Utils.cs rename to Src/PlanetbaseFramework/Common/Utils.cs index aee2225..c3ecd64 100644 --- a/Utils.cs +++ b/Src/PlanetbaseFramework/Common/Utils.cs @@ -17,7 +17,8 @@ public static class Utils /// public static Texture2D ErrorTexture { get; internal set; } - /// + #region Split to ResourceLoaders + /// /// Load the a XML file containing strings (for localization/translations) /// /// The absolute path to the XML file @@ -130,6 +131,9 @@ public static Texture2D LoadPngFromFile(string absolutePath) return loadedTexture; } + #endregion + + /// /// Set the normal map on a texture. This should be called on any normal maps either at the init stage or the constructor of the mod. /// @@ -149,6 +153,7 @@ public static void SetNormalMap(this Texture2D texture) texture.SetPixels(pixels); } + #region Split to Object finder public static T FindObjectByFilename(this List list, string filename) where T : UnityEngine.Object { try @@ -169,8 +174,10 @@ public static T FindObjectByFilepath(this List list, string filepath) wher { return FindObjectByFilename(list, Path.GetFileName(filepath)); } + #endregion - public static bool IsValidTag(this string toCheck) + #region GameObjectExtensions + public static bool IsValidTag(this string toCheck) { try { @@ -184,6 +191,8 @@ public static bool IsValidTag(this string toCheck) public static bool Compare(this Type t1, Type t2) => t1.FullName != null && t1.FullName.Equals(t2.FullName); + #endregion + public static string[] ListEmbeddedFiles() { var assembly = Assembly.GetCallingAssembly(); diff --git a/ModLoaderIgnoreAttribute.cs b/Src/PlanetbaseFramework/Loader/ModLoaderIgnoreAttribute.cs similarity index 100% rename from ModLoaderIgnoreAttribute.cs rename to Src/PlanetbaseFramework/Loader/ModLoaderIgnoreAttribute.cs diff --git a/Modloader.cs b/Src/PlanetbaseFramework/Loader/Modloader.cs similarity index 95% rename from Modloader.cs rename to Src/PlanetbaseFramework/Loader/Modloader.cs index 2ec665b..4f29a0b 100644 --- a/Modloader.cs +++ b/Src/PlanetbaseFramework/Loader/Modloader.cs @@ -11,12 +11,9 @@ namespace PlanetbaseFramework * This is the core class behind loading all mods. The patcher injects calls to loadMods() and updateMods() into the native PB code, which then * calls the methods in this file. This allows for minimal changes to PB's native code, while still allowing it to be extended. */ - public class ModLoader + public static class ModLoader { - /// - /// A list of all mods that have been initialized - /// - public static List ModList = new List(); + public static List InitializedMods = new List(); /// /// Called by the game manager on startup to load in mods @@ -25,6 +22,7 @@ public static void LoadMods() { Debug.Log("Loading mods..."); + // Split to function: LoadAssemblyFiles var modDLLs = new List(); modDLLs.Add(Assembly.GetExecutingAssembly().Location); @@ -46,6 +44,7 @@ public static void LoadMods() foreach (var file in modDLLs) { + // Split to function- LoadTypes() Type[] types; try { @@ -72,6 +71,7 @@ public static void LoadMods() continue; } + // Create method- InjectMods(types) foreach (var type in types) { //Skip if the type isn't a mod diff --git a/OBJLoader.cs b/Src/PlanetbaseFramework/Loader/OBJLoader.cs similarity index 100% rename from OBJLoader.cs rename to Src/PlanetbaseFramework/Loader/OBJLoader.cs diff --git a/StringFile.cs b/Src/PlanetbaseFramework/Loader/StringFile.cs similarity index 100% rename from StringFile.cs rename to Src/PlanetbaseFramework/Loader/StringFile.cs diff --git a/BaseModuleType.cs b/Src/PlanetbaseFramework/Mod/BaseModuleType.cs similarity index 94% rename from BaseModuleType.cs rename to Src/PlanetbaseFramework/Mod/BaseModuleType.cs index ddd45b4..b8024b9 100644 --- a/BaseModuleType.cs +++ b/Src/PlanetbaseFramework/Mod/BaseModuleType.cs @@ -22,7 +22,8 @@ public BaseModuleType(Texture2D icon, GameObject[] moduleObjects) public override GameObject loadPrefab(int sizeIndex) { - int adjustedSizeIndex = sizeIndex - mMinSize; //Takes into account the edge case where mMinSize != 0 + //Takes into account the edge case where mMinSize != 0 + int adjustedSizeIndex = sizeIndex - mMinSize; ModuleObjects[adjustedSizeIndex].calculateSmoothMeshRecursive(mMeshes); diff --git a/FrameworkMod.cs b/Src/PlanetbaseFramework/Mod/FrameworkMod.cs similarity index 100% rename from FrameworkMod.cs rename to Src/PlanetbaseFramework/Mod/FrameworkMod.cs diff --git a/ModBase.cs b/Src/PlanetbaseFramework/Mod/ModBase.cs similarity index 78% rename from ModBase.cs rename to Src/PlanetbaseFramework/Mod/ModBase.cs index d0cf23f..84e61d0 100644 --- a/ModBase.cs +++ b/Src/PlanetbaseFramework/Mod/ModBase.cs @@ -7,122 +7,44 @@ using ICSharpCode.SharpZipLib.Zip; using PlanetbaseFramework.Patches.Planetbase.GameStateTitle; using UnityEngine; +using System.ComponentModel; namespace PlanetbaseFramework { public abstract class ModBase { + public abstract string ModName { get; } + + public virtual Version ModVersion => new Version(0, 0, 0, 0); + public virtual string ModPath => Path.Combine(BasePath, ModName); + public virtual string AssetsPath => Path.Combine(ModPath, "assets"); + public List ModTextures { get; protected set; } public List ModObjects { get; protected set; } - public virtual Version ModVersion => new Version(0, 0, 0, 0); + //Some of you might notice the odd '/' character in this string. This is because native PB code doesn't use Path.DirectorySeparatorChar, causing + //one char to be wrong. I'll fix it at some point after I rewrite the patcher. + public static string BasePath { get; } = Path.Combine(Util.getFilesFolder(), "Mods"); + + private static IResourceUnpacker _resourceUnpacker; private HarmonyInstance Harmony { get; set; } - private static FastZip ZipInstance { get; } = new FastZip(); protected ModBase() { - //Extract embedded assets - ZipConstants.DefaultCodePage = 0; //This is a workaround to get files to extract properly - - var currentAssembly = Assembly.GetCallingAssembly(); - var manifest = currentAssembly.GetManifestResourceNames(); - - PreProcessEmbeddedResources(manifest); - - foreach (var file in manifest) - { - if (!PreProcessEmbeddedResource(file)) continue; - - Debug.Log($"Processing embedded file \"{file}\""); - - using (var resourceStream = currentAssembly.GetManifestResourceStream(file)) - { - switch (Path.GetExtension(file)) - { - case ".zip": - Debug.Log("zip " + GetResourceRelativeFilePath(file)); - ZipInstance.ExtractZip( - resourceStream, - ModPath, - FastZip.Overwrite.Always, - null, - null, - null, - false, - false - ); - break; - default: //Copy the file to a directory matching the name under the mod's folder - var filePath = Path.Combine(ModPath, GetResourceRelativeFilePath(file)); - - Debug.Log($"Loading \"{file}\" to \"{filePath}\""); - - Directory.CreateDirectory(Path.GetDirectoryName(filePath)); - - using (var fileStream = File.Create(filePath)) - { - resourceStream.CopyTo(fileStream); - } - - break; - } - } - } - - try - { - LoadAllStrings("strings"); - } - catch (Exception e) - { - Debug.Log("Failed to load strings files due to exception:"); - Utils.LogException(e); - } - - try - { - ModTextures = LoadAllPngs("png"); - - if (ModTextures.Count > 0) - { - Debug.Log($"Successfully loaded {ModTextures.Count} texture(s)"); - } - } - catch (Exception e) - { - Debug.Log("Failed to load PNG files due to exception:"); - Utils.LogException(e); - } - - try - { - ModObjects = LoadAllObjs("obj"); - - if(ModObjects.Count > 0) - { - Debug.Log($"Successfully loaded {ModObjects.Count} object(s)"); - } - } - catch (Exception e) - { - Debug.Log("Failed to load OBJ files due to exception:"); - Utils.LogException(e); - } + // Consider moving out. + ExtractAssets(); + LoadStrings(); + LoadTextures(); + LoadMeshes(); + SetupUnpackers(); } - public abstract string ModName { get; } - - //Some of you might notice the odd '/' character in this string. This is because native PB code doesn't use Path.DirectorySeparatorChar, causing - //one char to be wrong. I'll fix it at some point after I rewrite the patcher. - public static string BasePath { get; } = Path.Combine(Util.getFilesFolder(), "Mods"); - - public virtual string ModPath => Path.Combine(BasePath, ModName); - - public virtual string AssetsPath => Path.Combine(ModPath, "assets"); - - public virtual void Init() //This is virtual instead of abstract so mods aren't required to implement it. Same with Update below + /// + /// This is virtual instead of abstract so mods aren't required to implement it. Same with Update below + /// + public virtual void Init() { } @@ -226,6 +148,84 @@ protected virtual bool PreProcessEmbeddedResource(string resourceName) return true; } + private static void SetupUnpackers() + { + var resourceUnpacker = new ResourceUnpacker(); + + var zipUnpacker = new ZipUnpacker(); + resourceUnpacker.RegisterUnpacker(zipUnpacker); + + var defaultUnpacker = new NoUnpacker(); + resourceUnpacker.RegisterDefault(defaultUnpacker); + } + + private static void ExtractAssets() + { + var currentAssembly = Assembly.GetCallingAssembly(); + var manifest = currentAssembly.GetManifestResourceNames(); + + PreProcessEmbeddedResources(manifest); + + foreach (var file in manifest) + { + if (!PreProcessEmbeddedResource(file)) continue; + + Debug.Log($"Processing embedded file \"{file}\""); + } + + _resourceUnpacker.Unpack(re) + } + + private static void LoadStrings() + { + // LoadStrings + try + { + LoadAllStrings("strings"); + } + catch (Exception e) + { + Debug.Log("Failed to load strings files due to exception:"); + Utils.LogException(e); + } + } + + private static void LoadTextures() + { + try + { + ModTextures = LoadAllPngs("png"); + + if (ModTextures.Count > 0) + { + Debug.Log($"Successfully loaded {ModTextures.Count} texture(s)"); + } + } + catch (Exception e) + { + Debug.Log("Failed to load PNG files due to exception:"); + Utils.LogException(e); + } + } + + private static void LoadMeshes() + { + try + { + ModObjects = LoadAllObjs("obj"); + + if (ModObjects.Count > 0) + { + Debug.Log($"Successfully loaded {ModObjects.Count} object(s)"); + } + } + catch (Exception e) + { + Debug.Log("Failed to load OBJ files due to exception:"); + Utils.LogException(e); + } + } + private static string GetResourceRelativeFilePath(string resourceName) { //Remove the project name from the path, including the preceding '.' @@ -237,5 +237,17 @@ private static string GetResourceRelativeFilePath(string resourceName) return convertedFilePath; } + + private class SomethingFastZip : FastZip + { + public SomethingFastZip() + { + //This is a workaround to get files to extract properly. + // Define properly. + // Don't inline comments. + ZipConstants.DefaultCodePage = 0; + } + } + } } \ No newline at end of file diff --git a/ModListGameState.cs b/Src/PlanetbaseFramework/Mod/ModListGameState.cs similarity index 90% rename from ModListGameState.cs rename to Src/PlanetbaseFramework/Mod/ModListGameState.cs index ff80bb3..70b66bb 100644 --- a/ModListGameState.cs +++ b/Src/PlanetbaseFramework/Mod/ModListGameState.cs @@ -8,10 +8,7 @@ public class ModListGameState : GameState { private GuiRenderer Renderer { get; } = new GuiRenderer(); - public override bool isTitleState() - { - return true; - } + public override bool isTitleState() => true; public override void onGui() { @@ -20,8 +17,10 @@ public override void onGui() return; } + PrintLine("Loaded Mods:", 0); - for(var i = 0; i < ModLoader.ModList.Count; i++) + // This should be split to a method + for (var i = 0; i < ModLoader.ModList.Count; i++) { PrintLine(ModLoader.ModList[i].ModName, i + 1); } diff --git a/TitleButton.cs b/Src/PlanetbaseFramework/Mod/TitleButton.cs similarity index 100% rename from TitleButton.cs rename to Src/PlanetbaseFramework/Mod/TitleButton.cs diff --git a/PlanetbaseFramework.csproj b/Src/PlanetbaseFramework/PlanetbaseFramework.csproj similarity index 100% rename from PlanetbaseFramework.csproj rename to Src/PlanetbaseFramework/PlanetbaseFramework.csproj diff --git a/PlanetbaseFramework.csproj.user b/Src/PlanetbaseFramework/PlanetbaseFramework.csproj.user similarity index 100% rename from PlanetbaseFramework.csproj.user rename to Src/PlanetbaseFramework/PlanetbaseFramework.csproj.user diff --git a/Src/PlanetbaseFramework/Resources/ResourceUnpacker.cs b/Src/PlanetbaseFramework/Resources/ResourceUnpacker.cs new file mode 100644 index 0000000..67f9196 --- /dev/null +++ b/Src/PlanetbaseFramework/Resources/ResourceUnpacker.cs @@ -0,0 +1,101 @@ +// Could be abstract class instead due to the need fo Unpack with same implementation all accross. +public interface IResourceUnpacker +{ + public void Unpack(Stream resourceStream, string file); +} + +public class ZipUnpacker : IResourceUnpacker +{ + private readonly FastZip _zipInstance = new SomethingFastZip(); + + public void Unpack(string file) + { + using (var resourceStream = currentAssembly.GetManifestResourceStream(file)) + { + Unpack(file, resourceStream); + } + } + + public void Unpack(Stream resourceStream, string file) + { + Debug.Log("zip " + GetResourceRelativeFilePath(file)); + ZipInstance.ExtractZip( + resourceStream, + ModPath, + FastZip.Overwrite.Always, + null, + null, + null, + false, + false + ); + } +} + +public class NoUnpacker : IResourceUnpacker +{ + public void Unpack(string file) + { + using (var resourceStream = currentAssembly.GetManifestResourceStream(file)) + { + Unpack(file, resourceStream); + } + } + + public void Unpack(Stream resourceStream, string file) + { + var filePath = Path.Combine(ModPath, GetResourceRelativeFilePath(file)); + + Debug.Log($"Loading \"{file}\" to \"{filePath}\""); + + Directory.CreateDirectory(Path.GetDirectoryName(filePath)); + + using (var fileStream = File.Create(filePath)) + { + resourceStream.CopyTo(fileStream); + } + + break; + } +} + + +public class ResourceUnpacker : IResourceUnpacker +{ + private readonly Dictionary _unpackers = new Dictionary(); + private readonly IResourceUnpacker _defaultUnpacker = new NoUnpacker(); + + public void RegisterUnpacker(string fileExtension, IResourceUnpacker unpacker) + { + _unpackers.Add(fileExtension, unpacker); + } + + public void RegisterDefault(IResourceUnpacker unpacker) + { + _defaultUnpacker = unpacker; + } + + public void Unpack(string file) + { + using (var resourceStream = currentAssembly.GetManifestResourceStream(file)) + { + Unpack(file, resourceStream); + } + } + + public void Unpack(Stream resourceStream, string file) + { + using (var resourceStream = currentAssembly.GetManifestResourceStream(file)) + { + var extension = Path.GetExtension(file); + if (_unpackers.ContainsKey(extension)) + { + _unpackers[extension].Unpack(resourceStream, file); + } + else + { + _defaultUnpacker.Unpack(resourceStream, file); + } + } + } +}