using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Reflection; using DataLoader; using GamecraftModdingAPI.Utility; using GPUInstancer; using HarmonyLib; using RobocraftX.Blocks; using RobocraftX.Common; using RobocraftX.Rendering; using Svelto.DataStructures; using Svelto.Tasks; using Unity.Entities; using Unity.Entities.Conversion; using Unity.Physics; using UnityEngine; using UnityEngine.AddressableAssets; using BoxCollider = UnityEngine.BoxCollider; using Material = UnityEngine.Material; using Object = UnityEngine.Object; using ScalingPermission = DataLoader.ScalingPermission; namespace GamecraftModdingAPI.Blocks { public class CustomBlock { private static ushort nextID = 500; public static void RegisterCustomBlock(string path) { var prefabData = new List(); //category ID: //0 - regular //1 - joint //2 - controller uint prefabId = PrefabsID.FetchNewPrefabID(PrefabsID.GenerateDBID(0, nextID++)); prefabData.Add(new PrefabData() { prefabName = path, prefabId = prefabId }); var loadTask = Addressables.LoadAssetAsync(path); AccessTools.Method("RobocraftX.Common.ECSGPUIResourceManager:RegisterPrefab") .Invoke(ECSGPUIResourceManager.Instance, new object[] {prefabId, loadTask.Result, 1}); } [HarmonyPatch] public static class Patch { /*public static IEnumerable Transpiler(IEnumerable instructions) { var list = new List(instructions); try { *int index = -1; CodeInstruction loadTask = null; for (var i = 0; i < list.Count - 1; i++) { if (list[i].opcode == OpCodes.Ldfld && ((string) list[i].operand).Contains("renderingWorld") && list[i + 1].opcode == OpCodes.Brfalse_S) index = i - 1; //It loads 'this' first if (list[i].opcode == OpCodes.Ldflda && ((string) list[i].operand).Contains("loadTask")) loadTask = new CodeInstruction(list[i]); }* var array = new[] { //Set Yield.It to be returned (current) new CodeInstruction(OpCodes.Ldarg_0), // this new CodeInstruction(OpCodes.Ldsfld, typeof(Yield).GetField("It", BindingFlags.Public | BindingFlags.Static)), new CodeInstruction(OpCodes.Stfld, "object RobocraftX.Common.ECSResourceManagerUtility/'d__0'::'<>2__current'"), //Set which yield return we're at (state) new CodeInstruction(OpCodes.Ldarg_0), // this new CodeInstruction(OpCodes.Ldc_I4_1), //new CodeInstruction(OpCodes.Call, ((Action)AddInfo).Method) }; list.InsertRange(index, array); * IL_00ad: ldarg.0 // this IL_00ae: ldsfld class [Svelto.Tasks]Svelto.Tasks.Yield [Svelto.Tasks]Svelto.Tasks.Yield::It IL_00b3: stfld object RobocraftX.Common.ECSResourceManagerUtility/'d__0'::'<>2__current' IL_0072: ldarg.0 // this IL_0073: ldnull IL_0074: stfld object RobocraftX.Common.ECSResourceManagerUtility/'d__0'::'<>2__current' IL_0079: ldarg.0 // this IL_007a: ldc.i4.2 IL_007b: stfld object RobocraftX.Common.ECSResourceManagerUtility/'d__0'::'<>1__state' IL_0080: ldc.i4.1 IL_0081: ret * yield break; } catch (Exception e) { Logging.LogWarning("Failed to inject AddInfo method for the debug display!\n" + e); } }*/ private static Material[] materials; public static void Prefix(List prefabData, IList prefabs) { /*foreach (var block in blocks.Values.Cast()) { Console.WriteLine("Block info: " + block); }*/ /*var res = Addressables.LoadContentCatalogAsync("customCatalog.json"); while (!res.IsDone) yield return Yield.It;*/ foreach (var gameObject in prefabs) { switch (gameObject.name) { case "Cube": gameObject.GetComponentsInChildren()[0].sharedMaterials = materials; break; case "CTR_CommandBlock": materials = gameObject.GetComponentsInChildren()[0].sharedMaterials; break; } } } public static MethodBase TargetMethod() { //General block registration //return AccessTools.Method("RobocraftX.Blocks.BlocksCompositionRoot:RegisterPartPrefabs"); return AccessTools.Method("RobocraftX.Rendering.ECSGPUIResourceManager:InitPreRegisteredPrefabs"); } } /*[HarmonyPatch] public static class RendererPatch { private static Material[] materials; public static void Prefix(uint prefabID, GameObject gameObject) { Console.WriteLine("ID: " + prefabID + " - Name: " + gameObject.name); if (gameObject.name == "Cube") { //Console.WriteLine("Length: " + gameObject.GetComponentsInChildren().Length); if (materials != null) gameObject.GetComponentsInChildren()[0].sharedMaterials = materials; /*ECSGPUIResourceManager.Instance.RegisterGhostsPrefabsAtRuntime( new[] {new PrefabData {prefabId = prefabID, prefabName = "Assets/Prefabs/Cube.prefab"}}, new List {gameObject});#1# GameObject go = Object.Instantiate(gameObject); go.SetActive(false); AccessTools.Method("RobocraftX.Rendering.ECSGPUIResourceManager:RegisterNewPrefabAtRuntime") .Invoke(ECSGPUIResourceManager.Instance, new object[] {(uint) ((int) prefabID * 2 + 1), gameObject, true}); //ECSGPUIResourceManager.Instance.RegisterNewPrefabAtRuntime((uint) ((int)prefabID * 2 + 1), gameObject, true); //.isOcclusionCulling = false; UnityEngine.Object.Destroy(gameObject); GPUInstancerAPI.AddInstancesToPrefabPrototypeAtRuntime(ECSGPUIResourceManager.Instance.prefabManager, gameObject.GetComponent().prefabPrototype, new[] {gameObject}); Console.WriteLine("Registered prefab to instancer"); /*var register = AccessTools.Method("RobocraftX.Common.ECSPhysicResourceManager:RegisterPrefab", new[] {typeof(uint), typeof(GameObject), typeof(World), typeof(BlobAssetStore)}); register.Invoke(ECSPhysicResourceManager.Instance, new object[] {prefabID, gameObject, MGPatch.data.Item1, MGPatch.data.Item2});#1# /*Console.WriteLine( "Entity: " + ECSPhysicResourceManager.Instance.GetUECSPhysicEntityPrefab(prefabID)); Console.WriteLine("Prefab ID: " + PrefabsID.DBIDMAP[500]); PhysicsCollider componentData = MGPatch.data.Item1.EntityManager.GetComponentData(ECSPhysicResourceManager.Instance.GetUECSPhysicEntityPrefab(prefabID)); Console.WriteLine("Collider valid: " + componentData.IsValid); unsafe { Console.WriteLine("Collider type: " + componentData.ColliderPtr->Type); CollisionFilter filter = componentData.Value.Value.Filter; Console.WriteLine("Filter not empty: " + !filter.IsEmpty); }#1# //MGPatch.data.Item1.EntityManager.GetComponentData<>() gameObject.AddComponent(); gameObject.AddComponent(); Console.WriteLine("Registered prefab to physics"); ECSGPUIResourceManager.Instance.RegisterGhostsPrefabsAtRuntime(); } else if (gameObject.name == "CTR_CommandBlock") materials = gameObject.GetComponentsInChildren()[0].sharedMaterials; } public static MethodBase TargetMethod() {RobocraftX.Common.ECSGPUIResourceManager.RegisterPrefab return AccessTools.Method("RobocraftX.Common.ECSGPUIResourceManager:RegisterPrefab", new[] {typeof(uint), typeof(GameObject)}); } }*/ [HarmonyPatch] public static class RMPatch { public static void Prefix(World physicsWorld, GameObjectConversionSystem getExistingSystem, FasterList gos, List prefabData) { Console.WriteLine("First game object data:\n" + gos[0].GetComponents() .Select(c => c + " - " + c.name + " " + c.GetType()) .Aggregate((a, b) => a + "\n" + b)); for (var index = 0; index < prefabData.Count; index++) { var data = prefabData[index]; if (!data.prefabName.EndsWith("Cube.prefab")) continue; //getExistingSystem.DeclareLinkedEntityGroup(gos[index]); /*Entity entity = GameObjectConversionUtility.ConvertGameObjectHierarchy(gos[index], GameObjectConversionSettings.FromWorld(physicsWorld, MGPatch.data.Item2));*/ Console.WriteLine("Transform: " + gos[index].transform.childCount); Entity primaryEntity = getExistingSystem.GetPrimaryEntity(gos[index]); MultiListEnumerator entities = getExistingSystem.GetEntities(gos[index]); Console.WriteLine("ID: " + data.prefabId + " - Name: " + data.prefabName); Console.WriteLine("Primary entity: " + primaryEntity); EntityManager entityManager = physicsWorld.EntityManager; Console.WriteLine("Has collider: " + entityManager.HasComponent(primaryEntity)); while (entities.MoveNext()) { Entity current = entities.Current; Console.WriteLine("Entity " + current + " has collider: " + entityManager.HasComponent(current)); } Console.WriteLine("Adding GPUI prefab"); ((GPUInstancerPrefabManager) GPUInstancerManager.activeManagerList.Single(gim => gim is GPUInstancerPrefabManager)) .AddRuntimeRegisteredPrefab(gos[index].GetComponent()); Console.WriteLine("Added GPUI prefab"); } } public static MethodBase TargetMethod() { return AccessTools.Method("RobocraftX.Blocks.ECSResourceManagerUtility:RelinkEntities", new[] { typeof(World), typeof(GameObjectConversionSystem), typeof(FasterList), typeof(List) }); } } [HarmonyPatch] public static class MGPatch { internal static (World, BlobAssetStore) data; public static void Prefix(World physicsWorld, BlobAssetStore blobStore, IDataDB dataDB) { data = (physicsWorld, blobStore); //RobocraftX.CR.MachineEditing.UpdateSelectedGhostBlockEngine.UpdateGhostBlock //var cld = (CubeListData) ((DataImplementor) dataDB).CreateDataObject("500", typeof(CubeListData), null); var abd = dataDB.GetValue((int) BlockIDs.AluminiumCube); var cld = new CubeListData { cubeType = CubeType.Block, cubeCategory = CubeCategory.General, inventoryCategory = InventoryCategory.Shapes, ID = 500, Path = "Assets/Prefabs/Cube.prefab", //Index out of range exception: Asset failed to load (wrong path) SpriteName = "CTR_CommandBlock", CubeNameKey = "strConsoleBlock", SelectableFaces = new[] {0, 1, 2, 3, 4, 5}, GridScale = new[] {1, 1, 1}, Mass = 1, Material = abd.Material, scalingPermission = ScalingPermission.NonUniform, SortIndex = 12, DefaultColour = (byte) BlockColors.Lime, Volume = 1f, timeRunningCollision = TimeRunningCollision.Enabled, IsIsolator = false, EdgeConnectingFaces = new[] {0, 1, 2, 3, 4, 5}, PointDataVolumeMultiplier = 1f }; Console.WriteLine("Aluminium block data:\n" + abd); Console.WriteLine("Material: " + abd.Material); dataDB.GetValues().Add("500", cld); //The registration needs to happen after the ID has been set dataDB.GetFasterValues().Add(500, cld); //RobocraftX.ExplosionFragments.Engines.PlayFragmentExplodeEngine.PlayRigidBodyEffect } public static MethodBase TargetMethod() { return AccessTools.Method("RobocraftX.CR.MainGame.MainGameCompositionRoot:Init"); } } public static IEnumerator Prep() { //TODO: Don't let the game load until this finishes Console.WriteLine("Loading custom catalog..."); var res = Addressables.LoadContentCatalogAsync("customCatalog.json"); while (!res.IsDone) yield return Yield.It; Console.WriteLine("Loaded custom catalog: " + res.Result.LocatorId); Addressables.AddResourceLocator(res.Result); /*Console.WriteLine("Loading Cube asset..."); var loadTask = Addressables.LoadAssetAsync("Assets/Cube.prefab"); while (!loadTask.IsDone) yield return Yield.It; Console.WriteLine("Exception: "+loadTask.OperationException); Console.WriteLine("Result: " + loadTask.Result.name);*/ } } }