added resource culling and resource saving in the ResourceManager
This commit is contained in:
parent
460d0e3643
commit
b085612908
|
@ -1,6 +1,5 @@
|
||||||
import AI from "../DataTypes/Interfaces/AI";
|
import AI from "../DataTypes/Interfaces/AI";
|
||||||
import StateMachine from "../DataTypes/State/StateMachine";
|
import StateMachine from "../DataTypes/State/StateMachine";
|
||||||
import GameEvent from "../Events/GameEvent";
|
|
||||||
import GameNode from "../Nodes/GameNode";
|
import GameNode from "../Nodes/GameNode";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -17,6 +16,7 @@ export default class StateMachineAI extends StateMachine implements AI {
|
||||||
destroy(){
|
destroy(){
|
||||||
// Get rid of our reference to the owner
|
// Get rid of our reference to the owner
|
||||||
delete this.owner;
|
delete this.owner;
|
||||||
|
this.receiver.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
// @implemented
|
// @implemented
|
||||||
|
|
|
@ -13,6 +13,9 @@ export default interface Physical {
|
||||||
/** Represents whether the object is moving or not. */
|
/** Represents whether the object is moving or not. */
|
||||||
moving: boolean;
|
moving: boolean;
|
||||||
|
|
||||||
|
/** Represent whether the object is frozen from moving or not. */
|
||||||
|
frozen: boolean;
|
||||||
|
|
||||||
/** Represents whether the object is on the ground or not. */
|
/** Represents whether the object is on the ground or not. */
|
||||||
onGround: boolean;
|
onGround: boolean;
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ export default class Queue<T> implements Collection {
|
||||||
*/
|
*/
|
||||||
enqueue(item: T): void{
|
enqueue(item: T): void{
|
||||||
if((this.tail + 1) % this.MAX_ELEMENTS === this.head){
|
if((this.tail + 1) % this.MAX_ELEMENTS === this.head){
|
||||||
throw "Queue full - cannot add element"
|
throw new Error("Queue full - cannot add element");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.size += 1;
|
this.size += 1;
|
||||||
|
@ -51,7 +51,7 @@ export default class Queue<T> implements Collection {
|
||||||
*/
|
*/
|
||||||
dequeue(): T {
|
dequeue(): T {
|
||||||
if(this.head === this.tail){
|
if(this.head === this.tail){
|
||||||
throw "Queue empty - cannot remove element"
|
throw new Error("Queue empty - cannot remove element");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import Collection from "./Collection";
|
||||||
*/
|
*/
|
||||||
export default class Stack<T> implements Collection {
|
export default class Stack<T> implements Collection {
|
||||||
/** The maximum number of elements in the Stack */
|
/** The maximum number of elements in the Stack */
|
||||||
private readonly MAX_ELEMENTS: number;
|
private MAX_ELEMENTS: number;
|
||||||
|
|
||||||
/** The internal representation of the stack */
|
/** The internal representation of the stack */
|
||||||
private stack: Array<T>;
|
private stack: Array<T>;
|
||||||
|
|
|
@ -81,7 +81,7 @@ export default class EventQueue {
|
||||||
unsubscribe(receiver: Receiver, ...events: Array<string>): void {
|
unsubscribe(receiver: Receiver, ...events: Array<string>): void {
|
||||||
this.receivers.forEach(eventName => {
|
this.receivers.forEach(eventName => {
|
||||||
// If keys were provided, only continue if this key is one of them
|
// If keys were provided, only continue if this key is one of them
|
||||||
if(events !== undefined && events.indexOf(eventName) === -1) return;
|
if(events.length > 0 && events.indexOf(eventName) === -1) return;
|
||||||
|
|
||||||
// Find the index of our receiver for this key
|
// Find the index of our receiver for this key
|
||||||
let index = this.receivers.get(eventName).indexOf(receiver);
|
let index = this.receivers.get(eventName).indexOf(receiver);
|
||||||
|
|
|
@ -36,7 +36,12 @@ export default class Receiver {
|
||||||
* @param event The event to receive
|
* @param event The event to receive
|
||||||
*/
|
*/
|
||||||
receive(event: GameEvent): void {
|
receive(event: GameEvent): void {
|
||||||
|
try{
|
||||||
this.q.enqueue(event);
|
this.q.enqueue(event);
|
||||||
|
} catch(e){
|
||||||
|
console.warn("Receiver overflow for event " + event.toString());
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -33,6 +33,7 @@ export default abstract class GameNode implements Positioned, Unique, Updateable
|
||||||
/*---------- PHYSICAL ----------*/
|
/*---------- PHYSICAL ----------*/
|
||||||
hasPhysics: boolean = false;
|
hasPhysics: boolean = false;
|
||||||
moving: boolean = false;
|
moving: boolean = false;
|
||||||
|
frozen: boolean = false;
|
||||||
onGround: boolean = false;
|
onGround: boolean = false;
|
||||||
onWall: boolean = false;
|
onWall: boolean = false;
|
||||||
onCeiling: boolean = false;
|
onCeiling: boolean = false;
|
||||||
|
@ -151,11 +152,13 @@ export default abstract class GameNode implements Positioned, Unique, Updateable
|
||||||
* @param velocity The velocity with which to move the object.
|
* @param velocity The velocity with which to move the object.
|
||||||
*/
|
*/
|
||||||
move(velocity: Vec2): void {
|
move(velocity: Vec2): void {
|
||||||
|
if(this.frozen) return;
|
||||||
this.moving = true;
|
this.moving = true;
|
||||||
this._velocity = velocity;
|
this._velocity = velocity;
|
||||||
};
|
};
|
||||||
|
|
||||||
moveOnPath(speed: number, path: NavigationPath): void {
|
moveOnPath(speed: number, path: NavigationPath): void {
|
||||||
|
if(this.frozen) return;
|
||||||
this.path = path;
|
this.path = path;
|
||||||
let dir = path.getMoveDirection(this);
|
let dir = path.getMoveDirection(this);
|
||||||
this.moving = true;
|
this.moving = true;
|
||||||
|
@ -230,6 +233,9 @@ export default abstract class GameNode implements Positioned, Unique, Updateable
|
||||||
|
|
||||||
/** Removes this object from the physics system */
|
/** Removes this object from the physics system */
|
||||||
removePhysics(): void {
|
removePhysics(): void {
|
||||||
|
// Remove this from the physics manager
|
||||||
|
this.scene.getPhysicsManager().deregisterObject(this);
|
||||||
|
|
||||||
// Nullify all physics fields
|
// Nullify all physics fields
|
||||||
this.hasPhysics = false;
|
this.hasPhysics = false;
|
||||||
this.moving = false;
|
this.moving = false;
|
||||||
|
@ -250,9 +256,16 @@ export default abstract class GameNode implements Positioned, Unique, Updateable
|
||||||
this.collisionShape = null;
|
this.collisionShape = null;
|
||||||
this.colliderOffset = Vec2.ZERO;
|
this.colliderOffset = Vec2.ZERO;
|
||||||
this.sweptRect = null;
|
this.sweptRect = null;
|
||||||
|
}
|
||||||
|
|
||||||
// Remove this from the physics manager
|
/** Disables physics movement for this node */
|
||||||
this.scene.getPhysicsManager().deregisterObject(this);
|
freeze(): void {
|
||||||
|
this.frozen = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Reenables physics movement for this node */
|
||||||
|
unfreeze(): void {
|
||||||
|
this.frozen = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Prevents this object from participating in all collisions and triggers. It can still move. */
|
/** Prevents this object from participating in all collisions and triggers. It can still move. */
|
||||||
|
|
|
@ -90,7 +90,6 @@ export default abstract class UIElement extends CanvasNode {
|
||||||
}
|
}
|
||||||
if(this.onClickEventId !== null){
|
if(this.onClickEventId !== null){
|
||||||
let data = {};
|
let data = {};
|
||||||
console.log("Click event: " + this.onClickEventId)
|
|
||||||
this.emitter.fireEvent(this.onClickEventId, data);
|
this.emitter.fireEvent(this.onClickEventId, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,6 @@ export default class BasicPhysicsManager extends PhysicsManager {
|
||||||
* @param options A record of options
|
* @param options A record of options
|
||||||
*/
|
*/
|
||||||
protected parseOptions(options: Record<string, any>): void {
|
protected parseOptions(options: Record<string, any>): void {
|
||||||
console.log("Parsing physics options: ", options);
|
|
||||||
if(options.groupNames !== undefined && options.collisions !== undefined){
|
if(options.groupNames !== undefined && options.collisions !== undefined){
|
||||||
for(let i = 0; i < options.groupNames.length; i++){
|
for(let i = 0; i < options.groupNames.length; i++){
|
||||||
let group = options.groupNames[i];
|
let group = options.groupNames[i];
|
||||||
|
@ -108,6 +107,7 @@ export default class BasicPhysicsManager extends PhysicsManager {
|
||||||
|
|
||||||
// @override
|
// @override
|
||||||
deregisterObject(node: Physical): void {
|
deregisterObject(node: Physical): void {
|
||||||
|
console.log("Deregistering physics object");
|
||||||
if(node.isStatic){
|
if(node.isStatic){
|
||||||
// Remove the node from the static list
|
// Remove the node from the static list
|
||||||
const index = this.staticNodes.indexOf(node);
|
const index = this.staticNodes.indexOf(node);
|
||||||
|
|
|
@ -33,6 +33,10 @@ export default abstract class PhysicsManager implements Updateable {
|
||||||
this.groupNames = new Array();
|
this.groupNames = new Array();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
destroy(): void {
|
||||||
|
this.receiver.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers a gamenode with this physics manager
|
* Registers a gamenode with this physics manager
|
||||||
* @param object The object to register
|
* @param object The object to register
|
||||||
|
|
|
@ -81,7 +81,6 @@ export default class ResourceManager {
|
||||||
private loadonly_gl_ShaderProgramsToLoad: number;
|
private loadonly_gl_ShaderProgramsToLoad: number;
|
||||||
private loadonly_gl_ShaderLoadingQueue: Queue<KeyPath_Shader>;
|
private loadonly_gl_ShaderLoadingQueue: Queue<KeyPath_Shader>;
|
||||||
|
|
||||||
private gl_DefaultShaderPrograms: Map<WebGLProgramType>;
|
|
||||||
private gl_ShaderPrograms: Map<WebGLProgramType>;
|
private gl_ShaderPrograms: Map<WebGLProgramType>;
|
||||||
|
|
||||||
private gl_Textures: Map<number>;
|
private gl_Textures: Map<number>;
|
||||||
|
@ -90,6 +89,13 @@ export default class ResourceManager {
|
||||||
|
|
||||||
private gl: WebGLRenderingContext;
|
private gl: WebGLRenderingContext;
|
||||||
|
|
||||||
|
/* ########## UNLOADING AND EXCLUSION LIST ########## */
|
||||||
|
/** A list of resources that will be unloaded at the end of the current scene */
|
||||||
|
private resourcesToUnload: Array<ResourceReference>;
|
||||||
|
|
||||||
|
/** A list of resources to keep until further notice */
|
||||||
|
private resourcesToKeep: Array<ResourceReference>;
|
||||||
|
|
||||||
private constructor(){
|
private constructor(){
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
this.justLoaded = false;
|
this.justLoaded = false;
|
||||||
|
@ -123,14 +129,17 @@ export default class ResourceManager {
|
||||||
this.loadonly_gl_ShaderProgramsToLoad = 0;
|
this.loadonly_gl_ShaderProgramsToLoad = 0;
|
||||||
this.loadonly_gl_ShaderLoadingQueue = new Queue();
|
this.loadonly_gl_ShaderLoadingQueue = new Queue();
|
||||||
|
|
||||||
this.gl_DefaultShaderPrograms = new Map();
|
|
||||||
this.gl_ShaderPrograms = new Map();
|
this.gl_ShaderPrograms = new Map();
|
||||||
|
|
||||||
this.gl_Textures = new Map();
|
this.gl_Textures = new Map();
|
||||||
this.gl_NextTextureID = 0;
|
this.gl_NextTextureID = 0;
|
||||||
this.gl_Buffers = new Map();
|
this.gl_Buffers = new Map();
|
||||||
|
|
||||||
|
this.resourcesToUnload = new Array();
|
||||||
|
this.resourcesToKeep = new Array();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* ######################################## SINGLETON ########################################*/
|
||||||
/**
|
/**
|
||||||
* Returns the current instance of this class or a new instance if none exist
|
* Returns the current instance of this class or a new instance if none exist
|
||||||
* @returns The resource manager
|
* @returns The resource manager
|
||||||
|
@ -143,6 +152,7 @@ export default class ResourceManager {
|
||||||
return this.instance;
|
return this.instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ######################################## PUBLIC FUNCTION ########################################*/
|
||||||
/**
|
/**
|
||||||
* Activates or deactivates the use of WebGL
|
* Activates or deactivates the use of WebGL
|
||||||
* @param flag True if WebGL should be used, false otherwise
|
* @param flag True if WebGL should be used, false otherwise
|
||||||
|
@ -165,6 +175,14 @@ export default class ResourceManager {
|
||||||
this.loadonly_imageLoadingQueue.enqueue({key: key, path: path});
|
this.loadonly_imageLoadingQueue.enqueue({key: key, path: path});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tells the resource manager to keep this resource
|
||||||
|
* @param key The key of the resource
|
||||||
|
*/
|
||||||
|
public keepImage(key: string): void {
|
||||||
|
this.keepResource(key, ResourceType.IMAGE);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves a loaded image
|
* Retrieves a loaded image
|
||||||
* @param key The key of the loaded image
|
* @param key The key of the loaded image
|
||||||
|
@ -187,6 +205,14 @@ export default class ResourceManager {
|
||||||
this.loadonly_spritesheetLoadingQueue.enqueue({key: key, path: path});
|
this.loadonly_spritesheetLoadingQueue.enqueue({key: key, path: path});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tells the resource manager to keep this resource
|
||||||
|
* @param key The key of the resource
|
||||||
|
*/
|
||||||
|
public keepSpritesheet(key: string): void {
|
||||||
|
this.keepResource(key, ResourceType.SPRITESHEET);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves a loaded spritesheet
|
* Retrieves a loaded spritesheet
|
||||||
* @param key The key of the spritesheet to load
|
* @param key The key of the spritesheet to load
|
||||||
|
@ -205,6 +231,14 @@ export default class ResourceManager {
|
||||||
this.loadonly_audioLoadingQueue.enqueue({key: key, path: path});
|
this.loadonly_audioLoadingQueue.enqueue({key: key, path: path});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tells the resource manager to keep this resource
|
||||||
|
* @param key The key of the resource
|
||||||
|
*/
|
||||||
|
public keepAudio(key: string): void {
|
||||||
|
this.keepResource(key, ResourceType.AUDIO);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves a loaded audio file
|
* Retrieves a loaded audio file
|
||||||
* @param key The key of the audio file to load
|
* @param key The key of the audio file to load
|
||||||
|
@ -223,6 +257,14 @@ export default class ResourceManager {
|
||||||
this.loadonly_tilemapLoadingQueue.enqueue({key: key, path: path});
|
this.loadonly_tilemapLoadingQueue.enqueue({key: key, path: path});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tells the resource manager to keep this resource
|
||||||
|
* @param key The key of the resource
|
||||||
|
*/
|
||||||
|
public keepTilemap(key: string): void {
|
||||||
|
this.keepResource(key, ResourceType.TILEMAP);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retreives a loaded tilemap
|
* Retreives a loaded tilemap
|
||||||
* @param key The key of the loaded tilemap
|
* @param key The key of the loaded tilemap
|
||||||
|
@ -241,6 +283,14 @@ export default class ResourceManager {
|
||||||
this.loadonly_jsonLoadingQueue.enqueue({key: key, path: path});
|
this.loadonly_jsonLoadingQueue.enqueue({key: key, path: path});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tells the resource manager to keep this resource
|
||||||
|
* @param key The key of the resource
|
||||||
|
*/
|
||||||
|
public keepObject(key: string): void {
|
||||||
|
this.keepResource(key, ResourceType.JSON);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retreives a loaded object
|
* Retreives a loaded object
|
||||||
* @param key The key of the loaded object
|
* @param key The key of the loaded object
|
||||||
|
@ -250,6 +300,7 @@ export default class ResourceManager {
|
||||||
return this.jsonObjects.get(key);
|
return this.jsonObjects.get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ######################################## LOAD FUNCTION ########################################*/
|
||||||
/**
|
/**
|
||||||
* Loads all resources currently in the queue
|
* Loads all resources currently in the queue
|
||||||
* @param callback The function to cal when the resources are finished loading
|
* @param callback The function to cal when the resources are finished loading
|
||||||
|
@ -293,6 +344,21 @@ export default class ResourceManager {
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ######################################## UNLOAD FUNCTION ########################################*/
|
||||||
|
|
||||||
|
private keepResource(key: string, type: ResourceType): void {
|
||||||
|
console.log("Keep resource...");
|
||||||
|
for(let i = 0; i < this.resourcesToUnload.length; i++){
|
||||||
|
let resource = this.resourcesToUnload[i];
|
||||||
|
if(resource.key === key && resource.resourceType === type){
|
||||||
|
console.log("Found resource " + key + " of type " + type + ". Keeping.");
|
||||||
|
let resourceToMove = this.resourcesToUnload.splice(i, 1);
|
||||||
|
this.resourcesToKeep.push(...resourceToMove);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes references to all resources in the resource manager
|
* Deletes references to all resources in the resource manager
|
||||||
*/
|
*/
|
||||||
|
@ -300,29 +366,46 @@ export default class ResourceManager {
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
this.justLoaded = false;
|
this.justLoaded = false;
|
||||||
|
|
||||||
this.loadonly_imagesLoaded = 0;
|
for(let resource of this.resourcesToUnload){
|
||||||
this.loadonly_imagesToLoad = 0;
|
// Unload the resource
|
||||||
this.images.clear();
|
this.unloadResource(resource);
|
||||||
|
}
|
||||||
this.loadonly_spritesheetsLoaded = 0;
|
|
||||||
this.loadonly_spritesheetsToLoad = 0;
|
|
||||||
this.spritesheets.clear();
|
|
||||||
|
|
||||||
this.loadonly_tilemapsLoaded = 0;
|
|
||||||
this.loadonly_tilemapsToLoad = 0;
|
|
||||||
this.tilemaps.clear();
|
|
||||||
|
|
||||||
this.loadonly_audioLoaded = 0;
|
|
||||||
this.loadonly_audioToLoad = 0;
|
|
||||||
this.audioBuffers.clear();
|
|
||||||
|
|
||||||
// WebGL
|
|
||||||
// Delete all programs through webGL
|
|
||||||
this.gl_ShaderPrograms.forEach(key => this.gl_ShaderPrograms.get(key).delete(this.gl));
|
|
||||||
this.gl_ShaderPrograms.clear();
|
|
||||||
this.gl_Textures.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private unloadResource(resource: ResourceReference): void {
|
||||||
|
// Delete the resource itself
|
||||||
|
switch(resource.resourceType){
|
||||||
|
case ResourceType.IMAGE:
|
||||||
|
this.images.delete(resource.key);
|
||||||
|
if(this.gl_WebGLActive){
|
||||||
|
this.gl_Textures.delete(resource.key);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ResourceType.TILEMAP:
|
||||||
|
this.tilemaps.delete(resource.key);
|
||||||
|
break;
|
||||||
|
case ResourceType.SPRITESHEET:
|
||||||
|
this.spritesheets.delete(resource.key);
|
||||||
|
break;
|
||||||
|
case ResourceType.AUDIO:
|
||||||
|
this.audioBuffers.delete(resource.key);
|
||||||
|
break;
|
||||||
|
case ResourceType.JSON:
|
||||||
|
this.jsonObjects.delete(resource.key);
|
||||||
|
break;
|
||||||
|
case ResourceType.SHADER:
|
||||||
|
this.gl_ShaderPrograms.get(resource.key).delete(this.gl);
|
||||||
|
this.gl_ShaderPrograms.delete(resource.key);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete any dependencies
|
||||||
|
for(let dependency of resource.dependencies){
|
||||||
|
this.unloadResource(dependency);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ######################################## WORK FUNCTIONS ########################################*/
|
||||||
/**
|
/**
|
||||||
* Loads all tilemaps currently in the tilemap loading queue
|
* Loads all tilemaps currently in the tilemap loading queue
|
||||||
* @param onFinishLoading The function to call when loading is complete
|
* @param onFinishLoading The function to call when loading is complete
|
||||||
|
@ -355,22 +438,32 @@ export default class ResourceManager {
|
||||||
|
|
||||||
// We can parse the object later - it's much faster than loading
|
// We can parse the object later - it's much faster than loading
|
||||||
this.tilemaps.add(key, tilemapObject);
|
this.tilemaps.add(key, tilemapObject);
|
||||||
|
let resource = new ResourceReference(key, ResourceType.TILEMAP);
|
||||||
|
|
||||||
// Grab the tileset images we need to load and add them to the imageloading queue
|
// Grab the tileset images we need to load and add them to the imageloading queue
|
||||||
for(let tileset of tilemapObject.tilesets){
|
for(let tileset of tilemapObject.tilesets){
|
||||||
if(tileset.image){
|
if(tileset.image){
|
||||||
let key = tileset.image;
|
let key = tileset.image;
|
||||||
let path = StringUtils.getPathFromFilePath(pathToTilemapJSON) + key;
|
let path = StringUtils.getPathFromFilePath(pathToTilemapJSON) + key;
|
||||||
this.loadonly_imageLoadingQueue.enqueue({key: key, path: path});
|
this.loadonly_imageLoadingQueue.enqueue({key: key, path: path, isDependency: true});
|
||||||
|
|
||||||
|
// Add this image as a dependency to the tilemap
|
||||||
|
resource.addDependency(new ResourceReference(key, ResourceType.IMAGE));
|
||||||
} else if(tileset.tiles){
|
} else if(tileset.tiles){
|
||||||
for(let tile of tileset.tiles){
|
for(let tile of tileset.tiles){
|
||||||
let key = tile.image;
|
let key = tile.image;
|
||||||
let path = StringUtils.getPathFromFilePath(pathToTilemapJSON) + key;
|
let path = StringUtils.getPathFromFilePath(pathToTilemapJSON) + key;
|
||||||
this.loadonly_imageLoadingQueue.enqueue({key: key, path: path});
|
this.loadonly_imageLoadingQueue.enqueue({key: key, path: path, isDependency: true});
|
||||||
|
|
||||||
|
// Add this image as a dependency to the tilemap
|
||||||
|
resource.addDependency(new ResourceReference(key, ResourceType.IMAGE));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add the resource reference to the list of resource to unload
|
||||||
|
this.resourcesToUnload.push(resource);
|
||||||
|
|
||||||
// Finish loading
|
// Finish loading
|
||||||
this.finishLoadingTilemap(callbackIfLast);
|
this.finishLoadingTilemap(callbackIfLast);
|
||||||
});
|
});
|
||||||
|
@ -422,9 +515,14 @@ export default class ResourceManager {
|
||||||
// We can parse the object later - it's much faster than loading
|
// We can parse the object later - it's much faster than loading
|
||||||
this.spritesheets.add(key, spritesheet);
|
this.spritesheets.add(key, spritesheet);
|
||||||
|
|
||||||
|
let resource = new ResourceReference(key, ResourceType.SPRITESHEET);
|
||||||
|
|
||||||
// Grab the image we need to load and add it to the imageloading queue
|
// Grab the image we need to load and add it to the imageloading queue
|
||||||
let path = StringUtils.getPathFromFilePath(pathToSpritesheetJSON) + spritesheet.spriteSheetImage;
|
let path = StringUtils.getPathFromFilePath(pathToSpritesheetJSON) + spritesheet.spriteSheetImage;
|
||||||
this.loadonly_imageLoadingQueue.enqueue({key: spritesheet.name, path: path});
|
this.loadonly_imageLoadingQueue.enqueue({key: spritesheet.name, path: path, isDependency: true});
|
||||||
|
|
||||||
|
resource.addDependency(new ResourceReference(spritesheet.name, ResourceType.IMAGE));
|
||||||
|
this.resourcesToUnload.push(resource);
|
||||||
|
|
||||||
// Finish loading
|
// Finish loading
|
||||||
this.finishLoadingSpritesheet(callbackIfLast);
|
this.finishLoadingSpritesheet(callbackIfLast);
|
||||||
|
@ -460,7 +558,7 @@ export default class ResourceManager {
|
||||||
|
|
||||||
while(this.loadonly_imageLoadingQueue.hasItems()){
|
while(this.loadonly_imageLoadingQueue.hasItems()){
|
||||||
let image = this.loadonly_imageLoadingQueue.dequeue();
|
let image = this.loadonly_imageLoadingQueue.dequeue();
|
||||||
this.loadImage(image.key, image.path, onFinishLoading);
|
this.loadImage(image.key, image.path, image.isDependency, onFinishLoading);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -470,13 +568,18 @@ export default class ResourceManager {
|
||||||
* @param path The path to the image to load
|
* @param path The path to the image to load
|
||||||
* @param callbackIfLast The function to call if this is the last image
|
* @param callbackIfLast The function to call if this is the last image
|
||||||
*/
|
*/
|
||||||
public loadImage(key: string, path: string, callbackIfLast: Function): void {
|
public loadImage(key: string, path: string, isDependency: boolean, callbackIfLast: Function): void {
|
||||||
var image = new Image();
|
var image = new Image();
|
||||||
|
|
||||||
image.onload = () => {
|
image.onload = () => {
|
||||||
// Add to loaded images
|
// Add to loaded images
|
||||||
this.images.add(key, image);
|
this.images.add(key, image);
|
||||||
|
|
||||||
|
// If not a dependency, push it to the unload list. Otherwise it's managed by something else
|
||||||
|
if(!isDependency){
|
||||||
|
this.resourcesToUnload.push(new ResourceReference(key, ResourceType.IMAGE));
|
||||||
|
}
|
||||||
|
|
||||||
// If WebGL is active, create a texture
|
// If WebGL is active, create a texture
|
||||||
if(this.gl_WebGLActive){
|
if(this.gl_WebGLActive){
|
||||||
this.createWebGLTexture(key, image);
|
this.createWebGLTexture(key, image);
|
||||||
|
@ -539,6 +642,7 @@ export default class ResourceManager {
|
||||||
audioCtx.decodeAudioData(request.response, (buffer) => {
|
audioCtx.decodeAudioData(request.response, (buffer) => {
|
||||||
// Add to list of audio buffers
|
// Add to list of audio buffers
|
||||||
this.audioBuffers.add(key, buffer);
|
this.audioBuffers.add(key, buffer);
|
||||||
|
this.resourcesToUnload.push(new ResourceReference(key, ResourceType.AUDIO));
|
||||||
|
|
||||||
// Finish loading sound
|
// Finish loading sound
|
||||||
this.finishLoadingAudio(callbackIfLast);
|
this.finishLoadingAudio(callbackIfLast);
|
||||||
|
@ -592,6 +696,9 @@ export default class ResourceManager {
|
||||||
this.loadTextFile(path, (fileText: string) => {
|
this.loadTextFile(path, (fileText: string) => {
|
||||||
let obj = JSON.parse(fileText);
|
let obj = JSON.parse(fileText);
|
||||||
this.jsonObjects.add(key, obj);
|
this.jsonObjects.add(key, obj);
|
||||||
|
|
||||||
|
this.resourcesToUnload.push(new ResourceReference(key, ResourceType.JSON));
|
||||||
|
|
||||||
this.finishLoadingObject(callbackIfLast);
|
this.finishLoadingObject(callbackIfLast);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -706,6 +813,14 @@ export default class ResourceManager {
|
||||||
this.loadonly_gl_ShaderLoadingQueue.enqueue(paths);
|
this.loadonly_gl_ShaderLoadingQueue.enqueue(paths);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tells the resource manager to keep this resource
|
||||||
|
* @param key The key of the resource
|
||||||
|
*/
|
||||||
|
public keepShader(key: string): void {
|
||||||
|
this.keepResource(key, ResourceType.IMAGE);
|
||||||
|
}
|
||||||
|
|
||||||
private gl_LoadShadersFromQueue(onFinishLoading: Function): void {
|
private gl_LoadShadersFromQueue(onFinishLoading: Function): void {
|
||||||
this.loadonly_gl_ShaderProgramsToLoad = this.loadonly_gl_ShaderLoadingQueue.getSize();
|
this.loadonly_gl_ShaderProgramsToLoad = this.loadonly_gl_ShaderLoadingQueue.getSize();
|
||||||
this.loadonly_gl_ShaderProgramsLoaded = 0;
|
this.loadonly_gl_ShaderProgramsLoaded = 0;
|
||||||
|
@ -741,6 +856,8 @@ export default class ResourceManager {
|
||||||
// Add to our map
|
// Add to our map
|
||||||
this.gl_ShaderPrograms.add(key, programWrapper);
|
this.gl_ShaderPrograms.add(key, programWrapper);
|
||||||
|
|
||||||
|
this.resourcesToUnload.push(new ResourceReference(key, ResourceType.SHADER));
|
||||||
|
|
||||||
// Finish loading
|
// Finish loading
|
||||||
this.gl_FinishLoadingShader(callbackIfLast);
|
this.gl_FinishLoadingShader(callbackIfLast);
|
||||||
});
|
});
|
||||||
|
@ -769,7 +886,7 @@ export default class ResourceManager {
|
||||||
const program = this.gl.createProgram();
|
const program = this.gl.createProgram();
|
||||||
if(!program) {
|
if(!program) {
|
||||||
// Error creating
|
// Error creating
|
||||||
console.log("Failed to create program");
|
console.warn("Failed to create program");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -782,7 +899,7 @@ export default class ResourceManager {
|
||||||
if(!this.gl.getProgramParameter(program, this.gl.LINK_STATUS)){
|
if(!this.gl.getProgramParameter(program, this.gl.LINK_STATUS)){
|
||||||
// Error linking
|
// Error linking
|
||||||
const error = this.gl.getProgramInfoLog(program);
|
const error = this.gl.getProgramInfoLog(program);
|
||||||
console.log("Failed to link program: " + error);
|
console.warn("Failed to link program: " + error);
|
||||||
|
|
||||||
// Clean up
|
// Clean up
|
||||||
this.gl.deleteProgram(program);
|
this.gl.deleteProgram(program);
|
||||||
|
@ -810,7 +927,7 @@ export default class ResourceManager {
|
||||||
|
|
||||||
// If we couldn't create the shader, error
|
// If we couldn't create the shader, error
|
||||||
if(shader === null){
|
if(shader === null){
|
||||||
console.log("Unable to create shader");
|
console.warn("Unable to create shader");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -822,7 +939,7 @@ export default class ResourceManager {
|
||||||
if(!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)){
|
if(!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)){
|
||||||
// Not compiled - error
|
// Not compiled - error
|
||||||
const error = this.gl.getShaderInfoLog(shader);
|
const error = this.gl.getShaderInfoLog(shader);
|
||||||
console.log("Failed to compile shader: " + error);
|
console.warn("Failed to compile shader: " + error);
|
||||||
|
|
||||||
// Clean up
|
// Clean up
|
||||||
this.gl.deleteShader(shader);
|
this.gl.deleteShader(shader);
|
||||||
|
@ -871,9 +988,44 @@ export default class ResourceManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class representing a reference to a resource.
|
||||||
|
* This is used for the exemption list to assure assets and their dependencies don't get
|
||||||
|
* destroyed if they are still needed.
|
||||||
|
*/
|
||||||
|
class ResourceReference {
|
||||||
|
key: string;
|
||||||
|
resourceType: ResourceType;
|
||||||
|
dependencies: Array<ResourceReference>;
|
||||||
|
|
||||||
|
constructor(key: string, resourceType: ResourceType){
|
||||||
|
this.key = key;
|
||||||
|
this.resourceType = resourceType;
|
||||||
|
this. dependencies = new Array();
|
||||||
|
}
|
||||||
|
|
||||||
|
addDependency(resource: ResourceReference): void {
|
||||||
|
this.dependencies.push(resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
enum ResourceType {
|
||||||
|
IMAGE = "IMAGE",
|
||||||
|
TILEMAP = "TILEMAP",
|
||||||
|
SPRITESHEET = "SPRITESHEET",
|
||||||
|
AUDIO = "AUDIO",
|
||||||
|
JSON = "JSON",
|
||||||
|
SHADER = "SHADER"
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A pair representing a key and the path of the resource to load
|
||||||
|
*/
|
||||||
class KeyPathPair {
|
class KeyPathPair {
|
||||||
key: string;
|
key: string;
|
||||||
path: string;
|
path: string;
|
||||||
|
isDependency?: boolean = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
class KeyPath_Shader {
|
class KeyPath_Shader {
|
||||||
|
|
|
@ -90,7 +90,6 @@ export default class TilemapFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isParallaxLayer){
|
if(isParallaxLayer){
|
||||||
console.log("Adding parallax layer: " + layer.name)
|
|
||||||
sceneLayer = this.scene.addParallaxLayer(layer.name, new Vec2(1, 1), depth);
|
sceneLayer = this.scene.addParallaxLayer(layer.name, new Vec2(1, 1), depth);
|
||||||
} else {
|
} else {
|
||||||
sceneLayer = this.scene.addLayer(layer.name, depth);
|
sceneLayer = this.scene.addLayer(layer.name, depth);
|
||||||
|
|
|
@ -81,9 +81,12 @@ export default class Scene implements Updateable {
|
||||||
/** An interface that allows the adding of different nodes to the scene */
|
/** An interface that allows the adding of different nodes to the scene */
|
||||||
public add: FactoryManager;
|
public add: FactoryManager;
|
||||||
|
|
||||||
/** An interface that allows the loading of different files for use in the scene */
|
/** An interface that allows the loading of different files for use in the scene. An alias for resourceManager */
|
||||||
public load: ResourceManager;
|
public load: ResourceManager;
|
||||||
|
|
||||||
|
/** An interface that allows the loading and unloading of different files for use in the scene */
|
||||||
|
public resourceManager: ResourceManager;
|
||||||
|
|
||||||
/** The configuration options for this scene */
|
/** The configuration options for this scene */
|
||||||
public sceneOptions: SceneOptions;
|
public sceneOptions: SceneOptions;
|
||||||
|
|
||||||
|
@ -120,7 +123,8 @@ export default class Scene implements Updateable {
|
||||||
|
|
||||||
this.add = new FactoryManager(this, this.tilemaps);
|
this.add = new FactoryManager(this, this.tilemaps);
|
||||||
|
|
||||||
this.load = ResourceManager.getInstance();
|
this.load = ResourceManager.getInstance()
|
||||||
|
this.resourceManager = this.load;
|
||||||
|
|
||||||
// Get the timer manager and clear any existing timers
|
// Get the timer manager and clear any existing timers
|
||||||
TimerManager.getInstance().clearTimers();
|
TimerManager.getInstance().clearTimers();
|
||||||
|
@ -132,9 +136,6 @@ export default class Scene implements Updateable {
|
||||||
/** A lifecycle method that gets called when a new scene is created. Load all files you wish to access in the scene here. */
|
/** A lifecycle method that gets called when a new scene is created. Load all files you wish to access in the scene here. */
|
||||||
loadScene(): void {}
|
loadScene(): void {}
|
||||||
|
|
||||||
/** A lifecycle method that gets called on scene destruction. Specify which files you no longer need for garbage collection. */
|
|
||||||
unloadScene(): void {}
|
|
||||||
|
|
||||||
/** A lifecycle method called strictly after loadScene(). Create any game objects you wish to use in the scene here. */
|
/** A lifecycle method called strictly after loadScene(). Create any game objects you wish to use in the scene here. */
|
||||||
startScene(): void {}
|
startScene(): void {}
|
||||||
|
|
||||||
|
@ -144,6 +145,9 @@ export default class Scene implements Updateable {
|
||||||
*/
|
*/
|
||||||
updateScene(deltaT: number): void {}
|
updateScene(deltaT: number): void {}
|
||||||
|
|
||||||
|
/** A lifecycle method that gets called on scene destruction. Specify which files you no longer need for garbage collection. */
|
||||||
|
unloadScene(): void {}
|
||||||
|
|
||||||
update(deltaT: number): void {
|
update(deltaT: number): void {
|
||||||
this.updateScene(deltaT);
|
this.updateScene(deltaT);
|
||||||
|
|
||||||
|
@ -232,6 +236,12 @@ export default class Scene implements Updateable {
|
||||||
node.destroy();
|
node.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for(let tilemap of this.tilemaps){
|
||||||
|
tilemap.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.receiver.destroy();
|
||||||
|
|
||||||
delete this.sceneGraph;
|
delete this.sceneGraph;
|
||||||
delete this.physicsManager;
|
delete this.physicsManager;
|
||||||
delete this.navManager;
|
delete this.navManager;
|
||||||
|
|
|
@ -2,6 +2,7 @@ import Scene from "./Scene";
|
||||||
import ResourceManager from "../ResourceManager/ResourceManager";
|
import ResourceManager from "../ResourceManager/ResourceManager";
|
||||||
import Viewport from "../SceneGraph/Viewport";
|
import Viewport from "../SceneGraph/Viewport";
|
||||||
import RenderingManager from "../Rendering/RenderingManager";
|
import RenderingManager from "../Rendering/RenderingManager";
|
||||||
|
import MemoryUtils from "../Utils/MemoryUtils";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The SceneManager acts as an interface to create Scenes, and handles the lifecycle methods of Scenes.
|
* The SceneManager acts as an interface to create Scenes, and handles the lifecycle methods of Scenes.
|
||||||
|
@ -25,6 +26,7 @@ export default class SceneManager {
|
||||||
|
|
||||||
/** For consistency, only change scenes at the beginning of the update cycle */
|
/** For consistency, only change scenes at the beginning of the update cycle */
|
||||||
protected pendingScene: Scene;
|
protected pendingScene: Scene;
|
||||||
|
protected pendingSceneInit: Record<string, any>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new SceneManager
|
* Creates a new SceneManager
|
||||||
|
@ -37,6 +39,7 @@ export default class SceneManager {
|
||||||
this.viewport = viewport;
|
this.viewport = viewport;
|
||||||
this.renderingManager = renderingManager;
|
this.renderingManager = renderingManager;
|
||||||
this.idCounter = 0;
|
this.idCounter = 0;
|
||||||
|
this.pendingScene = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -46,31 +49,47 @@ export default class SceneManager {
|
||||||
* @param init An object to pass to the init function of the new scene
|
* @param init An object to pass to the init function of the new scene
|
||||||
*/
|
*/
|
||||||
public changeToScene<T extends Scene>(constr: new (...args: any) => T, init?: Record<string, any>, options?: Record<string, any>): void {
|
public changeToScene<T extends Scene>(constr: new (...args: any) => T, init?: Record<string, any>, options?: Record<string, any>): void {
|
||||||
|
console.log("Creating the new scene - change is pending until next update");
|
||||||
|
this.pendingScene = new constr(this.viewport, this, this.renderingManager, options);
|
||||||
|
this.pendingSceneInit = init;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected doSceneChange(){
|
||||||
|
console.log("Performing scene change");
|
||||||
this.viewport.setCenter(this.viewport.getHalfSize().x, this.viewport.getHalfSize().y);
|
this.viewport.setCenter(this.viewport.getHalfSize().x, this.viewport.getHalfSize().y);
|
||||||
|
|
||||||
let scene = new constr(this.viewport, this, this.renderingManager, options);
|
|
||||||
|
|
||||||
if(this.currentScene){
|
if(this.currentScene){
|
||||||
console.log("Destroying Old Scene");
|
console.log("Unloading old scene")
|
||||||
|
this.currentScene.unloadScene();
|
||||||
|
|
||||||
|
console.log("Destroying old scene");
|
||||||
this.currentScene.destroy();
|
this.currentScene.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.currentScene = scene;
|
console.log("Unloading old resources...");
|
||||||
|
this.resourceManager.unloadAllResources();
|
||||||
|
|
||||||
scene.initScene(init);
|
// Make the pending scene the current one
|
||||||
|
this.currentScene = this.pendingScene;
|
||||||
|
|
||||||
|
// Make the pending scene null
|
||||||
|
this.pendingScene = null;
|
||||||
|
|
||||||
|
// Init the scene
|
||||||
|
this.currentScene.initScene(this.pendingSceneInit);
|
||||||
|
|
||||||
// Enqueue all scene asset loads
|
// Enqueue all scene asset loads
|
||||||
scene.loadScene();
|
this.currentScene.loadScene();
|
||||||
|
|
||||||
// Load all assets
|
// Load all assets
|
||||||
console.log("Starting Scene Load");
|
console.log("Starting Scene Load");
|
||||||
this.resourceManager.loadResourcesFromQueue(() => {
|
this.resourceManager.loadResourcesFromQueue(() => {
|
||||||
console.log("Starting Scene");
|
console.log("Starting Scene");
|
||||||
scene.startScene();
|
this.currentScene.startScene();
|
||||||
scene.setRunning(true);
|
this.currentScene.setRunning(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.renderingManager.setScene(scene);
|
this.renderingManager.setScene(this.currentScene);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -85,7 +104,9 @@ export default class SceneManager {
|
||||||
* Renders the current Scene
|
* Renders the current Scene
|
||||||
*/
|
*/
|
||||||
public render(): void {
|
public render(): void {
|
||||||
this.currentScene.render();
|
if(this.currentScene){
|
||||||
|
this.currentScene.render();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -93,7 +114,11 @@ export default class SceneManager {
|
||||||
* @param deltaT The timestep of the Scene
|
* @param deltaT The timestep of the Scene
|
||||||
*/
|
*/
|
||||||
public update(deltaT: number){
|
public update(deltaT: number){
|
||||||
if(this.currentScene.isRunning()){
|
if(this.pendingScene !== null){
|
||||||
|
this.doSceneChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.currentScene && this.currentScene.isRunning()){
|
||||||
this.currentScene.update(deltaT);
|
this.currentScene.update(deltaT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -155,7 +155,7 @@ export default class Viewport {
|
||||||
* @param zoom The zoom level
|
* @param zoom The zoom level
|
||||||
*/
|
*/
|
||||||
setZoomLevel(zoom: number): void {
|
setZoomLevel(zoom: number): void {
|
||||||
this.view.halfSize.scale(1/zoom);
|
this.view.halfSize.copy(this.canvasSize.scaled(1/zoom/2));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -46,7 +46,7 @@ export default class AudioManager {
|
||||||
this.audioCtx = new AudioContext();
|
this.audioCtx = new AudioContext();
|
||||||
console.log('Web Audio API successfully loaded');
|
console.log('Web Audio API successfully loaded');
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
console.log('Web Audio API is not supported in this browser');
|
console.warn('Web Audio API is not supported in this browser');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
46
src/Wolfie2D/Utils/MemoryUtils.ts
Normal file
46
src/Wolfie2D/Utils/MemoryUtils.ts
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
import Stack from "../DataTypes/Stack";
|
||||||
|
|
||||||
|
export default class MemoryUtils {
|
||||||
|
/**
|
||||||
|
* Returns an approximate size in bytes of any object
|
||||||
|
* @param obj The object to get the size of
|
||||||
|
* @returns An approximation of the number of bytes in the object provided
|
||||||
|
*/
|
||||||
|
static approxSizeOf(obj: any): number {
|
||||||
|
let objectList = new Array<object>();
|
||||||
|
let stack = new Stack<any>(10000);
|
||||||
|
stack.push(obj);
|
||||||
|
let bytes = 0;
|
||||||
|
|
||||||
|
while(!stack.isEmpty()){
|
||||||
|
let item = stack.pop();
|
||||||
|
|
||||||
|
// We aren't interested in counting window and document
|
||||||
|
if(item === window || item === document) continue;
|
||||||
|
|
||||||
|
if((typeof item) === "boolean"){
|
||||||
|
bytes += 4;
|
||||||
|
} else if((typeof item) === "number"){
|
||||||
|
bytes += 8;
|
||||||
|
} else if((typeof item) === "string"){
|
||||||
|
bytes += item.length;
|
||||||
|
} else if((typeof item) === "object" && objectList.indexOf(item) === -1){
|
||||||
|
// We haven't seen this object before - log it
|
||||||
|
objectList.push(item);
|
||||||
|
|
||||||
|
// Get the number of bytes in all of its fields
|
||||||
|
for(let field in item){
|
||||||
|
try {
|
||||||
|
stack.push(item[field]);
|
||||||
|
} catch(e){
|
||||||
|
console.log("Pushing item: ", + item[field]);
|
||||||
|
console.warn(`Ran out of room counting memory (Stack has size ${stack.size()}) - returning current number of bytes`);
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user