TechbloxModdingAPI/GamecraftModdingAPI/Blocks/CustomBlock.cs

288 lines
14 KiB
C#
Raw Normal View History

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using DataLoader;
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;
namespace GamecraftModdingAPI.Blocks
{
public class CustomBlock
{
private static ushort nextID = 500;
public static void RegisterCustomBlock(string path)
{
var prefabData = new List<PrefabData>();
//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<GameObject>(path);
AccessTools.Method("RobocraftX.Common.ECSGPUIResourceManager:RegisterPrefab")
.Invoke(ECSGPUIResourceManager.Instance, new object[] {prefabId, loadTask.Result, 1});
}
[HarmonyPatch]
public static class Patch
{
/*public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
var list = new List<CodeInstruction>(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/'<RegisterPrefabs>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<StringBuffer>)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/'<RegisterPrefabs>d__0'::'<>2__current'
IL_0072: ldarg.0 // this
IL_0073: ldnull
IL_0074: stfld object RobocraftX.Common.ECSResourceManagerUtility/'<RegisterPrefabs>d__0'::'<>2__current'
IL_0079: ldarg.0 // this
IL_007a: ldc.i4.2
IL_007b: stfld object RobocraftX.Common.ECSResourceManagerUtility/'<RegisterPrefabs>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> prefabData, IList<GameObject> prefabs)
{
/*foreach (var block in blocks.Values.Cast<CubeListData>())
{
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<MeshRenderer>()[0].sharedMaterials = materials;
break;
case "CTR_CommandBlock":
materials = gameObject.GetComponentsInChildren<MeshRenderer>()[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<MeshRenderer>().Length);
if (materials != null)
gameObject.GetComponentsInChildren<MeshRenderer>()[0].sharedMaterials = materials;
/*ECSGPUIResourceManager.Instance.RegisterGhostsPrefabsAtRuntime(
new[] {new PrefabData {prefabId = prefabID, prefabName = "Assets/Prefabs/Cube.prefab"}},
new List<GameObject> {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<GPUInstancerPrefab>().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<PhysicsCollider>(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<BoxCollider>();
gameObject.AddComponent<Transform>();
Console.WriteLine("Registered prefab to physics");
ECSGPUIResourceManager.Instance.RegisterGhostsPrefabsAtRuntime();
}
else if (gameObject.name == "CTR_CommandBlock")
materials = gameObject.GetComponentsInChildren<MeshRenderer>()[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<GameObject> gos,
List<PrefabData> prefabData)
{
Console.WriteLine("First game object data:\n" + gos[0].GetComponents<Component>()
.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<Entity> 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<PhysicsCollider>(primaryEntity));
while (entities.MoveNext())
{
Entity current = entities.Current;
Console.WriteLine("Entity " + current + " has collider: " +
entityManager.HasComponent<PhysicsCollider>(current));
}
Console.WriteLine("Adding GPUI prefab");
((GPUInstancerPrefabManager) GPUInstancerManager.activeManagerList.Single(gim =>
gim is GPUInstancerPrefabManager))
.AddRuntimeRegisteredPrefab(gos[index].GetComponent<GPUInstancerPrefab>());
Console.WriteLine("Added GPUI prefab");
}
}
public static MethodBase TargetMethod()
{
return AccessTools.Method("RobocraftX.Blocks.ECSResourceManagerUtility:RelinkEntities",
new[]
{
typeof(World),
typeof(GameObjectConversionSystem),
typeof(FasterList<GameObject>),
typeof(List<PrefabData>)
});
}
}
[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);
cld.cubeType = CubeType.Block;
cld.cubeCategory = CubeCategory.General;
cld.inventoryCategory = InventoryCategory.Shapes;
cld.ID = 500;
cld.Path = "Assets/Prefabs/Cube.prefab"; //Index out of range exception: Asset failed to load (wrong path)
cld.SpriteName = "CTR_CommandBlock";
cld.CubeNameKey = "strConsoleBlock";
cld.SelectableFaces = new[] {0, 1, 2, 3, 4, 5};
cld.GridScale = new[] {1, 1, 1};
cld.Mass = 1;
cld.JointBreakAngle = 1;
}
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<GameObject>("Assets/Cube.prefab");
while (!loadTask.IsDone) yield return Yield.It;
Console.WriteLine("Exception: "+loadTask.OperationException);
Console.WriteLine("Result: " + loadTask.Result.name);*/
}
}
}