nitro-renderer/src/room/RoomManager.ts

413 lines
12 KiB
TypeScript
Raw Normal View History

2021-03-17 03:02:09 +01:00
import { NitroManager } from '../core/common/NitroManager';
import { RoomContentLoader } from '../nitro/room/RoomContentLoader';
import { RoomContentLoadedEvent } from './events/RoomContentLoadedEvent';
import { IRoomInstance } from './IRoomInstance';
import { IRoomInstanceContainer } from './IRoomInstanceContainer';
import { IRoomManager } from './IRoomManager';
import { IRoomManagerListener } from './IRoomManagerListener';
import { IRoomObjectManager } from './IRoomObjectManager';
import { IRoomObject } from './object/IRoomObject';
import { IRoomObjectController } from './object/IRoomObjectController';
import { IRoomObjectLogicFactory } from './object/logic/IRoomObjectLogicFactory';
import { IRoomObjectVisualizationFactory } from './object/visualization/IRoomObjectVisualizationFactory';
import { IGraphicAssetCollection } from './object/visualization/utils/IGraphicAssetCollection';
import { RoomInstance } from './RoomInstance';
import { RoomObjectManager } from './RoomObjectManager';
export class RoomManager extends NitroManager implements IRoomManager, IRoomInstanceContainer
{
2021-06-07 05:36:03 +02:00
public static ROOM_MANAGER_ERROR: number = -1;
public static ROOM_MANAGER_LOADING: number = 0;
public static ROOM_MANAGER_LOADED: number = 1;
public static ROOM_MANAGER_INITIALIZING: number = 2;
public static ROOM_MANAGER_INITIALIZED: number = 3;
private static CONTENT_PROCESSING_TIME_LIMIT_MILLISECONDS: number = 40;
2021-03-17 03:02:09 +01:00
private _state: number;
private _rooms: Map<string, IRoomInstance>;
private _contentLoader: RoomContentLoader;
private _updateCategories: number[];
private _listener: IRoomManagerListener;
private _visualizationFactory: IRoomObjectVisualizationFactory;
private _logicFactory: IRoomObjectLogicFactory;
private _initialLoadList: string[];
private _pendingContentTypes: string[];
private _skipContentProcessing: boolean;
private _disposed: boolean;
constructor(listener: IRoomManagerListener, visualizationFactory: IRoomObjectVisualizationFactory, logicFactory: IRoomObjectLogicFactory)
{
super();
2021-06-07 05:36:03 +02:00
this._state = RoomManager.ROOM_MANAGER_LOADED;
2021-03-17 03:02:09 +01:00
this._rooms = new Map();
this._contentLoader = null;
this._updateCategories = [];
this._listener = listener;
this._visualizationFactory = visualizationFactory;
this._logicFactory = logicFactory;
this._initialLoadList = [];
this._pendingContentTypes = [];
this._skipContentProcessing = false;
this._disposed = false;
this.onRoomContentLoadedEvent = this.onRoomContentLoadedEvent.bind(this);
this.events.addEventListener(RoomContentLoadedEvent.RCLE_SUCCESS, this.onRoomContentLoadedEvent);
this.events.addEventListener(RoomContentLoadedEvent.RCLE_FAILURE, this.onRoomContentLoadedEvent);
this.events.addEventListener(RoomContentLoadedEvent.RCLE_CANCEL, this.onRoomContentLoadedEvent);
}
public onInit(): void
{
2021-06-07 05:36:03 +02:00
if(this._state >= RoomManager.ROOM_MANAGER_INITIALIZING || !this._contentLoader) return;
2021-03-17 03:02:09 +01:00
const mandatoryLibraries = RoomContentLoader.MANDATORY_LIBRARIES;
for(const library of mandatoryLibraries)
{
if(!library) continue;
if(this._initialLoadList.indexOf(library) === -1)
{
this._contentLoader.downloadAsset(library, this.events);
this._initialLoadList.push(library);
}
}
2021-06-07 05:36:03 +02:00
this._state = RoomManager.ROOM_MANAGER_INITIALIZING;
2021-03-17 03:02:09 +01:00
}
public getRoomInstance(roomId: string): IRoomInstance
{
const existing = this._rooms.get(roomId);
if(!existing) return null;
return existing;
}
public createRoomInstance(roomId: string): IRoomInstance
{
if(this._rooms.get(roomId)) return null;
const instance = new RoomInstance(roomId, this);
this._rooms.set(instance.id, instance);
if(this._updateCategories.length)
{
for(const category of this._updateCategories)
{
instance.addUpdateCategory(category);
}
}
return instance;
}
public removeRoomInstance(roomId: string): boolean
{
const existing = this._rooms.get(roomId);
if(!existing) return false;
this._rooms.delete(roomId);
existing.dispose();
return true;
}
public createRoomObjectAndInitalize(roomId: string, objectId: number, type: string, category: number): IRoomObject
{
const instance = this.getRoomInstance(roomId);
if(!instance) return null;
let visualization = type;
let logic = type;
let assetName = type;
let asset: IGraphicAssetCollection = null;
let isLoading = false;
if(this._contentLoader.isLoaderType(type))
{
asset = this._contentLoader.getCollection(type);
if(!asset)
{
isLoading = true;
this._contentLoader.downloadAsset(type, this.events);
assetName = this._contentLoader.getPlaceholderName(type);
asset = this._contentLoader.getCollection(assetName);
if(!asset) return null;
}
visualization = asset.data.visualizationType;
logic = asset.data.logicType;
}
const object = (instance.createRoomObject(objectId, 1, type, category) as IRoomObjectController);
if(!object) return null;
if(this._visualizationFactory)
{
const visualizationInstance = this._visualizationFactory.getVisualization(visualization);
if(!visualizationInstance)
{
instance.removeRoomObject(objectId, category);
return null;
}
visualizationInstance.asset = asset;
const visualizationData = this._visualizationFactory.getVisualizationData(assetName, visualization, ((asset && asset.data) || null));
if(!visualizationData || !visualizationInstance.initialize(visualizationData))
{
instance.removeRoomObject(objectId, category);
return null;
}
object.setVisualization(visualizationInstance);
}
if(this._logicFactory)
{
const logicInstance = this._logicFactory.getLogic(logic);
object.setLogic(logicInstance);
if(logicInstance)
{
logicInstance.initialize((asset && asset.data) || null);
}
}
if(!isLoading) object.isReady = true;
this._contentLoader.setRoomObjectRoomId(object, roomId);
return object;
}
private reinitializeRoomObjectsByType(type: string): void
{
if(!type || !this._contentLoader || !this._visualizationFactory || !this._logicFactory) return;
const asset = this._contentLoader.getCollection(type);
if(!asset) return;
const visualization = asset.data.visualizationType;
const logic = asset.data.logicType;
const visualizationData = this._visualizationFactory.getVisualizationData(type, visualization, asset.data);
for(const room of this._rooms.values())
{
if(!room) continue;
for(const [ category, manager ] of room.managers.entries())
{
if(!manager) continue;
for(const object of manager.objects.getValues())
{
if(!object || object.type !== type) continue;
const visualizationInstance = this._visualizationFactory.getVisualization(visualization);
if(visualizationInstance)
{
visualizationInstance.asset = asset;
if(!visualizationData || !visualizationInstance.initialize(visualizationData))
{
manager.removeObject(object.id);
}
else
{
object.setVisualization(visualizationInstance);
const logicInstance = this._logicFactory.getLogic(logic);
object.setLogic(logicInstance);
if(logicInstance)
{
logicInstance.initialize(asset.data);
}
object.isReady = true;
if(this._listener) this._listener.objectInitialized(room.id, object.id, category);
}
}
else
{
manager.removeObject(object.id);
}
}
}
}
}
public addUpdateCategory(category: number): void
{
const index = this._updateCategories.indexOf(category);
if(index >= 0) return;
this._updateCategories.push(category);
if(!this._rooms.size) return;
for(const room of this._rooms.values())
{
if(!room) continue;
room.addUpdateCategory(category);
}
}
public removeUpdateCategory(category: number): void
{
const index = this._updateCategories.indexOf(category);
if(index === -1) return;
this._updateCategories.splice(index, 1);
if(!this._rooms.size) return;
for(const room of this._rooms.values())
{
if(!room) continue;
room.removeUpdateCategory(category);
}
}
public setContentLoader(loader: RoomContentLoader): void
{
if(this._contentLoader) this._contentLoader.dispose();
this._contentLoader = loader;
}
private processPendingContentTypes(time: number): void
{
if(this._skipContentProcessing)
{
this._skipContentProcessing = false;
return;
}
while(this._pendingContentTypes.length)
{
const type = this._pendingContentTypes.shift();
const collection = this._contentLoader.getCollection(type);
if(!collection)
{
if(this._listener)
{
this._listener.initalizeTemporaryObjectsByType(type, false);
}
this.logger.log(`Invalid Collection: ${ type }`);
continue;
}
this.reinitializeRoomObjectsByType(type);
if(this._listener) this._listener.initalizeTemporaryObjectsByType(type, true);
if(this._initialLoadList.length > 0) this.removeFromInitialLoad(type);
}
}
private removeFromInitialLoad(type: string): void
{
2021-06-07 05:36:03 +02:00
if(!type || this._state === RoomManager.ROOM_MANAGER_ERROR) return;
2021-03-17 03:02:09 +01:00
2021-06-07 05:36:03 +02:00
if(!this._contentLoader) this._state = RoomManager.ROOM_MANAGER_ERROR;
2021-03-17 03:02:09 +01:00
if(this._contentLoader.getCollection(type))
{
const i = this._initialLoadList.indexOf(type);
if(i >= 0) this._initialLoadList.splice(i, 1);
if(!this._initialLoadList.length)
{
2021-06-07 05:36:03 +02:00
this._state = RoomManager.ROOM_MANAGER_INITIALIZED;
2021-03-17 03:02:09 +01:00
if(this._listener)
{
this._listener.onRoomEngineInitalized(true);
}
}
}
else
{
2021-06-07 05:36:03 +02:00
this._state = RoomManager.ROOM_MANAGER_ERROR;
2021-03-17 03:02:09 +01:00
if(this._listener) this._listener.onRoomEngineInitalized(false);
}
}
private onRoomContentLoadedEvent(event: RoomContentLoadedEvent): void
{
if(!this._contentLoader) return;
const contentType = event.contentType;
if(this._pendingContentTypes.indexOf(contentType) >= 0) return;
this._pendingContentTypes.push(contentType);
}
public update(time: number, update: boolean = false): void
{
this.processPendingContentTypes(time);
if(!this._rooms.size) return;
for(const room of this._rooms.values()) room && room.update(time, update);
}
public createRoomObjectManager(category: number): IRoomObjectManager
{
return new RoomObjectManager();
}
public get rooms(): Map<string, IRoomInstance>
{
return this._rooms;
}
public get disposed(): boolean
{
return this._disposed;
}
2021-06-07 05:36:03 +02:00
}