Skip to content

Commit a2a6565

Browse files
committed
Version 0.12.3 Release [Bugfix]
Bugfix release
1 parent 5f82b24 commit a2a6565

14 files changed

+344
-8
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,15 @@ You can find changelogs for the individual modules in the [official Latios
1010
Framework Documentation
1111
repository](https://github.com/Dreaming381/Latios-Framework-Documentation).
1212

13+
## [0.12.3] – 2025-3-29
14+
15+
Officially supports Entities [1.3.9]
16+
17+
### Changed
18+
19+
- Updated Core to v0.12.3
20+
- Updated Kinemation to v0.12.3
21+
1322
## [0.12.2] – 2025-3-22
1423

1524
Officially supports Entities [1.3.9]

Core/Containers/ThreadLocal/ThreadStackAllocator.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@ public void Dispose()
4242
return (T*)m_statePtr->Allocate((ulong)UnsafeUtility.SizeOf<T>(), (ulong)UnsafeUtility.AlignOf<T>(), (ulong)count);
4343
}
4444

45+
public Span<T> AllocateAsSpan<T>(int count) where T : unmanaged
46+
{
47+
var ptr = Allocate<T>(count);
48+
return new Span<T>(ptr, count);
49+
}
50+
4551
// Slightly faster than getting the allocator globally.
4652
public ThreadStackAllocator CreateChildAllocator()
4753
{

Core/Editor/UnityScenesMods.meta

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 278 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
1+
// This system is based on tertle's Entities fork which allows for disabling subscene reimport during play mode.
2+
#if UNITY_EDITOR && !LATIOS_BL_FORK
3+
4+
using System;
5+
using System.Diagnostics;
6+
using Unity.Assertions;
7+
using Unity.Collections;
8+
using Unity.Entities;
9+
using Unity.Jobs;
10+
11+
namespace Unity.Scenes
12+
{
13+
static class SubscenePlayModeEditorOptions
14+
{
15+
static string editorPrefName = "LatiosDisableSubsceneReimportDuringPlaymode";
16+
internal static bool disableSubsceneReimportDuringPlaymode
17+
{
18+
get => UnityEditor.EditorPrefs.GetBool(editorPrefName);
19+
private set => UnityEditor.EditorPrefs.SetBool(editorPrefName, value);
20+
}
21+
22+
const string menuPath = "Edit/Latios/Disable Subscene Reimport During Playmode";
23+
24+
[UnityEditor.InitializeOnLoadMethod]
25+
public static void InitToggle() => UnityEditor.Menu.SetChecked(menuPath, disableSubsceneReimportDuringPlaymode);
26+
27+
[UnityEditor.MenuItem(menuPath)]
28+
public static void ToggleDriver()
29+
{
30+
var currentState = disableSubsceneReimportDuringPlaymode;
31+
currentState = !currentState;
32+
disableSubsceneReimportDuringPlaymode = currentState;
33+
UnityEditor.Menu.SetChecked(menuPath, currentState);
34+
}
35+
}
36+
37+
[WorldSystemFilter(WorldSystemFilterFlags.Default | WorldSystemFilterFlags.Editor | WorldSystemFilterFlags.Streaming)]
38+
[UpdateInGroup(typeof(SceneSystemGroup))]
39+
[UpdateAfter(typeof(WeakAssetReferenceLoadingSystem))]
40+
[UpdateAfter(typeof(SceneSystem))]
41+
[UpdateBefore(typeof(ResolveSceneReferenceSystem))]
42+
partial class LatiosEditorResolveSceneReferenceSystem : SystemBase
43+
{
44+
struct AssetDependencyTrackerState : ICleanupComponentData
45+
{
46+
public UnityEditor.GUID SceneAndBuildConfigGUID;
47+
}
48+
49+
EntityQuery m_AddScenes;
50+
EntityQuery m_RemoveScenesWithoutSceneReference;
51+
EntityQuery m_RemoveScenesWithDisableSceneResolveAndLoad;
52+
EntityQuery m_RemoveScenesWithDisabled;
53+
EntityQuery m_ValidSceneQuery;
54+
EntityQueryMask m_ValidSceneMask;
55+
ResolveSceneSectionArchetypes m_ResolveSceneSectionArchetypes;
56+
57+
AssetDependencyTracker<Entity> _AssetDependencyTracker;
58+
NativeList<AssetDependencyTracker<Entity>.Completed> _Changed;
59+
60+
SystemHandle _sceneSystem;
61+
62+
SceneHeaderUtility _SceneHeaderUtility;
63+
64+
[Conditional("LOG_RESOLVING")]
65+
void LogResolving(string type, Hash128 sceneGUID)
66+
{
67+
Debug.Log(type + ": " + sceneGUID);
68+
}
69+
70+
[Conditional("LOG_RESOLVING")]
71+
void LogResolving(string log)
72+
{
73+
Debug.Log(log);
74+
}
75+
76+
protected override unsafe void OnUpdate()
77+
{
78+
SceneWithBuildConfigurationGUIDs.ValidateBuildSettingsCache();
79+
80+
var buildConfigurationGUID = EntityManager.GetComponentData<SceneSystemData>(_sceneSystem).BuildConfigurationGUID;
81+
82+
// Add scene entities that haven't been encountered yet
83+
if (!m_AddScenes.IsEmptyIgnoreFilter)
84+
{
85+
//@TODO: Should use Entities.ForEach but we are missing Entities.ForEach support for explicit queries
86+
87+
using (var addScenes = m_AddScenes.ToEntityArray(Allocator.TempJob))
88+
{
89+
var trackerStates = new NativeArray<AssetDependencyTrackerState>(addScenes.Length, Allocator.Temp);
90+
for (int i = 0; i != addScenes.Length; i++)
91+
{
92+
var sceneEntity = addScenes[i];
93+
var scene = EntityManager.GetComponentData<SceneReference>(sceneEntity);
94+
var requestSceneLoaded = EntityManager.GetComponentData<RequestSceneLoaded>(sceneEntity);
95+
96+
var guid = SceneWithBuildConfigurationGUIDs.EnsureExistsFor(scene.SceneGUID,
97+
buildConfigurationGUID, true, out var requireRefresh);
98+
var async = (requestSceneLoaded.LoadFlags & SceneLoadFlags.BlockOnImport) == 0;
99+
100+
LogResolving(async ? "Adding Async" : "Adding Sync", guid);
101+
102+
_AssetDependencyTracker.Add(guid, sceneEntity, async);
103+
if (requireRefresh)
104+
_AssetDependencyTracker.RequestRefresh();
105+
106+
trackerStates[i] = new AssetDependencyTrackerState { SceneAndBuildConfigGUID = guid };
107+
}
108+
109+
EntityManager.AddComponentData(m_AddScenes, trackerStates);
110+
trackerStates.Dispose();
111+
}
112+
}
113+
114+
// Remove scene entities that were added and should no longer be tracked
115+
RemoveSceneEntities(m_RemoveScenesWithoutSceneReference);
116+
RemoveSceneEntities(m_RemoveScenesWithDisableSceneResolveAndLoad);
117+
RemoveSceneEntities(m_RemoveScenesWithDisabled);
118+
119+
// Process any scenes that have completed their asset import
120+
var isDone = _AssetDependencyTracker.GetCompleted(_Changed);
121+
foreach (var change in _Changed)
122+
{
123+
var sceneEntity = change.UserKey;
124+
LogResolving($"Resolving: {change.Asset} -> {change.ArtifactID}");
125+
126+
// This happens when instantiating an already fully resolved scene entity,
127+
// AssetDependencyTrackerState will be added and results in a completed change request,
128+
// but since this scene is already fully resolved with the same hash we can simply skip it.
129+
if (SystemAPI.HasComponent<ResolvedSceneHash>(sceneEntity) &&
130+
SystemAPI.GetComponent<ResolvedSceneHash>(sceneEntity).ArtifactHash == (Hash128)change.ArtifactID)
131+
{
132+
if (!SystemAPI.HasBuffer<ResolvedSectionEntity>(sceneEntity))
133+
throw new InvalidOperationException(
134+
$"Entity {sceneEntity} used for a scene load has a {nameof(ResolvedSceneHash)} component but no {nameof(ResolvedSectionEntity)} buffer. " +
135+
"This suggests that you copied a scene entity after loading it, but before its scene data had been fully resolved. " +
136+
$"Please only copy it after resolving has finished, which will add {nameof(ResolvedSectionEntity)} to the entity.");
137+
continue;
138+
}
139+
140+
if (!m_ValidSceneMask.MatchesIgnoreFilter(sceneEntity))
141+
throw new InvalidOperationException("entity should have been removed from tracker already");
142+
143+
if (UnityEditor.EditorApplication.isPlaying && SubscenePlayModeEditorOptions.disableSubsceneReimportDuringPlaymode &&
144+
SceneSystem.IsSceneLoaded(World.Unmanaged, sceneEntity))
145+
continue;
146+
147+
// Unload any previous state
148+
SceneSystem.UnloadSceneSectionMetaEntitiesOnly(World.Unmanaged, sceneEntity, false);
149+
150+
// Resolve new state
151+
var scene = EntityManager.GetComponentData<SceneReference>(change.UserKey);
152+
var request = EntityManager.GetComponentData<RequestSceneLoaded>(change.UserKey);
153+
154+
SceneWithBuildConfigurationGUIDs.EnsureExistsFor(scene.SceneGUID,
155+
buildConfigurationGUID, true, out var requireRefresh);
156+
157+
if (change.ArtifactID != default)
158+
{
159+
LogResolving($"Schedule header load: {change.ArtifactID}");
160+
SceneHeaderUtility.ScheduleHeaderLoadOnEntity(EntityManager, change.UserKey, scene.SceneGUID,
161+
request, change.ArtifactID, SceneSystem.SceneLoadDir);
162+
}
163+
else
164+
Debug.LogError(
165+
$"Failed to import entity scene because the automatically generated SceneAndBuildConfigGUID asset was not present: '{AssetDatabaseCompatibility.GuidToPath(scene.SceneGUID)}' -> '{AssetDatabaseCompatibility.GuidToPath(change.Asset)}'");
166+
}
167+
168+
_SceneHeaderUtility.CleanupHeaders(EntityManager);
169+
170+
bool headerLoadInProgress = false;
171+
Entities.WithStructuralChanges().WithNone<DisableSceneResolveAndLoad, ResolvedSectionEntity>().ForEach(
172+
(Entity sceneEntity, ref RequestSceneHeader requestHeader, ref SceneReference scene,
173+
ref ResolvedSceneHash resolvedSceneHash, ref RequestSceneLoaded requestSceneLoaded) =>
174+
{
175+
if (!requestHeader.IsCompleted)
176+
{
177+
if ((requestSceneLoaded.LoadFlags & SceneLoadFlags.BlockOnImport) == 0)
178+
{
179+
headerLoadInProgress = true;
180+
return;
181+
}
182+
requestHeader.Complete();
183+
}
184+
185+
var headerLoadResult = SceneHeaderUtility.FinishHeaderLoad(requestHeader, scene.SceneGUID, SceneSystem.SceneLoadDir);
186+
LogResolving($"Finished header load: {scene.SceneGUID}");
187+
if (!headerLoadResult.Success)
188+
{
189+
requestHeader.Dispose();
190+
EntityManager.AddBuffer<ResolvedSectionEntity>(sceneEntity);
191+
EntityManager.RemoveComponent<RequestSceneHeader>(sceneEntity);
192+
return;
193+
}
194+
195+
ResolveSceneSectionUtility.ResolveSceneSections(EntityManager, sceneEntity, requestSceneLoaded, ref headerLoadResult.SceneMetaData.Value,
196+
m_ResolveSceneSectionArchetypes, headerLoadResult.SectionPaths, headerLoadResult.HeaderBlobOwner);
197+
requestHeader.Dispose();
198+
EntityManager.RemoveComponent<RequestSceneHeader>(sceneEntity);
199+
#if UNITY_EDITOR
200+
if (EntityManager.HasComponent<SubScene>(sceneEntity))
201+
{
202+
var subScene = EntityManager.GetComponentObject<SubScene>(sceneEntity);
203+
// Add SubScene component to section entities
204+
using (var sectionEntities = EntityManager.GetBuffer<ResolvedSectionEntity>(sceneEntity).ToNativeArray(Allocator.Temp))
205+
{
206+
for (int iSection = 0; iSection < sectionEntities.Length; ++iSection)
207+
EntityManager.AddComponentObject(sectionEntities[iSection].SectionEntity, subScene);
208+
}
209+
}
210+
#endif
211+
}).Run();
212+
213+
if (headerLoadInProgress)
214+
EditorUpdateUtility.EditModeQueuePlayerLoopUpdate();
215+
216+
if (!isDone)
217+
EditorUpdateUtility.EditModeQueuePlayerLoopUpdate();
218+
}
219+
220+
private void RemoveSceneEntities(EntityQuery query)
221+
{
222+
if (!query.IsEmptyIgnoreFilter)
223+
{
224+
using (var removeEntities = query.ToEntityArray(Allocator.TempJob))
225+
using (var removeGuids =
226+
query.ToComponentDataArray<AssetDependencyTrackerState>(Allocator.TempJob))
227+
{
228+
for (int i = 0; i != removeEntities.Length; i++)
229+
{
230+
LogResolving("Removing", removeGuids[i].SceneAndBuildConfigGUID);
231+
_AssetDependencyTracker.Remove(removeGuids[i].SceneAndBuildConfigGUID, removeEntities[i]);
232+
}
233+
}
234+
235+
EntityManager.RemoveComponent<AssetDependencyTrackerState>(query);
236+
}
237+
}
238+
239+
protected override void OnCreate()
240+
{
241+
World.GetExistingSystemManaged<ResolveSceneReferenceSystem>().Enabled = false;
242+
_sceneSystem = World.GetExistingSystem<SceneSystem>();
243+
_AssetDependencyTracker =
244+
new AssetDependencyTracker<Entity>(EntityScenesPaths.SubSceneImporterType, "Import EntityScene");
245+
_Changed = new NativeList<AssetDependencyTracker<Entity>.Completed>(32, Allocator.Persistent);
246+
_SceneHeaderUtility = new SceneHeaderUtility(this);
247+
m_ValidSceneQuery = new EntityQueryBuilder(Allocator.Temp)
248+
.WithAll<SceneReference, RequestSceneLoaded, AssetDependencyTrackerState>()
249+
.WithNone<DisableSceneResolveAndLoad>()
250+
.Build(this);
251+
Assert.IsFalse(m_ValidSceneQuery.HasFilter(), "The use of EntityQueryMask in this system will not respect the query's active filter settings.");
252+
m_ValidSceneMask = m_ValidSceneQuery.GetEntityQueryMask();
253+
254+
m_AddScenes = new EntityQueryBuilder(Allocator.Temp)
255+
.WithAll<SceneReference, RequestSceneLoaded>()
256+
.WithNone<DisableSceneResolveAndLoad, AssetDependencyTrackerState>()
257+
.Build(this);
258+
m_RemoveScenesWithoutSceneReference = new EntityQueryBuilder(Allocator.Temp)
259+
.WithAll<AssetDependencyTrackerState>().WithNone<SceneReference, RequestSceneLoaded>().Build(this);
260+
m_RemoveScenesWithDisableSceneResolveAndLoad = new EntityQueryBuilder(Allocator.Temp)
261+
.WithAll<AssetDependencyTrackerState, DisableSceneResolveAndLoad>().Build(this);
262+
m_RemoveScenesWithDisabled = new EntityQueryBuilder(Allocator.Temp)
263+
.WithAll<AssetDependencyTrackerState, Disabled>().Build(this);
264+
265+
m_ResolveSceneSectionArchetypes = ResolveSceneSectionUtility.CreateResolveSceneSectionArchetypes(EntityManager);
266+
}
267+
268+
protected override void OnDestroy()
269+
{
270+
_AssetDependencyTracker.Dispose();
271+
_Changed.Dispose();
272+
_SceneHeaderUtility.Dispose(EntityManager);
273+
}
274+
}
275+
}
276+
277+
#endif
278+

Core/Editor/UnityScenesMods/LatiosEditorResolveSceneReferenceSystem.cs.meta

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"reference": "GUID:5f3cf485eb0554709a8abbeace890c86"
3+
}

