Refactor digramManager observer mask, updated logger in controllerbase.

This commit is contained in:
Michael Mainguy 2024-04-23 09:10:26 -05:00
parent f9127df48a
commit e30bca5090
9 changed files with 113 additions and 156 deletions

View File

@ -9,7 +9,7 @@ import {
WebXRDefaultExperience,
WebXRInputSource
} from "@babylonjs/core";
import {DiagramManager} from "../diagram/diagramManager";
import {DiagramEventObserverMask, DiagramManager} from "../diagram/diagramManager";
import {DiagramEvent, DiagramEventType} from "../diagram/types/diagramEntity";
import log from "loglevel";
import {ControllerEventType, Controllers} from "./controllers";
@ -30,6 +30,8 @@ import {pointable} from "./functions/pointable";
import {DefaultScene} from "../defaultScene";
const CLICK_TIME = 300;
const logger = log.getLogger('Base');
export class Base {
static stickVector = Vector3.Zero();
protected xrInputSource: WebXRInputSource;
@ -44,7 +46,6 @@ export class Base {
private clickStart: number = 0;
protected readonly xr: WebXRDefaultExperience;
protected readonly diagramManager: DiagramManager;
private logger: log.Logger;
private lastPosition: Vector3 = null;
protected controllers: Controllers;
private clickMenu: ClickMenu;
@ -53,8 +54,6 @@ export class Base {
constructor(controller: WebXRInputSource,
xr: WebXRDefaultExperience,
diagramManager: DiagramManager) {
this.logger = log.getLogger('Base');
this.logger.setLevel(this.logger.levels.DEBUG);
this.xrInputSource = controller;
this.controllers = diagramManager.controllers;
this.scene = DefaultScene.Scene;
@ -69,15 +68,17 @@ export class Base {
});
this.diagramManager = diagramManager;
this.scene.onBeforeRenderObservable.add(beforeRenderObserver, -1, false, this);
//@TODO THis works, but it uses initGrip, not sure if this is the best idea
this.xrInputSource.onMotionControllerInitObservable.add(motionControllerObserver, -1, false, this);
this.controllers.controllerObserver.add((event) => {
this.logger.debug(event);
logger.debug(event);
switch (event.type) {
case ControllerEventType.PULSE:
if (event.gripId == this?.xrInputSource?.grip?.id) {
this.xrInputSource?.motionController?.pulse(.25, 30)
.then(() => {
this.logger.debug("pulse done");
logger.debug("pulse done");
});
}
break;
@ -104,7 +105,7 @@ export class Base {
}
protected initClicker(trigger: WebXRControllerComponent) {
this.logger.debug("initTrigger");
logger.debug("initTrigger");
trigger.onButtonStateChangedObservable.add(() => {
if (trigger.changes.pressed) {
if (trigger.pressed) {
@ -112,7 +113,7 @@ export class Base {
this.clickStart = Date.now();
window.setTimeout(() => {
if (this.clickStart > 0) {
this.logger.debug("grabbing and cloning");
logger.debug("grabbing and cloning");
this.grab(true);
}
}, 300, this);
@ -159,7 +160,7 @@ export class Base {
}
this.previousParentId = mesh?.parent?.id;
this.logger.warn("grabbed " + mesh?.id + " parent " + this.previousParentId);
logger.warn("grabbed " + mesh?.id + " parent " + this.previousParentId);
this.previousRotation = mesh?.rotation.clone();
this.previousScaling = mesh?.scaling.clone();
this.previousPosition = mesh?.position.clone();
@ -174,7 +175,7 @@ export class Base {
}
this.grabbedMesh = mesh;
} else {
this.logger.debug("cloning " + mesh?.id);
logger.debug("cloning " + mesh?.id);
const clone = grabAndClone(this.diagramManager, mesh, this.xrInputSource.motionController.rootMesh);
clone.newMesh.metadata.grabClone = false;
clone.newMesh.metadata.tool = false;
@ -185,7 +186,7 @@ export class Base {
type: DiagramEventType.ADD,
entity: toDiagramEntity(clone.newMesh)
}
this.diagramManager.onDiagramEventObservable.notifyObservers(event, -1);
this.diagramManager.onDiagramEventObservable.notifyObservers(event, DiagramEventObserverMask.ALL);
}
}
@ -232,22 +233,22 @@ export class Base {
const body = mesh?.physicsBody;
if (body) {
body.setMotionType(PhysicsMotionType.DYNAMIC);
this.logger.debug(body.transformNode.absolutePosition);
this.logger.debug(this.lastPosition);
logger.debug(body.transformNode.absolutePosition);
logger.debug(this.lastPosition);
if (this.lastPosition) {
body.setLinearVelocity(body.transformNode.absolutePosition.subtract(this.lastPosition).scale(20));
//body.setLinearVelocity(this.lastPosition.subtract(body.transformNode.absolutePosition).scale(20));
this.logger.debug(this.lastPosition.subtract(body.transformNode.absolutePosition).scale(20));
logger.debug(this.lastPosition.subtract(body.transformNode.absolutePosition).scale(20));
}
}
this.diagramManager.onDiagramEventObservable.notifyObservers(event, -1);
this.diagramManager.onDiagramEventObservable.notifyObservers(event, DiagramEventObserverMask.ALL);
}
private click() {
let mesh = this.xr.pointerSelection.getMeshUnderPointer(this.xrInputSource.uniqueId);
if (pointable(mesh)) {
this.logger.debug("click on " + mesh.id);
logger.debug("click on " + mesh.id);
if (this.clickMenu && !this.clickMenu.isDisposed) {
if (this.clickMenu.isConnecting) {
this.clickMenu.connect(mesh);
@ -258,7 +259,7 @@ export class Base {
}
} else {
this.logger.debug("click on nothing");
logger.debug("click on nothing");
}
@ -270,7 +271,6 @@ export class Base {
if (grip.pressed) {
this.grab();
} else {
this.drop();
}
}

View File

@ -1,5 +1,8 @@
import log from "loglevel";
const logger = log.getLogger('motionControllerObserver');
export function motionControllerObserver(init) {
this.logger.debug(init.components);
logger.debug(init.components);
if (init.components['xr-standard-squeeze']) {
this.initGrip(init.components['xr-standard-squeeze'])
}

View File

@ -1,7 +1,7 @@
import {AbstractMesh, KeyboardEventTypes, MeshBuilder, Scene} from "@babylonjs/core";
import {Rigplatform} from "./rigplatform";
import {ControllerEventType, Controllers} from "./controllers";
import {DiagramManager} from "../diagram/diagramManager";
import {DiagramEventObserverMask, DiagramManager} from "../diagram/diagramManager";
import {GridMaterial} from "@babylonjs/materials";
import {wheelHandler} from "./functions/wheelHandler";
import log, {Logger} from "loglevel";
@ -206,7 +206,7 @@ export class WebController {
this.diagramManager.onDiagramEventObservable.notifyObservers({
type: DiagramEventType.MODIFY,
entity: toDiagramEntity(this.mesh)
}, -1);
}, DiagramEventObserverMask.ALL);
}
this.mesh = null;
}

View File

@ -1,4 +1,4 @@
import {AbstractMesh, ActionManager, Color3, InstancedMesh, Mesh, Observable, Scene} from "@babylonjs/core";
import {AbstractMesh, ActionManager, InstancedMesh, Mesh, Observable, Scene} from "@babylonjs/core";
import {DiagramEvent, DiagramEventType} from "./types/diagramEntity";
import log from "loglevel";
import {Controllers} from "../controllers/controllers";
@ -16,7 +16,11 @@ import {InputTextView} from "../information/inputTextView";
import {DefaultScene} from "../defaultScene";
import {ScaleMenu} from "../menus/scaleMenu";
export enum DiagramEventObserverMask {
ALL = -1,
FROM_DB = 1,
TO_DB = 2,
}
export class DiagramManager {
public readonly _config: AppConfig;
private readonly _controllers: Controllers;
@ -39,10 +43,7 @@ export class DiagramManager {
if (mesh) {
const entity = toDiagramEntity(mesh);
entity.text = evt.text;
this.onDiagramEventObservable.notifyObservers({
type: DiagramEventType.MODIFY,
entity: entity
}, -1);
this.notifyAll({type: DiagramEventType.MODIFY, entity: entity});
} else {
this.logger.error("mesh not found", evt.id);
}
@ -51,29 +52,13 @@ export class DiagramManager {
this.toolbox = new Toolbox();
this.scaleMenu = new ScaleMenu();
this.scaleMenu.onScaleChangeObservable.add((mesh: AbstractMesh) => {
this.onDiagramEventObservable.notifyObservers({
type: DiagramEventType.MODIFY,
entity: toDiagramEntity(mesh),
}, -1);
this.notifyAll({type: DiagramEventType.MODIFY, entity: toDiagramEntity(mesh)});
const position = mesh.absolutePosition.clone();
position.y = mesh.getBoundingInfo().boundingBox.maximumWorld.y + .1;
this.scaleMenu.changePosition(position);
});
//this.presentationManager = new PresentationManager(this._scene);
this.diagramEntityActionManager = buildEntityActionManager(this._controllers);
if (this.onDiagramEventObservable.hasObservers()) {
this.logger.warn("onDiagramEventObservable already has Observers, you should be careful");
}
this.toolbox.colorChangeObservable.add((evt) => {
this.logger.debug(evt);
this.onDiagramEventObservable.notifyObservers({
type: DiagramEventType.CHANGECOLOR,
oldColor: Color3.FromHexString(evt.oldColor), newColor: Color3.FromHexString(evt.newColor)
}, 2);
}, -1, true, this, false);
this.onDiagramEventObservable.add(this.onDiagramEvent, 1, true, this);
this.onDiagramEventObservable.add(this.onDiagramEvent, DiagramEventObserverMask.FROM_DB, true, this);
this.logger.debug("DiagramManager constructed");
this._scene.onMeshRemovedObservable.add((mesh) => {
@ -82,10 +67,7 @@ export class DiagramManager {
this._scene.meshes.forEach((m) => {
if (m?.metadata?.to == mesh.id || m?.metadata?.from == mesh.id) {
this.logger.debug("removing connection", m.id);
this.onDiagramEventObservable.notifyObservers({
type: DiagramEventType.REMOVE,
entity: toDiagramEntity(m)
}, -1);
this.notifyAll({type: DiagramEventType.REMOVE, entity: toDiagramEntity(m)});
}
});
}
@ -93,6 +75,10 @@ export class DiagramManager {
});
}
private notifyAll(event: DiagramEvent) {
this.onDiagramEventObservable.notifyObservers(event, DiagramEventObserverMask.ALL);
}
public editText(mesh: AbstractMesh) {
this.inputTextView.show(mesh);
}
@ -105,10 +91,6 @@ export class DiagramManager {
return this._config;
}
public get scene(): Scene {
return this._scene;
}
public createCopy(mesh: AbstractMesh, copy: boolean = false): AbstractMesh {
let newMesh;
if (!mesh.isAnInstance) {

View File

@ -38,7 +38,6 @@ export function diagramEventHandler(event: DiagramEvent,
updateTextNode(mesh, entity.text);
}
switch (event.type) {
case DiagramEventType.RESET:
scene.getNodes().forEach((node) => {
if (node?.metadata?.template && !node?.metadata?.tool) {

View File

@ -0,0 +1,17 @@
export function hex_to_ascii(input) {
var hex = input.toString();
let output = '';
for (let n = 0; n < hex.length; n += 2) {
output += String.fromCharCode(parseInt(hex.substr(n, 2), 16));
}
return output;
}
export function ascii_to_hex(str) {
const arr1 = [];
for (let n = 0, l = str.length; n < l; n++) {
var hex = Number(str.charCodeAt(n)).toString(16);
arr1.push(hex);
}
return arr1.join('');
}

View File

@ -1,14 +1,16 @@
import PouchDB from 'pouchdb';
import {DiagramEntity, DiagramEventType} from "../diagram/types/diagramEntity";
import {Color3, Observable} from "@babylonjs/core";
import {Observable} from "@babylonjs/core";
import axios from "axios";
import {DiagramManager} from "../diagram/diagramManager";
import {DiagramEventObserverMask, DiagramManager} from "../diagram/diagramManager";
import log, {Logger} from "loglevel";
import {ascii_to_hex} from "./functions/hexFunctions";
import {getPath} from "../util/functions/getPath";
const logger: Logger = log.getLogger('PouchdbPersistenceManager');
export class PouchdbPersistenceManager {
updateObserver: Observable<DiagramEntity> = new Observable<DiagramEntity>();
removeObserver: Observable<DiagramEntity> = new Observable<DiagramEntity>();
onDBUpdateObservable: Observable<DiagramEntity> = new Observable<DiagramEntity>();
onDBRemoveObservable: Observable<DiagramEntity> = new Observable<DiagramEntity>();
private db: PouchDB;
private remote: PouchDB;
@ -17,54 +19,38 @@ export class PouchdbPersistenceManager {
constructor() {
}
public setDiagramManager(diagramManager: DiagramManager) {
diagramManager.onDiagramEventObservable.add((evt) => {
logger.debug(evt);
switch (evt.type) {
case DiagramEventType.CHANGECOLOR:
this.changeColor(evt.oldColor, evt.newColor);
break;
case DiagramEventType.ADD:
this.add(evt.entity);
break;
case DiagramEventType.REMOVE:
this.remove(evt.entity.id);
break;
case DiagramEventType.ADD:
case DiagramEventType.MODIFY:
case DiagramEventType.DROP:
this.modify(evt.entity);
this.upsert(evt.entity);
break;
default:
logger.warn('unknown diagram event type', evt);
}
}, 2);
this.updateObserver.add((evt) => {
}, DiagramEventObserverMask.TO_DB);
this.onDBUpdateObservable.add((evt) => {
logger.debug(evt);
diagramManager.onDiagramEventObservable.notifyObservers({
type: DiagramEventType.ADD,
entity: evt
}, 1);
}, DiagramEventObserverMask.FROM_DB);
});
this.removeObserver.add((entity) => {
this.onDBRemoveObservable.add((entity) => {
logger.debug(entity);
diagramManager.onDiagramEventObservable.notifyObservers(
{type: DiagramEventType.REMOVE, entity: entity}, 1);
{type: DiagramEventType.REMOVE, entity: entity}, DiagramEventObserverMask.FROM_DB);
});
}
public async add(entity: DiagramEntity) {
if (!entity) {
return;
}
const newEntity = {...entity, _id: entity.id};
try {
this.db.put(newEntity);
} catch (err) {
logger.error(err);
}
}
public async remove(id: string) {
if (!id) {
return;
@ -77,78 +63,62 @@ export class PouchdbPersistenceManager {
}
}
public async modify(entity: DiagramEntity) {
public async upsert(entity: DiagramEntity) {
if (!entity) {
return;
}
try {
const doc = await this.db.get(entity.id);
const newDoc = {...doc, ...entity};
this.db.put(newDoc);
if (doc) {
const newDoc = {...doc, ...entity};
this.db.put(newDoc);
}
} catch (err) {
logger.error(err);
if (err.status == 404) {
try {
const newEntity = {...entity, _id: entity.id};
this.db.put(newEntity);
} catch (err2) {
logger.error(err2);
}
} else {
logger.error(err);
}
}
}
public async getNewRelicData(): Promise<any[]> {
return [];
}
public async setNewRelicData(data: any[]): Promise<any> {
return data;
}
public async initialize() {
if (!await this.initLocal()) {
return;
}
await this.sendLocalDataToScene();
}
private async initLocal(): Promise<boolean> {
try {
let current = this.getPath();
if (current) {
this.db = new PouchDB(current);
} else {
current = 'public';
this.db = new PouchDB(current);
}
let current = getPath() || 'public';
this.db = new PouchDB(current);
await this.beginSync(current);
return true;
} catch (err) {
logger.error(err);
logger.error('cannot initialize pouchdb for sync');
return;
return false;
}
}
private async sendLocalDataToScene() {
try {
const all = await this.db.allDocs({include_docs: true});
for (const entity of all.rows) {
logger.debug(entity.doc);
this.updateObserver.notifyObservers(entity.doc, 1);
this.onDBUpdateObservable.notifyObservers(entity.doc, 1);
}
} catch (err) {
logger.error(err);
}
}
private getPath(): string {
const path = window.location.pathname.split('/');
if (path.length == 3 && path[1]) {
return path[2];
} else {
return null;
}
}
async changeColor(oldColor: Color3, newColor: Color3) {
const all = await this.db.allDocs({include_docs: true});
for (const entity of all.rows) {
logger.debug(`comparing ${entity.doc.color} to ${oldColor.toHexString()}`);
if (entity.doc.color == oldColor.toHexString()) {
entity.doc.color = newColor.toHexString();
this.db.put({...entity.doc, _rev: entity.doc._rev});
}
}
}
sync() {
@ -162,20 +132,17 @@ export class PouchdbPersistenceManager {
logger.debug(doc);
if (doc._deleted) {
logger.debug('Delete', doc);
this.removeObserver.notifyObservers({id: doc._id, template: doc.template}, 1);
this.onDBRemoveObservable.notifyObservers({id: doc._id, template: doc.template}, 1);
} else {
this.updateObserver.notifyObservers(doc, 1);
this.onDBUpdateObservable.notifyObservers(doc, 1);
}
}
}
}
private async beginSync(localName: string) {
try {
//const remoteDbName = "db1";
const userHex = ascii_to_hex(localName);
const remoteDbName = 'userdb-' + userHex;
const remoteUserName = localName;
@ -185,7 +152,6 @@ export class PouchdbPersistenceManager {
if (dbs.data.indexOf(remoteDbName) == -1) {
logger.warn('sync target missing attempting to create');
const newdb = await axios.post(import.meta.env.VITE_CREATE_ENDPOINT,
{
"_id": "org.couchdb.user:" + localName,
"name": localName,
@ -229,7 +195,6 @@ export class PouchdbPersistenceManager {
{auth: {username: remoteUserName, password: password}, skip_setup: true});
const dbInfo = await this.remote.info();
logger.debug(dbInfo);
this.db.sync(this.remote, {live: true, retry: true})
.on('change', (info) => {
this.syncDoc(info)
@ -249,20 +214,3 @@ export class PouchdbPersistenceManager {
}
}
function hex_to_ascii(input) {
var hex = input.toString();
let output = '';
for (let n = 0; n < hex.length; n += 2) {
output += String.fromCharCode(parseInt(hex.substr(n, 2), 16));
}
return output;
}
function ascii_to_hex(str) {
const arr1 = [];
for (let n = 0, l = str.length; n < l; n++) {
var hex = Number(str.charCodeAt(n)).toString(16);
arr1.push(hex);
}
return arr1.join('');
}

View File

@ -1,7 +1,7 @@
import {AbstractMesh, Scene, TransformNode, Vector3} from "@babylonjs/core";
import {DiagramEvent, DiagramEventType} from "../diagram/types/diagramEntity";
import {toDiagramEntity} from "../diagram/functions/toDiagramEntity";
import {DiagramManager} from "../diagram/diagramManager";
import {DiagramEventObserverMask, DiagramManager} from "../diagram/diagramManager";
import {DiagramConnection} from "../diagram/diagramConnection";
import {isDiagramEntity} from "../diagram/functions/isDiagramEntity";
import {HtmlButton} from "babylon-html";
@ -27,7 +27,7 @@ export class ClickMenu {
entity:
toDiagramEntity(this._mesh)
}
this.diagramManager.onDiagramEventObservable.notifyObservers(event, -1);
this.diagramManager.onDiagramEventObservable.notifyObservers(event, DiagramEventObserverMask.ALL);
this.dispose();
}
}, -1, false, this, false);
@ -88,7 +88,7 @@ export class ClickMenu {
this.diagramManager.onDiagramEventObservable.notifyObservers({
type: DiagramEventType.ADD,
entity: toDiagramEntity(this.connection.mesh)
}, -1);
}, DiagramEventObserverMask.ALL);
this.connection = null;
this.dispose();
}

View File

@ -0,0 +1,8 @@
export function getPath(): string {
const path = window.location.pathname.split('/');
if (path.length == 3 && path[1]) {
return path[2];
} else {
return null;
}
}