Migrate from legacy config to new AppConfig singleton system
Remove dual config system and migrate all code to use appConfigInstance. **Phase 1: Update VR Controller Code** - snapAll.ts: Replace getAppConfig() with appConfigInstance.current - Use `rotateSnap > 0` instead of rotationSnapEnabled flag - Use `locationSnap > 0` instead of locationSnapEnabled flag - Remove parseFloat() calls (values already numbers) - groundMeshObserver.ts: Direct property replacement - flyModeEnabled → flyMode - snapTurnSnap → turnSnap (remove parseFloat) - customPhysics.ts: Add enabled checks and update - Add `> 0` checks (was applying unconditionally) - Use locationSnap and rotateSnap directly **Phase 2: Remove Legacy Config Bridge** - vrConfigPanel.ts: Remove syncLegacyConfig() method and all calls - configModal.tsx: Remove legacy localStorage 'config' writes **Phase 3: Cleanup** - appConfig.ts: Remove legacy code (ConfigType, getAppConfig(), setAppConfig()) - Remove unused log import **Benefits:** - Eliminates dual config system confusion - Fixes precision error from string "0" values - Single source of truth via appConfigInstance - Reactive updates via Observable pattern - Cleaner, simpler codebase 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
3cf3d996dc
commit
c66da87401
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "immersive",
|
"name": "immersive",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.8-28",
|
"version": "0.0.8-30",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|||||||
@ -1,23 +1,23 @@
|
|||||||
import {TransformNode, Vector3} from "@babylonjs/core";
|
import {TransformNode, Vector3} from "@babylonjs/core";
|
||||||
import {getAppConfig} from "../../util/appConfig";
|
import {appConfigInstance} from "../../util/appConfig";
|
||||||
import {snapRotateVal} from "../../util/functions/snapRotateVal";
|
import {snapRotateVal} from "../../util/functions/snapRotateVal";
|
||||||
import {snapGridVal} from "../../util/functions/snapGridVal";
|
import {snapGridVal} from "../../util/functions/snapGridVal";
|
||||||
|
|
||||||
export function snapAll(node: TransformNode, pickPoint: Vector3) {
|
export function snapAll(node: TransformNode, pickPoint: Vector3) {
|
||||||
const config = getAppConfig();
|
const config = appConfigInstance.current;
|
||||||
const transform = new TransformNode('temp', node.getScene());
|
const transform = new TransformNode('temp', node.getScene());
|
||||||
transform.position = pickPoint;
|
transform.position = pickPoint;
|
||||||
node.setParent(transform);
|
node.setParent(transform);
|
||||||
if (config.rotationSnapEnabled) {
|
if (config.rotateSnap > 0) {
|
||||||
node.rotation = snapRotateVal(node.absoluteRotationQuaternion.toEulerAngles(), parseFloat(config.rotationSnap));
|
node.rotation = snapRotateVal(node.absoluteRotationQuaternion.toEulerAngles(), config.rotateSnap);
|
||||||
}
|
}
|
||||||
if (config.locationSnapEnabled) {
|
if (config.locationSnap > 0) {
|
||||||
transform.position = snapGridVal(transform.absolutePosition, parseFloat(config.locationSnap));
|
transform.position = snapGridVal(transform.absolutePosition, config.locationSnap);
|
||||||
}
|
}
|
||||||
|
|
||||||
node.setParent(null);
|
node.setParent(null);
|
||||||
if (config.locationSnapEnabled) {
|
if (config.locationSnap > 0) {
|
||||||
node.position = snapGridVal(node.absolutePosition, parseFloat(config.locationSnap));
|
node.position = snapGridVal(node.absolutePosition, config.locationSnap);
|
||||||
}
|
}
|
||||||
|
|
||||||
transform.dispose();
|
transform.dispose();
|
||||||
|
|||||||
@ -335,12 +335,10 @@ export class VRConfigPanel {
|
|||||||
const lastValue = appConfigInstance.current.locationSnap || 0.1;
|
const lastValue = appConfigInstance.current.locationSnap || 0.1;
|
||||||
appConfigInstance.setGridSnap(lastValue > 0 ? lastValue : 0.1);
|
appConfigInstance.setGridSnap(lastValue > 0 ? lastValue : 0.1);
|
||||||
this.updateLocationSnapButtonStates(lastValue);
|
this.updateLocationSnapButtonStates(lastValue);
|
||||||
this.syncLegacyConfig();
|
|
||||||
} else {
|
} else {
|
||||||
// Disable by setting to 0
|
// Disable by setting to 0
|
||||||
appConfigInstance.setGridSnap(0);
|
appConfigInstance.setGridSnap(0);
|
||||||
this.updateLocationSnapButtonStates(0);
|
this.updateLocationSnapButtonStates(0);
|
||||||
this.syncLegacyConfig();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -388,7 +386,6 @@ export class VRConfigPanel {
|
|||||||
if (this._locationSnapEnabled) {
|
if (this._locationSnapEnabled) {
|
||||||
appConfigInstance.setGridSnap(snap.value);
|
appConfigInstance.setGridSnap(snap.value);
|
||||||
this.updateLocationSnapButtonStates(snap.value);
|
this.updateLocationSnapButtonStates(snap.value);
|
||||||
this.syncLegacyConfig();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -457,12 +454,10 @@ export class VRConfigPanel {
|
|||||||
const lastValue = appConfigInstance.current.rotateSnap || 90;
|
const lastValue = appConfigInstance.current.rotateSnap || 90;
|
||||||
appConfigInstance.setRotateSnap(lastValue > 0 ? lastValue : 90);
|
appConfigInstance.setRotateSnap(lastValue > 0 ? lastValue : 90);
|
||||||
this.updateRotationSnapButtonStates(lastValue);
|
this.updateRotationSnapButtonStates(lastValue);
|
||||||
this.syncLegacyConfig();
|
|
||||||
} else {
|
} else {
|
||||||
// Disable by setting to 0
|
// Disable by setting to 0
|
||||||
appConfigInstance.setRotateSnap(0);
|
appConfigInstance.setRotateSnap(0);
|
||||||
this.updateRotationSnapButtonStates(0);
|
this.updateRotationSnapButtonStates(0);
|
||||||
this.syncLegacyConfig();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -510,7 +505,6 @@ export class VRConfigPanel {
|
|||||||
if (this._rotationSnapEnabled) {
|
if (this._rotationSnapEnabled) {
|
||||||
appConfigInstance.setRotateSnap(snap.value);
|
appConfigInstance.setRotateSnap(snap.value);
|
||||||
this.updateRotationSnapButtonStates(snap.value);
|
this.updateRotationSnapButtonStates(snap.value);
|
||||||
this.syncLegacyConfig();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -586,26 +580,4 @@ export class VRConfigPanel {
|
|||||||
// - Snap turn UI update
|
// - Snap turn UI update
|
||||||
// - Label rendering mode UI update
|
// - Label rendering mode UI update
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sync changes to legacy config for backward compatibility
|
|
||||||
* Legacy config is used by snapAll.ts and other older code
|
|
||||||
*/
|
|
||||||
private syncLegacyConfig(): void {
|
|
||||||
const config = appConfigInstance.current;
|
|
||||||
|
|
||||||
const legacyConfig = {
|
|
||||||
locationSnap: config.locationSnap.toString(),
|
|
||||||
locationSnapEnabled: config.locationSnap > 0,
|
|
||||||
rotationSnap: config.rotateSnap.toString(),
|
|
||||||
rotationSnapEnabled: config.rotateSnap > 0,
|
|
||||||
snapTurnSnap: config.turnSnap.toString(),
|
|
||||||
snapTurnSnapEnabled: config.turnSnap > 0,
|
|
||||||
flyModeEnabled: config.flyMode,
|
|
||||||
labelRenderingMode: config.labelRenderingMode
|
|
||||||
};
|
|
||||||
|
|
||||||
localStorage.setItem('config', JSON.stringify(legacyConfig));
|
|
||||||
this._logger.debug('Synced legacy config', legacyConfig);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -59,20 +59,6 @@ export default function ConfigModal({configOpened, closeConfig}) {
|
|||||||
appConfigInstance.setGridSnap(parseFloat(locationSnap));
|
appConfigInstance.setGridSnap(parseFloat(locationSnap));
|
||||||
appConfigInstance.setRotateSnap(parseFloat(rotationSnap));
|
appConfigInstance.setRotateSnap(parseFloat(rotationSnap));
|
||||||
appConfigInstance.setTurnSnap(parseFloat(snapTurnSnap));
|
appConfigInstance.setTurnSnap(parseFloat(snapTurnSnap));
|
||||||
|
|
||||||
// Also update legacy config for backward compatibility
|
|
||||||
const legacyConfig = {
|
|
||||||
locationSnap: locationSnap,
|
|
||||||
locationSnapEnabled: locationSnapEnabled,
|
|
||||||
rotationSnap: rotationSnap,
|
|
||||||
rotationSnapEnabled: rotationSnapEnabled,
|
|
||||||
snapTurnSnap: snapTurnSnap,
|
|
||||||
snapTurnSnapEnabled: snapTurnSnapEnabled,
|
|
||||||
flyModeEnabled: flyModeEnabled,
|
|
||||||
labelRenderingMode: labelRenderingMode
|
|
||||||
};
|
|
||||||
localStorage.setItem('config', JSON.stringify(legacyConfig));
|
|
||||||
|
|
||||||
}, [locationSnap, locationSnapEnabled, rotationSnap, rotationSnapEnabled, snapTurnSnap, snapTurnSnapEnabled, flyModeEnabled, labelRenderingMode]);
|
}, [locationSnap, locationSnapEnabled, rotationSnap, rotationSnapEnabled, snapTurnSnap, snapTurnSnapEnabled, flyModeEnabled, labelRenderingMode]);
|
||||||
return (
|
return (
|
||||||
<Modal onClose={closeConfig} opened={configOpened}>
|
<Modal onClose={closeConfig} opened={configOpened}>
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import {Observable} from "@babylonjs/core";
|
import {Observable} from "@babylonjs/core";
|
||||||
import {AppConfigType, LabelRenderingMode} from "./appConfigType";
|
import {AppConfigType, LabelRenderingMode} from "./appConfigType";
|
||||||
import log from "loglevel";
|
|
||||||
export class AppConfig {
|
export class AppConfig {
|
||||||
public readonly onConfigChangedObservable = new Observable<AppConfigType>();
|
public readonly onConfigChangedObservable = new Observable<AppConfigType>();
|
||||||
private _currentConfig: AppConfigType;
|
private _currentConfig: AppConfigType;
|
||||||
@ -88,42 +88,4 @@ export class AppConfig {
|
|||||||
|
|
||||||
// Singleton instance for app-wide configuration
|
// Singleton instance for app-wide configuration
|
||||||
// Use this instead of creating new AppConfig() instances
|
// Use this instead of creating new AppConfig() instances
|
||||||
export const appConfigInstance = new AppConfig();
|
export const appConfigInstance = new AppConfig();
|
||||||
|
|
||||||
let defaultConfig: ConfigType =
|
|
||||||
{
|
|
||||||
locationSnap: '.1',
|
|
||||||
locationSnapEnabled: true,
|
|
||||||
rotationSnap: '90',
|
|
||||||
rotationSnapEnabled: true,
|
|
||||||
flyModeEnabled: true,
|
|
||||||
snapTurnSnap: '45',
|
|
||||||
snapTurnSnapEnabled: false
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const newConfig = JSON.parse(localStorage.getItem('config'));
|
|
||||||
defaultConfig = {...defaultConfig, ...newConfig};
|
|
||||||
|
|
||||||
} catch (e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export type ConfigType = {
|
|
||||||
locationSnap: string,
|
|
||||||
locationSnapEnabled: boolean,
|
|
||||||
rotationSnap: string,
|
|
||||||
rotationSnapEnabled: boolean,
|
|
||||||
flyModeEnabled: boolean,
|
|
||||||
snapTurnSnap: string,
|
|
||||||
snapTurnSnapEnabled: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getAppConfig(): ConfigType {
|
|
||||||
return defaultConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setAppConfig(config: ConfigType) {
|
|
||||||
const logger = log.getLogger('setAppConfig');
|
|
||||||
logger.debug('setting config', JSON.stringify(config));
|
|
||||||
localStorage.setItem('config', JSON.stringify(config));
|
|
||||||
}
|
|
||||||
@ -3,7 +3,7 @@ import HavokPhysics from "@babylonjs/havok";
|
|||||||
import {snapGridVal} from "./functions/snapGridVal";
|
import {snapGridVal} from "./functions/snapGridVal";
|
||||||
import {snapRotateVal} from "./functions/snapRotateVal";
|
import {snapRotateVal} from "./functions/snapRotateVal";
|
||||||
import {isDiagramEntity} from "../diagram/functions/isDiagramEntity";
|
import {isDiagramEntity} from "../diagram/functions/isDiagramEntity";
|
||||||
import {getAppConfig} from "./appConfig";
|
import {appConfigInstance} from "./appConfig";
|
||||||
|
|
||||||
export class CustomPhysics {
|
export class CustomPhysics {
|
||||||
private readonly scene: Scene;
|
private readonly scene: Scene;
|
||||||
@ -21,6 +21,7 @@ export class CustomPhysics {
|
|||||||
|
|
||||||
scene.collisionsEnabled = true;
|
scene.collisionsEnabled = true;
|
||||||
scene.onAfterPhysicsObservable.add(() => {
|
scene.onAfterPhysicsObservable.add(() => {
|
||||||
|
const config = appConfigInstance.current;
|
||||||
scene.meshes.forEach((mesh) => {
|
scene.meshes.forEach((mesh) => {
|
||||||
if (isDiagramEntity(mesh) && mesh.physicsBody) {
|
if (isDiagramEntity(mesh) && mesh.physicsBody) {
|
||||||
const body = mesh.physicsBody;
|
const body = mesh.physicsBody;
|
||||||
@ -29,18 +30,26 @@ export class CustomPhysics {
|
|||||||
if (linearVelocity.length() < .1) {
|
if (linearVelocity.length() < .1) {
|
||||||
|
|
||||||
body.disablePreStep = false;
|
body.disablePreStep = false;
|
||||||
const pos: Vector3 = body.getObjectCenterWorld();
|
|
||||||
const val: Vector3 = snapGridVal(pos,
|
|
||||||
parseFloat(getAppConfig().locationSnap));
|
|
||||||
body.transformNode.position.set(val.x, val.y, val.z);
|
|
||||||
const rot: Quaternion =
|
|
||||||
Quaternion.FromEulerVector(
|
|
||||||
snapRotateVal(body.transformNode.rotationQuaternion.toEulerAngles(),
|
|
||||||
parseFloat(getAppConfig().rotationSnap)))
|
|
||||||
|
|
||||||
body.transformNode.rotationQuaternion.set(
|
// Apply location snap if enabled
|
||||||
rot.x, rot.y, rot.z, rot.w
|
if (config.locationSnap > 0) {
|
||||||
);
|
const pos: Vector3 = body.getObjectCenterWorld();
|
||||||
|
const val: Vector3 = snapGridVal(pos, config.locationSnap);
|
||||||
|
body.transformNode.position.set(val.x, val.y, val.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply rotation snap if enabled
|
||||||
|
if (config.rotateSnap > 0) {
|
||||||
|
const rot: Quaternion =
|
||||||
|
Quaternion.FromEulerVector(
|
||||||
|
snapRotateVal(body.transformNode.rotationQuaternion.toEulerAngles(),
|
||||||
|
config.rotateSnap));
|
||||||
|
|
||||||
|
body.transformNode.rotationQuaternion.set(
|
||||||
|
rot.x, rot.y, rot.z, rot.w
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
scene.onAfterRenderObservable.addOnce(() => {
|
scene.onAfterRenderObservable.addOnce(() => {
|
||||||
body.disablePreStep = true;
|
body.disablePreStep = true;
|
||||||
});
|
});
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import {WebController} from "../../controllers/webController";
|
|||||||
import {Rigplatform} from "../../controllers/rigplatform";
|
import {Rigplatform} from "../../controllers/rigplatform";
|
||||||
import {DiagramManager} from "../../diagram/diagramManager";
|
import {DiagramManager} from "../../diagram/diagramManager";
|
||||||
import {Spinner} from "../../objects/spinner";
|
import {Spinner} from "../../objects/spinner";
|
||||||
import {getAppConfig} from "../appConfig";
|
import {appConfigInstance} from "../appConfig";
|
||||||
import {Scene} from "@babylonjs/core";
|
import {Scene} from "@babylonjs/core";
|
||||||
|
|
||||||
|
|
||||||
@ -114,9 +114,9 @@ export async function groundMeshObserver(ground: AbstractMesh,
|
|||||||
});
|
});
|
||||||
|
|
||||||
const rig = new Rigplatform(xr, diagramManager);
|
const rig = new Rigplatform(xr, diagramManager);
|
||||||
const config = getAppConfig();
|
const config = appConfigInstance.current;
|
||||||
rig.flyMode = config.flyModeEnabled;
|
rig.flyMode = config.flyMode;
|
||||||
rig.turnSnap = parseFloat(config.snapTurnSnap);
|
rig.turnSnap = config.turnSnap;
|
||||||
const webController = new WebController(ground.getScene(), rig, diagramManager);
|
const webController = new WebController(ground.getScene(), rig, diagramManager);
|
||||||
|
|
||||||
// Set XR on diagram manager so toolbox can create exit button
|
// Set XR on diagram manager so toolbox can create exit button
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user