Core/Editor/UnityScenesMods/Unity.Entities.Scenes.Mods.asmref.meta

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Core/Framework/BootstrapTools.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -566,7 +566,7 @@ internal static T TryCreateCustomBootstrap<T>()
566566
else if (selectedType.IsAssignableFrom(bootType))
567567
selectedType = bootType;
568568
else if (!bootType.IsAssignableFrom(selectedType))
569-
UnityEngine.Debug.LogError($"Multiple custom {nameof(T)} exist in the project, ignoring {bootType}");
569+
UnityEngine.Debug.LogError($"Multiple custom {typeof(T)} exist in the project, ignoring {bootType} in favor of {selectedType}");
570570
}
571571
if (selectedType == null)
572572
return default;

Kinemation/Components/OptimizedSkeletonAspect.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,17 @@ public void StartNewInertialBlend(float previousDeltaTime, float maxBlendDuratio
148148
StartInertialBlendInternal(previousDeltaTime, maxBlendDurationStartingFromTimeOfPrevious, mask);
149149
}
150150

151+
/// <summary>
152+
/// Returns true if inertial blending has finished for all bones after the specified elapsed time.
153+
/// </summary>
154+
/// <param name="timeSinceStartOfBlend">The time since the start of the blend, which was the sample before
155+
/// StartNewInertialBlend was called.</param>
156+
/// <returns>True if all bones finished their inertial blend durations, false otherwise</returns>
157+
public bool IsFinishedWithInertialBlend(float timeSinceStartOfBlend)
158+
{
159+
return IsFinishedWithInertialBlendInternal(timeSinceStartOfBlend);
160+
}
161+
151162
/// <summary>
152163
/// Performs inertial blending for the entire skeleton. You may call this prior to syncing if you wish.
153164
/// </summary>

Kinemation/Components/OptimizedSkeletonAspectInternals.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,19 @@ unsafe void StartInertialBlendInternal(float previousDeltaTime, float maxBlendDu
111111
}
112112
}
113113

114+
unsafe bool IsFinishedWithInertialBlendInternal(float timesSinceStartOfBlend)
115+
{
116+
// We go unsafe here to avoid copying as these are large
117+
var inertialBlends = (InertialBlendingTransformState*)m_bonesInertialBlendStates.Reinterpret<InertialBlendingTransformState>().GetUnsafePtr();
118+
var count = m_bonesInertialBlendStates.Length;
119+
for (int i = 0; i < count; i++)
120+
{
121+
if (inertialBlends[i].NeedsBlend(timesSinceStartOfBlend))
122+
return false;
123+
}
124+
return true;
125+
}
126+
114127
unsafe void InertialBlendInternal(float timeSinceStartOfBlend)
115128
{
116129
var bufferAsArray = m_boneTransforms.Reinterpret<TransformQvvs>().AsNativeArray();

0 commit comments

Comments
 (0)