using System; using System.Collections.Generic; using HarmonyLib; using RobocraftX.Schedulers; using Svelto.ECS; using Svelto.ECS.Hybrid; using Svelto.Tasks; using Svelto.Tasks.Lean; using TechbloxModdingAPI.Blocks.Engines; using TechbloxModdingAPI.Common.Engines; using TechbloxModdingAPI.Utility; using TechbloxModdingAPI.Utility.ECS; namespace TechbloxModdingAPI.Common; public class EcsObjectBaseEngine : IFactoryEngine, IFunEngine { public void Ready() { } public EntitiesDB entitiesDB { get; set; } public void Dispose() { } public EntityReference GetEntityReference(EGID egid) { return entitiesDB is not null && egid != default ? egid.ToEntityReference(entitiesDB) : EntityReference.Invalid; } public EGID GetEgid(EntityReference reference) { return entitiesDB is not null && reference.ToEGID(entitiesDB, out var egid) ? egid : default; } public OptionalRef GetComponentOptional(EcsObjectBase obj) where T : unmanaged, IEntityComponent { return entitiesDB.QueryEntityOptional(obj); } public ref T GetComponent(EcsObjectBase obj) where T : unmanaged, IEntityComponent { #if DEBUG if (entitiesDB.Exists(obj.Id) && obj.InitData.Valid) throw new ArgumentException("The block exists but the init data has not been removed!"); #endif return ref entitiesDB.QueryEntityOrDefault(obj); } public ref T GetViewComponent(EcsObjectBase obj) where T : struct, IEntityViewComponent { return ref entitiesDB.QueryEntityOrDefault(obj); } public object GetComponent(EcsObjectBase obj, Type type, string name) { var opt = AccessTools.Method(typeof(NativeApiExtensions), "QueryEntityOptional", new[] { typeof(EntitiesDB), typeof(EcsObjectBase), typeof(ExclusiveGroupStruct) }, new[] { type }) .Invoke(null, new object[] { entitiesDB, obj, null }); var str = AccessTools.Property(opt.GetType(), "Value").GetValue(opt); return AccessTools.Field(str.GetType(), name).GetValue(str); } public void SetComponent(EcsObjectBase obj, Type type, string name, object value) { var opt = AccessTools.Method(typeof(BlockEngine), "GetBlockInfoOptional", generics: new[] { type }) .Invoke(this, new object[] { obj }); var prop = AccessTools.Property(opt.GetType(), "Value"); var str = prop.GetValue(opt); AccessTools.Field(str.GetType(), name).SetValue(str, value); prop.SetValue(opt, str); } private readonly Dictionary> _waitingForSubmission = new(); public void TrackNewEntity(EcsObjectBase obj, Action done) { if (_waitingForSubmission.ContainsKey(obj)) throw new InvalidOperationException("Something has gone horribly wrong here"); _waitingForSubmission.Add(obj, done); WaitUntilEntitySubmission().RunOn(ClientLean.UIScheduler); // TODO: Pick the right scheduler } private IEnumerator WaitUntilEntitySubmission() { // TODO: Get the scheduler instance based on the engine (inject in engine manager) yield return new WaitForSubmissionEnumerator(FullGameFields._mainGameEnginesRoot.scheduler).Continue(); foreach (var (obj, done) in _waitingForSubmission) done(obj); } public IEntityFactory Factory { get; set; } public IEntityFunctions Functions { get; set; } }