Last Updated: 2026-4-19
As the original author and primary developer of the Latios Framework for Unity’s ECS, I regularly run into bugs, inadequate functionalities, and pitfalls within the ECS ecosystem. This has resulted in lots of “hacks” in the framework to patch up problems. This is a living document describing the issues and hacks. My hope is that the Unity ECS team will find this to be a valuable reference to help improve the quality of their packages.
This document does not include all possible features the Latios Framework may eventually implement if no official solution is provided. If you would like to learn about such features, it is best to ask me. I’ve focused this list specifically on things I would like to see. There are a lot more things I could list that I know many users have asked for, and arrive to the Latios Framework due to these missing features or other issues. If you would like to get a list of these things in a specific area, or if you have any questions about anything listed here, feel free to reach out to me!
These are high-severity items that are preventing the Latios Framework from releasing new major features or advancing to new versions of packages.
There is an issue where setting the Batch Buffer in the OnFinishedCulling() callback of BatchRendererGroup causes the screen to flicker. I have reported this here: https://issuetracker.unity3d.com/issues/entities-flicker-when-setting-batchrenderergroup-buffer-inside-onfinishedculling-callback
The Entities package still relies on InstanceID for Unity 6.3 projects. This divergence causes problems with the framework targeting newer editor versions. Because 6.3 is an LTS, I am currently choosing to only support this version right now.
The Scriptable Render Pipelines currently call directly into GPU Resident Drawer for critical features such as double-pass occlusion culling. GPU Resident Drawer has significant performance design flaws, and I want to replace it. However, shipping an entire replacement for the Scriptable Render Pipeline Core package does not sound like a good idea.
These are issues that are compromising my ability to provide the best possible API and experience for users of the Latios Framework.
IAspect and ENTITY_STORE_V1 deprecation introduce significant problems. I don’t mind those going away, but I need the following to replace them.
I want to define custom type handles that SystemAPI can populate for me. I want to define custom types that can be iterated in idiomatic foreach and IJobEntity. I want to extract the EntityQuery auto-created by an IJobEntity definition. I wish the IJobEntityChunkBeginEnd interface was just part of IJobEntity and were default interface methods. And I want a method I can call that will populate all the type handles and indices arrays of an IJobEntity so that I can pass it into a generic method constrained by IJobChunk to schedule the job in a custom way.
I also want a per-world deterministic chunk ID that I can use to sort chunks deterministically.
These are features that are deep in the backlog of things I may develop for the framework, but I’d really rather these be developed by Unity first.
Companion Game Object lights are bad for any dynamic entities that are spawned and despawned. It would be awesome if we could feed unmanaged light data into the SRP, since that’s how it uses it internally.
This one is a bit wishful on my part. But I would love some built-in tools for an environment system not tied to heightmaps.
Cinemachine does not play nice with the job system, or ECS physics. I’d like to see better integration.
These are areas that make it harder for me to develop features for the framework.
I’d like to see the Numerics assembly inside Unity Physics be split into a separate package. Otherwise, I’m going to have to copy it if I want to use it, since I have my own physics solution.
I’d like structural changes made on entire chunk in-place to first check if there is a destination chunk that can house all of the entities contained in the source chunk, and then move all the entities there. This would solve a lot of fragmentation problems I am constantly having to dodge with cleanup and chunk components.
When Burst compiles a job, it often breaks the job up into multiple functions. I want an outline of all these functions that I can click on to jump to them.
It is very difficult to enforce unique identifiers to external resources, and correctly handle instantiation deep-copying those external resources and garbage-collecting dead entities. I want to see this area improved.
I want a better way to make more data visible to the runtime inspectors, such as fields I specify as internal. I also want to be able to override the entire DynamicBuffer drawer, rather than each element.
It seems Burst really only likes string interpolation for the fixed string types. I’d like the range to be covered a little more.
I want to assign each SharedStatic<int> a unique array index at creation time, so that I can use these as named indexers into some other resource, without having to try and gather all these instances at application startup.
These are issues that are preventing me from getting the most performance out of the framework.
While I think the first chunk of each archetype could be the fixed 16 kB layout, if there are archetypes that need more than one chunk, I’d like to see them switch to a design that allows far more entities to be iterated linearly at once, so that we can benefit more from hardware prefetching.
SRP allows all shadow-casting lights to be culled and processed in batch. Yet the culling callbacks sent back to BatchRendererGroup happen one-by-one. I’d love to perform culling for all lights at once.
I’d like the option to allow the component data moving part to be deferred to a parallel job during large structural changes, and for DynamicBuffer memory freeing operations to also get deferred to some later point off the main thread (unless mimalloc solves this)
I want to use SIMD (or pairs of 64-bit ops) to process enabled states of components in a chunk, both for reading and writing.
Here’s some examples of API holes that are a bit inconsistent. Commented out lines are lines that I would expect to compile, but don’t.
using System.Collections.Generic;
using Unity.Burst.Intrinsics;
using Unity.Collections;
using Unity.Entities;
using Unity.Entities.Graphics;
using Unity.Rendering;
using Unity.Transforms;
partial struct ApiProblemsSystem : ISystem
{
public void OnUpdate(ref SystemState state)
{
var list = new NativeList<int>(state.WorldUpdateAllocator);
state.Dependency = list.Dispose(state.Dependency);
var array = CollectionHelper.CreateNativeArray<int>(8, state.WorldUpdateAllocator);
//state.Dependency = CollectionHelper.Dispose(array, state.Dependency);
Entity anEntity = Entity.Null;
foreach ((var transform, var entity) in SystemAPI.Query<LocalTransform>().WithEntityAccess())
{
anEntity = entity;
}
//foreach (var entity in SystemAPI.Query().WithEntityAccess().WithAll<LocalTransform>())
{
}
var valuesManaged = new List<RenderFilterSettings>();
var indicesManaged = new List<int>();
state.EntityManager.GetAllUniqueSharedComponentsManaged(valuesManaged, indicesManaged);
state.EntityManager.GetAllUniqueSharedComponents<RenderFilterSettings>(out var valuesUnmanaged, state.WorldUpdateAllocator);
//state.EntityManager.GetAllUniqueSharedComponents<RenderFilterSettings>(out var valuesUnmanaged, out var indicesUnmanaged, state.WorldUpdateAllocator);
// Why do we even have custom SystemHandle APIs for things rather than just expose an Entity property on SystemHandle?
var dstBuffer = state.EntityManager.GetBuffer<LinkedEntityGroup>(state.SystemHandle);
//state.EntityManager.GetSharedComponentData<RenderFilterSettings>(state.SystemHandle, default);
state.EntityManager.GetComponentDataRW<LocalTransform>(state.SystemHandle);
//state.EntityManager.GetComponentDataRW<LocalTransform>(anEntity);
state.EntityManager.CompleteDependencyBeforeRO<LocalTransform>();
//state.EntityManager.CompleteDependencyBeforeRO(ComponentType.ReadOnly<LocalTransform>());
var systemTypeIndex = TypeManager.GetSystemTypeIndex<ApiProblemsSystem>();
//System.Type type = TypeManager.GetSystemType(systemTypeIndex);
var srcBuffer = state.EntityManager.GetBuffer<LinkedEntityGroup>(anEntity);
dstBuffer.CopyFrom(srcBuffer);
//dstBuffer.AddRange(srcBuffer);
dstBuffer.AddRange(srcBuffer.AsNativeArray()); // Safety violation
var archetype = state.EntityManager.GetChunk(anEntity).Archetype;
state.EntityManager.SetArchetype(anEntity, archetype);
var entityArray = new NativeArray<Entity>(1, Allocator.Temp);
entityArray[0] = anEntity;
//state.EntityManager.SetArchetype(entityArray, archetype);
}
struct Job : IJobChunk
{
public ComponentTypeHandle<EntitiesGraphicsChunkInfo> chunkComponentHandle;
public ComponentTypeHandle<MaterialMeshInfo> componentHandle;
public DynamicComponentTypeHandle dynamicHandle;
public SharedComponentTypeHandle<RenderFilterSettings> sharedHandle;
public DynamicSharedComponentTypeHandle dynamicSharedHandle;
public EntityQueryMask queryMask;
public unsafe void Execute(in ArchetypeChunk chunk, int unfilteredChunkIndex, bool useEnabledMask, in v128 chunkEnabledMask)
{
chunk.GetEnableableBits(ref dynamicHandle);
//chunk.GetEnableableBits(ref componentHandle);
//chunk.GetSharedComponent(ref sharedHandle);
chunk.GetSharedComponent(sharedHandle);
chunk.GetDynamicSharedComponentDataAddress(ref dynamicSharedHandle);
//chunk.GetSharedComponentIndex(ref sharedHandle);
chunk.GetSharedComponentIndex(sharedHandle);
chunk.GetSharedComponentIndex(ref dynamicSharedHandle);
EntityQueryMask defaultMask = default;
//bool isDefaultMask = queryMask == defaultMask;
var arrayRO = chunk.GetComponentDataPtrRO(ref componentHandle);
//var dynamicArrayRO = chunk.GetComponentDataPtrRO(ref dynamicHandle);
var dynamicHandleAsRO = dynamicHandle.CopyToReadOnly(); // RIP lookup cache.
var dynamicArrayRO = chunk.GetDynamicComponentDataArrayReinterpret<byte>(ref dynamicHandleAsRO, 4);
chunk.GetChunkComponentData(ref chunkComponentHandle);
//chunk.GetChunkComponentDataRW(ref chunkComponentHandle);
}
}
}Sometimes, I need to do hacky things to accomplish the desired functionality. While this isn’t a complete list, here are a few areas to look at to see if things can be improved.
I use this asmref directory to expose various extra APIs from the Entities package that I need. https://github.com/Dreaming381/Latios-Framework/tree/master/EntitiesExposed
The ILPostProcessing next to it is also hacks into the Entities package for where I needed to add extra hooks.
Please ask what I use each of these for.
I have custom bootstrap types that define other worlds, such as the editor world and baking worlds. I eventually plan to add a bootstrap for subscene post-processing. But it would be really nice if I didn’t have to do crazy hacks to make these things work.
Somehow, I can’t seem to find a PlayerLoop point that happens after all the rendering including SRP Render Graph execution. I need to use an end-of-frame coroutine on a hidden GameObject to run systems at this point. And then making those systems show up in the Systems window also required a bit of hackery.
Right now, I have my Smart Blobber feature, which makes blob baking with deduplication safer and easier, while offering parallel baking for fast live editing. However, I’d much rather see an approach that allows blobs to be baked in bakers with the same benefits. This would require two things:
First, it would require the ability to specify separate per-bake and per session hashes for potential blob assets. And second, it would require async awaiting on scheduled jobs so that other bakers can run while jobs are processing a blob.
Everything in here I would have expected to be provided out-of-the-box. https://github.com/Dreaming381/Latios-Framework/blob/master/Core/Authoring/BakerInterfaceSupport.cs
I had a heck of a time hacking packages in order to make Entity projected decals a thing. Related bug reports were all rejected. I wrote the details here: https://github.com/Dreaming381/Latios-Framework-Documentation/blob/main/Kinemation%20Animation%20and%20Rendering/Decals.md#deep-hackery
These are the big features that the Latios Framework provides some kind of substitute for, and the oversimplified reasons why.
I wanted animation-friendly squash-and-stretch hierarchies. And I also wanted much better performance. Unity Transforms did catch up performance-wise in a lot of ways since I started this endeavor.
I needed much better performance for skinned mesh rendering. Turns out, this path led me to discover optimizations for all projects in general. And after that, I went on a quest to support LODs for dense worlds as well. The more I and others pushed big worlds full of entities, the more I kept pushing my solution to meet the demand. The Entities Graphics package has been mostly stagnant in regards to features, getting the occasional bugfix every few DOTS releases. And GPU Resident Drawer has been repeating all the same mistakes (and even missing out on some optimizations). Therefore, my solution has become significantly faster than both.
I needed much more direct spatial query capabilities. And nowadays, I need more customizability over the simulation. Also, I needed hierarchies.
This unfortunately meant that I don’t get to directly use the character controller and vehicles packages either. But I’m not too disappointed by that, as neither meets my own needs.
I needed much more control over the interpolation of synchronized objects. And I needed better hierarchy support. I just could not achieve a good motion feel in NetCode for motions that felt great when not networked.