2020-06-14 19:40:47 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections;
|
|
|
|
|
using System.Collections.Generic;
|
2020-12-17 19:20:46 +00:00
|
|
|
|
using System.IO;
|
2020-06-14 19:40:47 +00:00
|
|
|
|
using System.Reflection;
|
|
|
|
|
using HarmonyLib;
|
2020-12-19 20:43:49 +00:00
|
|
|
|
|
|
|
|
|
using DataLoader;
|
2020-12-12 01:28:42 +00:00
|
|
|
|
using RobocraftX.Rendering;
|
2020-12-26 00:59:06 +00:00
|
|
|
|
using RobocraftX.Schedulers;
|
2020-12-17 19:20:46 +00:00
|
|
|
|
using Svelto.ECS;
|
2020-12-26 00:59:06 +00:00
|
|
|
|
using Svelto.ECS.Experimental;
|
2020-06-14 19:40:47 +00:00
|
|
|
|
using Svelto.Tasks;
|
2020-12-26 00:59:06 +00:00
|
|
|
|
using Svelto.Tasks.ExtraLean;
|
2020-06-14 19:40:47 +00:00
|
|
|
|
using UnityEngine;
|
|
|
|
|
using UnityEngine.AddressableAssets;
|
2020-10-22 00:34:59 +00:00
|
|
|
|
using Material = UnityEngine.Material;
|
2020-12-19 20:43:49 +00:00
|
|
|
|
|
|
|
|
|
using GamecraftModdingAPI.Utility;
|
2020-06-14 19:40:47 +00:00
|
|
|
|
|
|
|
|
|
namespace GamecraftModdingAPI.Blocks
|
|
|
|
|
{
|
2020-12-26 00:59:06 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Experimental support for adding custom blocks to the game.
|
|
|
|
|
/// </summary>
|
2020-12-17 19:20:46 +00:00
|
|
|
|
public class CustomBlock : Block
|
2020-06-14 19:40:47 +00:00
|
|
|
|
{
|
|
|
|
|
private static ushort nextID = 500;
|
2020-12-17 19:20:46 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Key: Prefab path
|
|
|
|
|
/// </summary>
|
2020-12-26 00:59:06 +00:00
|
|
|
|
private static readonly Dictionary<string, Type> CustomBlocks = new Dictionary<string, Type>();
|
2020-12-27 20:13:49 +00:00
|
|
|
|
//private static readonly CustomBlockEngine Engine = new CustomBlockEngine();
|
|
|
|
|
private static readonly List<(ushort id, Action<CubeListData> action)> BlockChangeActions =
|
|
|
|
|
new List<(ushort, Action<CubeListData>)>();
|
2020-12-17 19:20:46 +00:00
|
|
|
|
|
|
|
|
|
private static bool _canRegister = true;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Register a custom block type. Call it as soon as possible (in OnApplicationStart()).<br />
|
|
|
|
|
/// You need a Unity project with Addressables and Havok installed and need a prefab added as an addressable asset.
|
|
|
|
|
/// Build the addressables and the project and copy the catalog.json from StreamingAssets, you'll need to reference this file.
|
|
|
|
|
/// Also copy the asset files from the subfolder to the same path in the game.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <typeparam name="T">The custom block type</typeparam>
|
|
|
|
|
public static void RegisterCustomBlock<T>() where T : CustomBlock
|
2020-06-14 19:40:47 +00:00
|
|
|
|
{
|
2020-12-17 19:20:46 +00:00
|
|
|
|
if (!_canRegister)
|
|
|
|
|
throw new InvalidOperationException(
|
|
|
|
|
"It's too late to register custom blocks. Register it before the game starts loading.");
|
|
|
|
|
var type = typeof(T);
|
|
|
|
|
var attr = type.GetCustomAttribute<CustomBlockAttribute>();
|
|
|
|
|
if (attr == null)
|
|
|
|
|
throw new ArgumentException("The custom block type is missing the CustomBlock annotation");
|
|
|
|
|
string typeName = type.FullName ??
|
|
|
|
|
throw new ArgumentException("The given block type doesn't have a concrete full name.");
|
|
|
|
|
if (!File.Exists(attr.Catalog))
|
|
|
|
|
throw new FileNotFoundException("The specified catalog cannot be found for " + typeName);
|
2020-12-26 00:59:06 +00:00
|
|
|
|
CustomBlocks.Add(attr.AssetPath, type);
|
2020-12-17 19:20:46 +00:00
|
|
|
|
Logging.MetaDebugLog("Registered custom block type " + typeName);
|
2020-06-14 19:40:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-12-27 20:13:49 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// A low-level method for changing any property of an existing block. Use with caution.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="id">The block ID</param>
|
|
|
|
|
/// <param name="modifier">An action that modifies a property of the block</param>
|
|
|
|
|
public static void ChangeExistingBlock(ushort id, Action<CubeListData> modifier)
|
|
|
|
|
{
|
|
|
|
|
BlockChangeActions.Add((id, modifier));
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-17 19:20:46 +00:00
|
|
|
|
public CustomBlock(EGID id) : base(id)
|
2020-06-14 19:40:47 +00:00
|
|
|
|
{
|
2020-12-19 20:43:49 +00:00
|
|
|
|
/*if (id.groupID != Group)
|
|
|
|
|
throw new BlockTypeException("The block is not a custom block! It has a group of " + id.groupID);*/
|
2020-12-17 19:20:46 +00:00
|
|
|
|
}
|
2020-06-14 19:40:47 +00:00
|
|
|
|
|
2020-12-19 20:43:49 +00:00
|
|
|
|
public CustomBlock(uint id) : base(id)
|
2020-12-17 19:20:46 +00:00
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-19 20:43:49 +00:00
|
|
|
|
//public static ExclusiveGroup Group { get; } = new ExclusiveGroup("Custom block");
|
2020-06-14 19:40:47 +00:00
|
|
|
|
|
2020-12-17 19:20:46 +00:00
|
|
|
|
[HarmonyPatch]
|
2020-12-19 20:43:49 +00:00
|
|
|
|
public static class MaterialCopyPatch
|
2020-12-17 19:20:46 +00:00
|
|
|
|
{
|
2020-12-12 15:59:52 +00:00
|
|
|
|
private static Material[] materials;
|
|
|
|
|
|
|
|
|
|
public static void Prefix(List<PrefabData> prefabData, IList<GameObject> prefabs)
|
2020-06-14 19:40:47 +00:00
|
|
|
|
{
|
2020-12-17 19:20:46 +00:00
|
|
|
|
for (var index = 0; index < prefabs.Count; index++)
|
2020-06-14 19:40:47 +00:00
|
|
|
|
{
|
2020-12-17 19:20:46 +00:00
|
|
|
|
if (prefabData[index].prefabName == "ConsoleBlock")
|
|
|
|
|
materials = prefabs[index].GetComponentsInChildren<MeshRenderer>()[0].sharedMaterials;
|
|
|
|
|
}
|
2020-06-14 19:40:47 +00:00
|
|
|
|
|
2020-12-17 19:20:46 +00:00
|
|
|
|
for (var index = 0; index < prefabs.Count; index++)
|
2020-12-12 15:59:52 +00:00
|
|
|
|
{
|
2020-12-26 00:59:06 +00:00
|
|
|
|
if (CustomBlocks.ContainsKey(prefabData[index].prefabName)) //This is a custom block
|
2020-12-17 19:20:46 +00:00
|
|
|
|
prefabs[index].GetComponentsInChildren<MeshRenderer>()[0].sharedMaterials = materials;
|
2020-12-12 15:59:52 +00:00
|
|
|
|
}
|
2020-06-14 19:40:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static MethodBase TargetMethod()
|
|
|
|
|
{ //General block registration
|
2020-12-12 15:59:52 +00:00
|
|
|
|
return AccessTools.Method("RobocraftX.Rendering.ECSGPUIResourceManager:InitPreRegisteredPrefabs");
|
2020-06-14 19:40:47 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-22 00:34:59 +00:00
|
|
|
|
[HarmonyPatch]
|
2020-12-17 19:20:46 +00:00
|
|
|
|
public static class CubeRegistrationPatch
|
2020-10-22 00:34:59 +00:00
|
|
|
|
{
|
2020-12-17 19:20:46 +00:00
|
|
|
|
public static void Prefix(IDataDB dataDB)
|
2020-10-22 00:34:59 +00:00
|
|
|
|
{
|
2020-12-17 19:20:46 +00:00
|
|
|
|
//var abd = dataDB.GetValue<CubeListData>((int) BlockIDs.AluminiumCube);
|
2020-12-26 00:59:06 +00:00
|
|
|
|
foreach (var (key, type) in CustomBlocks)
|
2020-10-22 00:34:59 +00:00
|
|
|
|
{
|
2020-12-17 19:20:46 +00:00
|
|
|
|
var attr = type.GetCustomAttribute<CustomBlockAttribute>();
|
|
|
|
|
var cld = new CubeListData
|
|
|
|
|
{ //"Assets/Prefabs/Cube.prefab" - "CTR_CommandBlock" - "strConsoleBlock"
|
|
|
|
|
cubeType = attr.Type,
|
2020-12-19 20:43:49 +00:00
|
|
|
|
//cubeCategory = (CubeCategory) 1000,
|
2020-12-17 19:20:46 +00:00
|
|
|
|
cubeCategory = attr.Category,
|
|
|
|
|
inventoryCategory = attr.InventoryCategory,
|
|
|
|
|
ID = nextID++,
|
|
|
|
|
Path = attr.AssetPath, //Index out of range exception: Asset failed to load (wrong path)
|
|
|
|
|
SpriteName = attr.SpriteName,
|
|
|
|
|
CubeNameKey = attr.NameKey,
|
|
|
|
|
CubeDescriptionKey = attr.DescKey,
|
|
|
|
|
SelectableFaces = new[] {0, 1, 2, 3, 4, 5},
|
|
|
|
|
GridScale = new[] {5, 5, 5},
|
|
|
|
|
Mass = attr.Mass,
|
|
|
|
|
Material = attr.Material,
|
|
|
|
|
scalingPermission = attr.ScalingPermission,
|
|
|
|
|
SortIndex = attr.SortIndex,
|
|
|
|
|
DefaultColour = attr.DefaultColor.Index,
|
|
|
|
|
Volume = attr.Volume,
|
|
|
|
|
EdgeConnectingFaces = new[] {0, 1, 2, 3, 4, 5},
|
|
|
|
|
PointDataVolumeMultiplier = 1f
|
|
|
|
|
};
|
|
|
|
|
dataDB.GetValues<CubeListData>().Add(cld.ID.ToString(), cld); //The registration needs to happen after the ID has been set
|
|
|
|
|
dataDB.GetFasterValues<CubeListData>().Add(cld.ID, cld); //So can't use the builtin method to create a CubeListData
|
2020-12-27 20:13:49 +00:00
|
|
|
|
//Engine.RegisterBlock((ushort) cld.ID, key); - TODO
|
2020-10-22 00:34:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-12-27 20:13:49 +00:00
|
|
|
|
foreach (var (id, action) in BlockChangeActions)
|
|
|
|
|
action(dataDB.GetValue<CubeListData>(id));
|
|
|
|
|
|
2020-12-17 19:20:46 +00:00
|
|
|
|
_canRegister = false;
|
2020-09-17 21:08:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static MethodBase TargetMethod()
|
|
|
|
|
{
|
|
|
|
|
return AccessTools.Method("RobocraftX.CR.MainGame.MainGameCompositionRoot:Init");
|
2020-06-14 19:40:47 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-19 20:43:49 +00:00
|
|
|
|
/*[HarmonyPatch] - The block has no collision even in simulation if using a custom category
|
|
|
|
|
private static class FactorySetupPatch
|
|
|
|
|
{
|
|
|
|
|
public static void Prefix(BlockEntityFactory __instance)
|
|
|
|
|
{
|
|
|
|
|
var builders = (Dictionary<CubeCategory, IBlockBuilder>)
|
|
|
|
|
AccessTools.Field(__instance.GetType(), "_blockBuilders").GetValue(__instance);
|
|
|
|
|
builders.Add((CubeCategory) 1000, new BlockBuilder<StandardBlockEntityDescriptor>(Group));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static MethodBase TargetMethod()
|
|
|
|
|
{
|
|
|
|
|
return AccessTools.Method(typeof(BlockEntityFactory), "ParseDataDB");
|
|
|
|
|
}
|
|
|
|
|
}*/
|
|
|
|
|
|
2020-12-26 00:59:06 +00:00
|
|
|
|
private static IEnumerator Prepare()
|
2020-12-19 20:43:49 +00:00
|
|
|
|
{ //Should be pretty quick
|
2020-12-26 00:59:06 +00:00
|
|
|
|
foreach (var type in CustomBlocks.Values)
|
2020-12-17 19:20:46 +00:00
|
|
|
|
{
|
|
|
|
|
var attr = type.GetCustomAttribute<CustomBlockAttribute>();
|
|
|
|
|
Logging.Log("Loading custom block catalog " + attr.Catalog);
|
|
|
|
|
var res = Addressables.LoadContentCatalogAsync(attr.Catalog);
|
|
|
|
|
while (!res.IsDone) yield return Yield.It;
|
|
|
|
|
Logging.Log("Loaded custom block catalog: " + res.Result.LocatorId);
|
|
|
|
|
Addressables.AddResourceLocator(res.Result);
|
|
|
|
|
}
|
2020-06-14 19:40:47 +00:00
|
|
|
|
}
|
2020-12-19 20:43:49 +00:00
|
|
|
|
|
2020-12-26 00:59:06 +00:00
|
|
|
|
internal new static void Init()
|
|
|
|
|
{
|
|
|
|
|
Prepare().RunOn(ExtraLean.UIScheduler);
|
2020-12-27 20:13:49 +00:00
|
|
|
|
//GameEngineManager.AddGameEngine(Engine); - TODO: Fix serialization and implement block ID update
|
2020-12-26 00:59:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-12-19 20:43:49 +00:00
|
|
|
|
/*internal static void OnBlockFactoryObtained(BlockEntityFactory factory)
|
|
|
|
|
{
|
|
|
|
|
var builders = (Dictionary<CubeCategory, IBlockBuilder>)
|
|
|
|
|
AccessTools.Field(factory.GetType(), "_blockBuilders").GetValue(factory);
|
|
|
|
|
builders.Add((CubeCategory) 1000, new BlockBuilder<StandardBlockEntityDescriptor>(Group));
|
|
|
|
|
}*/
|
2020-12-26 00:59:06 +00:00
|
|
|
|
|
|
|
|
|
internal struct DataStruct : IEntityComponent
|
|
|
|
|
{
|
|
|
|
|
public ECSString Name;
|
|
|
|
|
public ushort ID;
|
|
|
|
|
}
|
2020-06-14 19:40:47 +00:00
|
|
|
|
}
|
|
|
|
|
}
|