Refactor runtime schedule synchronization to use a centralized sync context and result object

This commit is contained in:
2026-04-27 16:29:13 +02:00
parent 4fbdcc73f8
commit 4a3d44513e

View File

@@ -5191,57 +5191,18 @@ export class RuntimeHost {
return; return;
} }
const nextResolvedScheduler = resolveRuntimeProjectScheduleState({ this.runtimeScheduleSyncContext ??= createRuntimeScheduleSyncContext(
scheduler: this.runtimeScene.scheduler.document, this.runtimeScene
sequences: this.runtimeScene.sequences, );
actorIds: this.runtimeScene.npcDefinitions.map((npc) => npc.actorId),
dayNumber: this.currentClockState.dayCount + 1, const syncResult = syncRuntimeSceneScheduleToClock({
timeOfDayHours: this.currentClockState.timeOfDayHours, runtimeScene: this.runtimeScene,
pathsById: new Map(this.runtimeScene.paths.map((path) => [path.id, path])) clock: this.currentClockState,
context: this.runtimeScheduleSyncContext
}); });
const actorStates = new Map(
nextResolvedScheduler.actors.map((state) => [state.actorId, state])
);
const nextActiveImpulseRoutineIds = new Set(
nextResolvedScheduler.impulses.map((routine) => routine.routineId)
);
let changed = false;
for (const npc of this.runtimeScene.npcDefinitions) { for (const change of syncResult.npcChanges) {
const actorState = actorStates.get(npc.actorId); const { npc } = change;
const previousActive = npc.active;
const previousRoutineId = npc.activeRoutineId;
const previousRoutineTitle = npc.activeRoutineTitle;
const previousAnimationClipName = npc.animationClipName;
const previousAnimationLoop = npc.animationLoop;
const previousYawDegrees = npc.yawDegrees;
const previousPosition = {
x: npc.position.x,
y: npc.position.y,
z: npc.position.z
};
const previousPathId = npc.resolvedPath?.pathId ?? null;
const previousPathProgress = npc.resolvedPath?.progress ?? null;
applyActorScheduleStateToNpcDefinition(npc, actorState ?? null);
if (
npc.active === previousActive &&
npc.activeRoutineId === previousRoutineId &&
npc.activeRoutineTitle === previousRoutineTitle &&
npc.animationClipName === previousAnimationClipName &&
npc.animationLoop === previousAnimationLoop &&
npc.yawDegrees === previousYawDegrees &&
npc.position.x === previousPosition.x &&
npc.position.y === previousPosition.y &&
npc.position.z === previousPosition.z &&
(npc.resolvedPath?.pathId ?? null) === previousPathId &&
(npc.resolvedPath?.progress ?? null) === previousPathProgress
) {
continue;
}
changed = true;
const renderGroup = this.modelRenderObjects.get(npc.entityId); const renderGroup = this.modelRenderObjects.get(npc.entityId);
if (renderGroup !== undefined) { if (renderGroup !== undefined) {
@@ -5249,11 +5210,7 @@ export class RuntimeHost {
this.syncNpcRenderGroupTransform(renderGroup, npc); this.syncNpcRenderGroupTransform(renderGroup, npc);
} }
if ( if (this.animationMixers.has(npc.entityId) && change.animationChanged) {
this.animationMixers.has(npc.entityId) &&
(npc.animationClipName !== previousAnimationClipName ||
npc.animationLoop !== previousAnimationLoop)
) {
if (npc.animationClipName === null) { if (npc.animationClipName === null) {
this.applyStopAnimationAction(npc.entityId); this.applyStopAnimationAction(npc.entityId);
} else { } else {
@@ -5266,14 +5223,9 @@ export class RuntimeHost {
} }
} }
const nextResolvedControl = applyRuntimeProjectScheduleToControlState( this.syncResolvedControlStateToRuntime(syncResult.resolvedControl);
this.runtimeScene.control.resolved,
nextResolvedScheduler,
this.runtimeScene.control.baselineResolved
);
this.syncResolvedControlStateToRuntime(nextResolvedControl);
for (const impulseRoutine of nextResolvedScheduler.impulses) { for (const impulseRoutine of syncResult.resolvedScheduler.impulses) {
if ( if (
this.activeScheduledImpulseRoutineIds.has(impulseRoutine.routineId) || this.activeScheduledImpulseRoutineIds.has(impulseRoutine.routineId) ||
this.completedScheduledImpulseRoutineIds.has(impulseRoutine.routineId) this.completedScheduledImpulseRoutineIds.has(impulseRoutine.routineId)
@@ -5288,32 +5240,15 @@ export class RuntimeHost {
this.completedScheduledImpulseRoutineIds.add(impulseRoutine.routineId); this.completedScheduledImpulseRoutineIds.add(impulseRoutine.routineId);
} }
this.runtimeScene.scheduler.resolved = nextResolvedScheduler; commitRuntimeScheduleSyncResult(this.runtimeScene, syncResult);
this.runtimeScene.control.resolved = nextResolvedControl; this.activeScheduledImpulseRoutineIds =
this.activeScheduledImpulseRoutineIds = nextActiveImpulseRoutineIds; syncResult.nextActiveImpulseRoutineIds;
if (changed) { if (syncResult.npcColliderCollectionChanged) {
this.refreshRuntimeNpcCollections();
this.refreshCollisionWorldForNpcSchedule(); this.refreshCollisionWorldForNpcSchedule();
} }
} }
private refreshRuntimeNpcCollections() {
if (this.runtimeScene === null) {
return;
}
this.runtimeScene.entities.npcs = this.runtimeScene.npcDefinitions
.filter((npc) => npc.active)
.map((npc) => createRuntimeNpcFromDefinition(npc));
this.runtimeScene.colliders = [
...this.runtimeScene.staticColliders,
...this.runtimeScene.entities.npcs
.map((npc) => buildRuntimeNpcCollider(npc))
.filter(isNonNull)
];
}
private refreshCollisionWorldForNpcSchedule() { private refreshCollisionWorldForNpcSchedule() {
if (this.runtimeScene === null) { if (this.runtimeScene === null) {
return; return;