using System;
using System.Collections.Generic;
using Svelto.DataStructures;
using Svelto.ECS;
using Svelto.Tasks;
using Svelto.Tasks.Lean;
using TechbloxModdingAPI.Tasks;
namespace TechbloxModdingAPI.Utility.ECS
{
public static partial class NativeApiExtensions
{
///
/// Attempts to query an entity and returns an optional that contains the result if succeeded.
/// This overload does not take initializer data into account.
///
/// The entities DB
/// The EGID to query
/// The component type to query
/// An optional that contains the result on success or is empty if not found
public static OptionalRef QueryEntityOptional(this EntitiesDB entitiesDB, EGID egid)
where T : unmanaged, IEntityComponent
{
return entitiesDB.TryQueryEntitiesAndIndex(egid, out uint index, out var array)
? new OptionalRef(array, index)
: new OptionalRef();
}
///
/// Attempts to query an entity and returns the result in an optional reference.
///
/// The entities DB to query from
/// The ECS object to query
/// The group of the entity if the object can have multiple
/// The component to query
/// A reference to the component or a dummy value
public static OptionalRef QueryEntityOptional(this EntitiesDB entitiesDB, EcsObjectBase obj,
ExclusiveGroupStruct group = default)
where T : unmanaged, IEntityComponent
{
EGID id = group == ExclusiveGroupStruct.Invalid ? obj.Id : new EGID(obj.Id.entityID, group);
var opt = QueryEntityOptional(entitiesDB, id);
return opt ? opt : new OptionalRef(obj, true);
}
///
/// Attempts to query an entity and returns the result or a dummy value that can be modified.
///
/// The entities DB to query from
/// The ECS object to query
/// The group of the entity if the object can have multiple
/// The component to query
/// A reference to the component or a dummy value
public static ref T QueryEntityOrDefault(this EntitiesDB entitiesDB, EcsObjectBase obj,
ExclusiveGroupStruct group = default)
where T : unmanaged, IEntityComponent
{
EGID id = group == ExclusiveGroupStruct.Invalid ? obj.Id : new EGID(obj.Id.entityID, group);
var opt = QueryEntityOptional(entitiesDB, id);
if (opt) return ref opt.Get();
if (obj.InitData.Valid) return ref obj.InitData.Initializer(id).GetOrAdd();
/*if (!obj.InitData.Valid) return ref opt.Get(); //Default value
var init = obj.InitData.Initializer(id);
// Do not create the component if missing, as that can trigger Add() listeners that, in some cases, may be
// invalid if (ab)using the classes in an unusual way - TODO: Check entity descriptor or something
if (init.Has()) return ref init.Get();*/
return ref opt.Get(); //Default value
}
///
/// Publishes an entity change, ignoring duplicate publishes and delaying changes as necessary.
/// It will only publish in the next frame.
///
/// The entities DB to publish to
/// The ECS object that got changed
/// The component that changed
public static void PublishEntityChangeDelayed(this EntitiesDB entitiesDB, EGID id)
where T : unmanaged, IEntityComponent
{
PublishChanges(entitiesDB, id).RunOn(Scheduler.leanRunner);
}
private static IEnumerator PublishChanges(EntitiesDB entitiesDB, EGID id)
where T : unmanaged, IEntityComponent
{
yield return Yield.It;
var entityStream = entitiesDB.GetEntityStream();
if (entityStream is null)
yield break; // There is no entity stream for this type
var consumers = entityStream.GetConsumers();
if (consumers == null)
{
Console.WriteLine("Consumers is null");
yield break;
}
bool waitForConsumers;
do
{
waitForConsumers = false;
for (int i = 0; i < consumers.count; i++)
{
var buffer = consumers[i].GetRingBuffer();
if (buffer.Count + 1 <= buffer.Capacity) continue;
waitForConsumers = true;
break;
}
if (waitForConsumers) yield return Yield.It;
} while (waitForConsumers);
entitiesDB.PublishEntityChange(id);
}
///
/// Query entities as OptionalRefs. The elements always exist, it's just a nice way to encapsulate the data.
///
///
///
///
///
///
///
public static RefCollection QueryEntitiesOptional(this EntitiesDB entitiesDB, ExclusiveGroupStruct group) where T : unmanaged, IEntityComponent
{
var (buffer, ids, count) = entitiesDB.QueryEntities(group);
return new RefCollection(count, buffer, ids, group);
}
}
}