diff --git a/dist/r3.js b/dist/r3.js index 09b6706..9e245ac 100644 --- a/dist/r3.js +++ b/dist/r3.js @@ -17,12 +17,12 @@ class R3 { /** * static Version - Current R3 version */ -R3.Version = '3.0.255'; +R3.Version = '3.0.261'; /** * static CompileDate - Current compile date of R3 */ -R3.CompileDate = '2021 Oct 02 - 14:30:13 pm'; +R3.CompileDate = '2021 Oct 03 - 07:35:08 am'; class System { @@ -500,6 +500,20 @@ class SystemLinking extends System { * First we need to check that this value conforms to the requirement of being an Array */ if (!(value instanceof Array)) { + + if (r3Object.underConstruction) { + /** + * We are about to throw during a construction process. This means this r3Object will not + * be created - and so we need tell all of its children that this object is no longer their + * parent so that it can be garbage collected + */ + r3Object.children.map( + function(child) { + Utils.RemoveFromArray(child.parents, r3Object); + } + ); + } + throw new TypeError('The property ' + property + ' of ' + r3Object.name + ' was not properly defined - it should be an array'); } @@ -514,7 +528,21 @@ class SystemLinking extends System { r3Object.required[r][property].map( function (constructor) { if (!(value[i] instanceof constructor)) { - throw new TypeError('The property ' + property + ' of this object is not of the correct type'); + + if (r3Object.underConstruction) { + /** + * We are about to throw during a construction process. This means this r3Object will not + * be created - and so we need tell all of its children that this object is no longer their + * parent so that it can be garbage collected + */ + r3Object.children.map( + function(child) { + Utils.RemoveFromArray(child.parents, r3Object); + } + ); + } + + throw new TypeError('The child item inside ' + property + '[] of this object is not of the correct type'); } } ); @@ -530,6 +558,20 @@ class SystemLinking extends System { } if (!(value instanceof r3Object.required[r][property])) { + + if (r3Object.underConstruction) { + /** + * We are about to throw during a construction process. This means this r3Object will not + * be created - and so we need tell all of its children that this object is no longer their + * parent so that it can be garbage collected + */ + r3Object.children.map( + function(child) { + Utils.RemoveFromArray(child.parents, r3Object); + } + ); + } + throw new TypeError('The property ' + property + ' of ' + r3Object.name + ' is not of the correct type') } @@ -555,24 +597,6 @@ class SystemLinking extends System { if (value instanceof Array) { - /** - * This object could have its property set to an empty array. - * In this case - we should check its existing components and have their relationships - * severed - */ - // if (value.length === 0) { - // - // if (r3Object[property] instanceof Array) { - // for (let i = 0; i < r3Object[property].length; i++) { - // if (r3Object[property][i] instanceof R3Object) { - // r3Object.dirty = true; - // Utils.RemoveFromArray(r3Object[property][i].parents, r3Object); - // } - // } - // } - // - // } else { - /** * We need to check if we removed an item from the existing array */ @@ -638,20 +662,177 @@ class SystemLinking extends System { } /** - * DetermineReadyState() - * - When an object is assigned some value to one of its required properties, we should determine the 'readiness' - * state of this R3 Object. Ready objects, can have their instances created. + * DetermineFutureReadyState() + * - When an object is assigned some value to one of its required properties, we should determine the future + * 'readiness' state of this R3 Object. If an object will fall out of readiness, we need to notify all relevant + * systems of the eventual demise of this object, so that they have the opportunity to cleanly stop using running + * instances of this object. * @param r3Object * @param property * @param value */ - static DetermineReadyState( + static DetermineFutureReadyState( r3Object, property, value ) { - console.log('Determining ready state for ' + r3Object.name); + console.log('Determining future ready state of ' + r3Object.name + ' because of property change : ' + property); + + for (let r = 0; r < r3Object.required.length; r++) { + + if (r3Object.ready[r]) { + + let ready = true; + + /** + * This object is currently ready - we need to check if this object will fall out of a ready state + */ + let requirements = r3Object.required[r]; + + if (requirements.hasOwnProperty(property)) { + + /** + * The property change is one of the required properties of this Object, so it affects the overall + * 'readiness' of this object. + */ + if (requirements[property] instanceof Array) { + + /** + * + */ + if (!(value instanceof Array)) { + ready = false; + } + + if (value.length === 0) { + ready = false; + } + + for (let v = 0; v < value.length; v++) { + if (!(value[v] instanceof requirements[property][0])) { + ready = false; + } + } + + } else { + + if (!(value instanceof requirements[property])) { + + ready = false; + + } + } + + } + + if (!ready) { + /** + * This object will fall out of readiness state - notify all systems + */ + Event.Emit( + Event.FUTURE_READY_STATE_FALSE, + { + r3Object, + property, + value, + requiredIndex : r + } + ); + } + + } else { + + let ready = true; + + /** + * This object is current *NOT* ready - we need to check if this object will fall into a ready state. + */ + let requirements = r3Object.required[r]; + + for (let requirementProperty in requirements) { + if (requirements.hasOwnProperty(requirementProperty)) { + + if (requirementProperty === property) { + /** + * Compare against the current value and not the r3Object[requirementProperty] + */ + + if (requirements[requirementProperty] instanceof Array) { + + } + + } + + } + } + + /** + * Now check all the other requirements (since we can only have a true ready state if *ALL* requirements are met) + */ + for (let requirement in requirements) { + + if (requirement === property) { + /** + * Skip the current property - it has already been evaluated + */ + continue; + } + + if (requirements.hasOwnProperty(requirement)) { + + if (requirements[requirement] instanceof Array) { + + if (!(r3Object[requirement] instanceof Array)) { + ready = false; + } + + if (r3Object[requirement].length === 0) { + ready = false; + } + + for (let p = 0; p < r3Object[requirement].length; p++) { + if (!(r3Object[requirement][p] instanceof requirements[requirement][0])) { + ready = false; + } + } + + } else { + if (!(r3Object[requirement] instanceof requirements[requirement])) { + ready = false; + } + } + } + } + + // if (requirements.hasOwnProperty(property)) { + // + // + // + // } else { + // ready = false; + // } + + if (ready) { + + /** + * This object will become ready - notify all systems - but don't modify the ready state yet (until after the update) + */ + Event.Emit( + Event.FUTURE_READY_STATE_TRUE, + { + r3Object, + property, + value, + requiredIndex: r + } + ); + + } + + } // if or not ready + + } // for // if (r3Object.required[property] instanceof Array) { // @@ -699,6 +880,83 @@ class SystemLinking extends System { } + /** + * DetermineActualReadyState() + * - When an object is assigned some value to one of its required properties, we should determine the current + * 'readiness' state of this R3 Object after its property has assumed the value. If the ready state of an object + * changed - we need to start / stop this Object or Entity, create / delete instances of the Component + * @param r3Object + * @param property + * @param value + */ + static DetermineActualReadyState( + r3Object, + property, + value + ) { + + console.log('Determining actual ready state of ' + r3Object.name); + + for (let r = 0; r < r3Object.required.length; r++) { + + let ready = true; + + /** + * This object is currently ready - we need to check if this object will fall out of a ready state + */ + let requirements = r3Object.required[r]; + + for (let property in requirements) { + if (requirements.hasOwnProperty(property)) { + + if (requirements[property] instanceof Array) { + + if (!(r3Object[property] instanceof Array)) { + ready = false; + } + + if (r3Object[property] .length === 0) { + ready = false; + } + + for (let v = 0; v < r3Object[property].length; v++) { + if (!(r3Object[property][v] instanceof requirements[property][0])) { + ready = false; + } + } + + } else { + if (!(r3Object[property] instanceof requirements[property])) { + ready = false; + } + } + } + } + + r3Object.ready[r] = ready; + } + + } + + /** + * RequirementsValueCheck() + * - Does a quick check of the value against the requirement + * @param requirementProperty + * @param value + */ + static RequirementsValueCheck( + requirementProperty, + value + ) { + + //GENERATED_STATIC_REQUIREMENTS_VALUE_CHECK_METHOD_START + //GENERATED_STATIC_REQUIREMENTS_VALUE_CHECK_METHOD_END + + //CUSTOM_STATIC_REQUIREMENTS_VALUE_CHECK_METHOD_START + //CUSTOM_STATIC_REQUIREMENTS_VALUE_CHECK_METHOD_END + + } + /** * ActivateInstances() * - No comment @@ -827,9 +1085,9 @@ class SystemLinking extends System { SystemLinking.SetParentChildRelationships(r3Object, property, value); /** - * Determine the ready state of the r3Object + * Determine the future ready state of the r3Object */ - SystemLinking.DetermineReadyState(r3Object, property, value); + SystemLinking.DetermineFutureReadyState(r3Object, property, value); /** * The value was unassigned - remove the parent relationships of the existing @@ -867,24 +1125,12 @@ class SystemLinking extends System { */ static OnObjectPropertyUpdated(object) { - let {r3Object} = object; + let {r3Object, property, value} = object; - if (!r3Object.underConstruction) { - - /** - * At this point - the object entity would have been brought to a stop - * if it had been transitioned into an uninitialized state by setting one of - * its required properties to a null, empty or undefined state. - * We can safely clear the dirty flag. - */ - - if (r3Object.dirty) { - r3Object.dirty = false; - } - - r3Object.initializeDepth = 0; - r3Object.initialize(); - } + /** + * Determine the actual ready state of the r3Object + */ + SystemLinking.DetermineActualReadyState(r3Object, property, value); } @@ -1908,21 +2154,29 @@ class Event { subscriptionIds.map( function(subscriptionId) { try { + let result = Event.Subscriptions[eventId][subscriptionId](data); if (clientCallback) { clientCallback(result); } + } catch (error) { + if (clientErrorCallback) { clientErrorCallback(error); } else { console.error(error); throw error; } + } } ) + } else { + if (clientCallback) { + clientCallback(); + } } } @@ -2007,42 +2261,44 @@ Event.ENTITY_CREATED = 0xa; Event.ENTITY_INITIALIZED = 0xb; Event.ENTITY_STARTED = 0xc; Event.FINAL_INITIALIZE = 0xd; -Event.GET_API_URL = 0xe; -Event.GET_RUNTIME = 0xf; -Event.GET_WINDOW_SIZE = 0x10; -Event.GRAPHICS_COMPONENT_INITIALIZED = 0x11; -Event.IMAGE_COMPONENT_INITIALIZED = 0x12; -Event.IMAGE_INSTANCE_CREATED = 0x13; -Event.INPUT_COMPONENT_INITIALIZED = 0x14; -Event.INSTANCE_CREATED = 0x15; -Event.INSTANCE_DISPOSED = 0x16; -Event.KEYBOARD_DOWN = 0x17; -Event.KEYBOARD_UP = 0x18; -Event.MOUSE_DOWN = 0x19; -Event.MOUSE_MOVE = 0x1a; -Event.MOUSE_UP = 0x1b; -Event.MOUSE_WHEEL = 0x1c; -Event.OBJECT_CREATED = 0x1d; -Event.OBJECT_PROPERTY_UPDATE = 0x1e; -Event.OBJECT_PROPERTY_UPDATED = 0x1f; -Event.PAUSE = 0x20; -Event.PROJECT_INITIALIZED = 0x21; -Event.RESTART = 0x22; -Event.RUNTIME_CREATED = 0x23; -Event.SLIDER_ENTITY_INITIALIZED = 0x24; -Event.START = 0x25; -Event.TOUCH_CANCEL = 0x26; -Event.TOUCH_COMPONENT_INITIALIZED = 0x27; -Event.TOUCH_END = 0x28; -Event.TOUCH_MOVE = 0x29; -Event.TOUCH_START = 0x2a; -Event.UPDATE_FROM_INSTANCE_AFTER = 0x2b; -Event.UPDATE_FROM_INSTANCE_BEFORE = 0x2c; -Event.UPDATE_INSTANCE_AFTER = 0x2d; -Event.UPDATE_INSTANCE_BEFORE = 0x2e; -Event.UPDATE_INSTANCE_PROPERTY = 0x2f; -Event.UPDATE_PROPERTY_FROM_INSTANCE = 0x30; -Event.MAX_EVENTS = 0x31; +Event.FUTURE_READY_STATE_FALSE = 0xe; +Event.FUTURE_READY_STATE_TRUE = 0xf; +Event.GET_API_URL = 0x10; +Event.GET_RUNTIME = 0x11; +Event.GET_WINDOW_SIZE = 0x12; +Event.GRAPHICS_COMPONENT_INITIALIZED = 0x13; +Event.IMAGE_COMPONENT_INITIALIZED = 0x14; +Event.IMAGE_INSTANCE_CREATED = 0x15; +Event.INPUT_COMPONENT_INITIALIZED = 0x16; +Event.INSTANCE_CREATED = 0x17; +Event.INSTANCE_DISPOSED = 0x18; +Event.KEYBOARD_DOWN = 0x19; +Event.KEYBOARD_UP = 0x1a; +Event.MOUSE_DOWN = 0x1b; +Event.MOUSE_MOVE = 0x1c; +Event.MOUSE_UP = 0x1d; +Event.MOUSE_WHEEL = 0x1e; +Event.OBJECT_CREATED = 0x1f; +Event.OBJECT_PROPERTY_UPDATE = 0x20; +Event.OBJECT_PROPERTY_UPDATED = 0x21; +Event.PAUSE = 0x22; +Event.PROJECT_INITIALIZED = 0x23; +Event.RESTART = 0x24; +Event.RUNTIME_CREATED = 0x25; +Event.SLIDER_ENTITY_INITIALIZED = 0x26; +Event.START = 0x27; +Event.TOUCH_CANCEL = 0x28; +Event.TOUCH_COMPONENT_INITIALIZED = 0x29; +Event.TOUCH_END = 0x2a; +Event.TOUCH_MOVE = 0x2b; +Event.TOUCH_START = 0x2c; +Event.UPDATE_FROM_INSTANCE_AFTER = 0x2d; +Event.UPDATE_FROM_INSTANCE_BEFORE = 0x2e; +Event.UPDATE_INSTANCE_AFTER = 0x2f; +Event.UPDATE_INSTANCE_BEFORE = 0x30; +Event.UPDATE_INSTANCE_PROPERTY = 0x31; +Event.UPDATE_PROPERTY_FROM_INSTANCE = 0x32; +Event.MAX_EVENTS = 0x33; Event.GetEventName = function(eventId) { @@ -2060,41 +2316,43 @@ Event.GetEventName = function(eventId) { case 0xb : return 'entity_initialized'; case 0xc : return 'entity_started'; case 0xd : return 'final_initialize'; - case 0xe : return 'get_api_url'; - case 0xf : return 'get_runtime'; - case 0x10 : return 'get_window_size'; - case 0x11 : return 'graphics_component_initialized'; - case 0x12 : return 'image_component_initialized'; - case 0x13 : return 'image_instance_created'; - case 0x14 : return 'input_component_initialized'; - case 0x15 : return 'instance_created'; - case 0x16 : return 'instance_disposed'; - case 0x17 : return 'keyboard_down'; - case 0x18 : return 'keyboard_up'; - case 0x19 : return 'mouse_down'; - case 0x1a : return 'mouse_move'; - case 0x1b : return 'mouse_up'; - case 0x1c : return 'mouse_wheel'; - case 0x1d : return 'object_created'; - case 0x1e : return 'object_property_update'; - case 0x1f : return 'object_property_updated'; - case 0x20 : return 'pause'; - case 0x21 : return 'project_initialized'; - case 0x22 : return 'restart'; - case 0x23 : return 'runtime_created'; - case 0x24 : return 'slider_entity_initialized'; - case 0x25 : return 'start'; - case 0x26 : return 'touch_cancel'; - case 0x27 : return 'touch_component_initialized'; - case 0x28 : return 'touch_end'; - case 0x29 : return 'touch_move'; - case 0x2a : return 'touch_start'; - case 0x2b : return 'update_from_instance_after'; - case 0x2c : return 'update_from_instance_before'; - case 0x2d : return 'update_instance_after'; - case 0x2e : return 'update_instance_before'; - case 0x2f : return 'update_instance_property'; - case 0x30 : return 'update_property_from_instance'; + case 0xe : return 'future_ready_state_false'; + case 0xf : return 'future_ready_state_true'; + case 0x10 : return 'get_api_url'; + case 0x11 : return 'get_runtime'; + case 0x12 : return 'get_window_size'; + case 0x13 : return 'graphics_component_initialized'; + case 0x14 : return 'image_component_initialized'; + case 0x15 : return 'image_instance_created'; + case 0x16 : return 'input_component_initialized'; + case 0x17 : return 'instance_created'; + case 0x18 : return 'instance_disposed'; + case 0x19 : return 'keyboard_down'; + case 0x1a : return 'keyboard_up'; + case 0x1b : return 'mouse_down'; + case 0x1c : return 'mouse_move'; + case 0x1d : return 'mouse_up'; + case 0x1e : return 'mouse_wheel'; + case 0x1f : return 'object_created'; + case 0x20 : return 'object_property_update'; + case 0x21 : return 'object_property_updated'; + case 0x22 : return 'pause'; + case 0x23 : return 'project_initialized'; + case 0x24 : return 'restart'; + case 0x25 : return 'runtime_created'; + case 0x26 : return 'slider_entity_initialized'; + case 0x27 : return 'start'; + case 0x28 : return 'touch_cancel'; + case 0x29 : return 'touch_component_initialized'; + case 0x2a : return 'touch_end'; + case 0x2b : return 'touch_move'; + case 0x2c : return 'touch_start'; + case 0x2d : return 'update_from_instance_after'; + case 0x2e : return 'update_from_instance_before'; + case 0x2f : return 'update_instance_after'; + case 0x30 : return 'update_instance_before'; + case 0x31 : return 'update_instance_property'; + case 0x32 : return 'update_property_from_instance'; default : throw new Error('Event type not defined : ' + eventId); } @@ -2136,6 +2394,14 @@ class R3Object extends Event { if (typeof options.name === 'undefined') { options.name = this.constructor.name + '(' + options.id + ')'; } + /** + * ready - Normally all objects are 'ready' to have their instances created, unless it has some required + * Object which is not present at time of construction and will be assigned later. All objects + * have multiple sets of 'required' objects which affect its 'ready' state. + */ + if (typeof options.ready === 'undefined') { + options.ready = []; + } /** * dirty - When dirty is true, it means that this object is in transition from having a child Object to * not having this child Object, and will probably end up in an uninitialized state. During the @@ -2173,7 +2439,7 @@ class R3Object extends Event { * initialize */ if (typeof options.required === 'undefined') { - options.required = [Object]; + options.required = []; } Object.assign(this, options); @@ -2532,6 +2798,10 @@ class EntitySlider extends Entity { } ) + for (let r = 0; r < this.required.length; r++) { + this.ready[r] = true; + } + this.underConstruction = true; Object.assign(this, options); @@ -2846,6 +3116,10 @@ class ComponentCode extends Component { options.instance = null; } + for (let r = 0; r < this.required.length; r++) { + this.ready[r] = true; + } + this.underConstruction = true; Object.assign(this, options); @@ -2940,6 +3214,10 @@ class ComponentDOM extends Component { options.instance = null; } + for (let r = 0; r < this.required.length; r++) { + this.ready[r] = true; + } + this.underConstruction = true; Object.assign(this, options); @@ -3084,6 +3362,10 @@ class ComponentCanvas extends ComponentDOM { options.style = 'border:1px solid #00bb00;'; } + for (let r = 0; r < this.required.length; r++) { + this.ready[r] = true; + } + this.underConstruction = true; Object.assign(this, options); @@ -3259,6 +3541,10 @@ class ComponentGeometry extends Component { options.instance = null; } + for (let r = 0; r < this.required.length; r++) { + this.ready[r] = true; + } + this.underConstruction = true; Object.assign(this, options); @@ -3346,6 +3632,10 @@ class ComponentBufferGeometry extends ComponentGeometry { options.instance = null; } + for (let r = 0; r < this.required.length; r++) { + this.ready[r] = true; + } + this.underConstruction = true; Object.assign(this, options); @@ -3433,6 +3723,10 @@ class ComponentPlaneGeometry extends ComponentBufferGeometry { options.instance = null; } + for (let r = 0; r < this.required.length; r++) { + this.ready[r] = true; + } + this.underConstruction = true; Object.assign(this, options); @@ -3520,6 +3814,10 @@ class ComponentGraphics extends Component { options.instance = null; } + for (let r = 0; r < this.required.length; r++) { + this.ready[r] = true; + } + this.underConstruction = true; Object.assign(this, options); @@ -3676,6 +3974,10 @@ class ComponentImage extends ComponentGraphics { options.orientation = 'square'; } + for (let r = 0; r < this.required.length; r++) { + this.ready[r] = true; + } + if (options.extension.match(/(png)$/i)) { options.contentType = 'image/png'; } @@ -4015,6 +4317,10 @@ class ComponentInput extends Component { options.instance = null; } + for (let r = 0; r < this.required.length; r++) { + this.ready[r] = true; + } + this.underConstruction = true; Object.assign(this, options); @@ -4157,6 +4463,10 @@ class ComponentTouch extends ComponentInput { } ) + for (let r = 0; r < this.required.length; r++) { + this.ready[r] = true; + } + this.underConstruction = true; Object.assign(this, options); @@ -4276,6 +4586,10 @@ class ComponentMaterial extends Component { options.instance = null; } + for (let r = 0; r < this.required.length; r++) { + this.ready[r] = true; + } + this.underConstruction = true; Object.assign(this, options); @@ -4363,6 +4677,10 @@ class ComponentMesh extends Component { options.instance = null; } + for (let r = 0; r < this.required.length; r++) { + this.ready[r] = true; + } + this.underConstruction = true; Object.assign(this, options); @@ -4450,6 +4768,10 @@ class ComponentTexture extends Component { options.instance = null; } + for (let r = 0; r < this.required.length; r++) { + this.ready[r] = true; + } + this.underConstruction = true; Object.assign(this, options); diff --git a/package.json b/package.json index 86424c8..6b14106 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "r3", - "version": "3.0.255", + "version": "3.0.262", "description": "", "private": true, "dependencies": { diff --git a/r3.php b/r3.php index 4f866b8..2325cda 100755 --- a/r3.php +++ b/r3.php @@ -628,6 +628,12 @@ function generateRequiredComponents($file, $tokens, $token, $section) updateSection($file, $section , $updates); } +function generateSection($file, $templateFile, $section) +{ + $template = file_get_contents($templateFile); + updateSection($file, $section , $template); +} + function stripRequiredComponents(&$store, $tokens) { $excluded = getTokenStore('CUSTOM_REQUIRED_COMPONENTS', $tokens); @@ -2123,6 +2129,8 @@ foreach ($files as $file) { generateRequiredComponents($file, $tokens, 'CUSTOM_REQUIRED_COMPONENTS', 'GENERATED_REQUIRED_COMPONENTS'); // generateCreateInstanceOptions($file, $tokens); + generateSection($file,'src/templates/generated_after_required_components.template' ,'GENERATED_AFTER_REQUIRED_COMPONENTS'); + generateUpdateInstanceOptions($file, $tokens, 'CUSTOM_OPTIONS', 'GENERATED_UPDATE_INSTANCE_OPTIONS', 'CUSTOM_INSTANCE_OPTIONS_MAPPING', 'CUSTOM_EXCLUDED_FROM_INSTANCE_OPTIONS'); generateUpdateInstanceOptions($file, $tokens, 'TEMPLATE_OPTIONS', 'GENERATED_TEMPLATE_UPDATE_INSTANCE_OPTIONS', 'TEMPLATE_INSTANCE_OPTIONS_MAPPING', 'TEMPLATE_EXCLUDED_FROM_INSTANCE_OPTIONS'); diff --git a/src/r3/r3-component/r3-component-buffer-geometry.js b/src/r3/r3-component/r3-component-buffer-geometry.js index c243154..8fc9c51 100644 --- a/src/r3/r3-component/r3-component-buffer-geometry.js +++ b/src/r3/r3-component/r3-component-buffer-geometry.js @@ -99,6 +99,12 @@ class ComponentBufferGeometry extends ComponentGeometry { //GENERATED_REQUIRED_COMPONENTS_START //GENERATED_REQUIRED_COMPONENTS_END + //GENERATED_AFTER_REQUIRED_COMPONENTS_START + for (let r = 0; r < this.required.length; r++) { + this.ready[r] = true; + } + //GENERATED_AFTER_REQUIRED_COMPONENTS_END + //CUSTOM_OPTIONS_INIT_START //CUSTOM_OPTIONS_INIT_END diff --git a/src/r3/r3-component/r3-component-canvas.js b/src/r3/r3-component/r3-component-canvas.js index 34adff1..80337fe 100644 --- a/src/r3/r3-component/r3-component-canvas.js +++ b/src/r3/r3-component/r3-component-canvas.js @@ -128,6 +128,12 @@ class ComponentCanvas extends ComponentDOM { //GENERATED_REQUIRED_COMPONENTS_START //GENERATED_REQUIRED_COMPONENTS_END + //GENERATED_AFTER_REQUIRED_COMPONENTS_START + for (let r = 0; r < this.required.length; r++) { + this.ready[r] = true; + } + //GENERATED_AFTER_REQUIRED_COMPONENTS_END + //CUSTOM_OPTIONS_INIT_START //CUSTOM_OPTIONS_INIT_END diff --git a/src/r3/r3-component/r3-component-code.js b/src/r3/r3-component/r3-component-code.js index ac7494e..04ade69 100644 --- a/src/r3/r3-component/r3-component-code.js +++ b/src/r3/r3-component/r3-component-code.js @@ -98,6 +98,12 @@ class ComponentCode extends Component { //GENERATED_REQUIRED_COMPONENTS_START //GENERATED_REQUIRED_COMPONENTS_END + //GENERATED_AFTER_REQUIRED_COMPONENTS_START + for (let r = 0; r < this.required.length; r++) { + this.ready[r] = true; + } + //GENERATED_AFTER_REQUIRED_COMPONENTS_END + //CUSTOM_OPTIONS_INIT_START //CUSTOM_OPTIONS_INIT_END diff --git a/src/r3/r3-component/r3-component-d-o-m.js b/src/r3/r3-component/r3-component-d-o-m.js index b69654e..e4c8b7d 100644 --- a/src/r3/r3-component/r3-component-d-o-m.js +++ b/src/r3/r3-component/r3-component-d-o-m.js @@ -105,6 +105,12 @@ class ComponentDOM extends Component { //GENERATED_REQUIRED_COMPONENTS_START //GENERATED_REQUIRED_COMPONENTS_END + //GENERATED_AFTER_REQUIRED_COMPONENTS_START + for (let r = 0; r < this.required.length; r++) { + this.ready[r] = true; + } + //GENERATED_AFTER_REQUIRED_COMPONENTS_END + //CUSTOM_OPTIONS_INIT_START //CUSTOM_OPTIONS_INIT_END diff --git a/src/r3/r3-component/r3-component-geometry.js b/src/r3/r3-component/r3-component-geometry.js index 0a11401..7e208ab 100644 --- a/src/r3/r3-component/r3-component-geometry.js +++ b/src/r3/r3-component/r3-component-geometry.js @@ -98,6 +98,12 @@ class ComponentGeometry extends Component { //GENERATED_REQUIRED_COMPONENTS_START //GENERATED_REQUIRED_COMPONENTS_END + //GENERATED_AFTER_REQUIRED_COMPONENTS_START + for (let r = 0; r < this.required.length; r++) { + this.ready[r] = true; + } + //GENERATED_AFTER_REQUIRED_COMPONENTS_END + //CUSTOM_OPTIONS_INIT_START //CUSTOM_OPTIONS_INIT_END diff --git a/src/r3/r3-component/r3-component-graphics.js b/src/r3/r3-component/r3-component-graphics.js index e02ddda..ee1fe04 100644 --- a/src/r3/r3-component/r3-component-graphics.js +++ b/src/r3/r3-component/r3-component-graphics.js @@ -98,6 +98,12 @@ class ComponentGraphics extends Component { //GENERATED_REQUIRED_COMPONENTS_START //GENERATED_REQUIRED_COMPONENTS_END + //GENERATED_AFTER_REQUIRED_COMPONENTS_START + for (let r = 0; r < this.required.length; r++) { + this.ready[r] = true; + } + //GENERATED_AFTER_REQUIRED_COMPONENTS_END + //CUSTOM_OPTIONS_INIT_START //CUSTOM_OPTIONS_INIT_END diff --git a/src/r3/r3-component/r3-component-image.js b/src/r3/r3-component/r3-component-image.js index 8a6d4d8..dbaffeb 100644 --- a/src/r3/r3-component/r3-component-image.js +++ b/src/r3/r3-component/r3-component-image.js @@ -181,6 +181,12 @@ class ComponentImage extends ComponentGraphics { //GENERATED_REQUIRED_COMPONENTS_START //GENERATED_REQUIRED_COMPONENTS_END + //GENERATED_AFTER_REQUIRED_COMPONENTS_START + for (let r = 0; r < this.required.length; r++) { + this.ready[r] = true; + } + //GENERATED_AFTER_REQUIRED_COMPONENTS_END + //CUSTOM_OPTIONS_INIT_START if (options.extension.match(/(png)$/i)) { diff --git a/src/r3/r3-component/r3-component-input.js b/src/r3/r3-component/r3-component-input.js index cb46a86..3d7e0b1 100644 --- a/src/r3/r3-component/r3-component-input.js +++ b/src/r3/r3-component/r3-component-input.js @@ -98,6 +98,12 @@ class ComponentInput extends Component { //GENERATED_REQUIRED_COMPONENTS_START //GENERATED_REQUIRED_COMPONENTS_END + //GENERATED_AFTER_REQUIRED_COMPONENTS_START + for (let r = 0; r < this.required.length; r++) { + this.ready[r] = true; + } + //GENERATED_AFTER_REQUIRED_COMPONENTS_END + //CUSTOM_OPTIONS_INIT_START //CUSTOM_OPTIONS_INIT_END diff --git a/src/r3/r3-component/r3-component-material.js b/src/r3/r3-component/r3-component-material.js index 7e7d500..68d5998 100644 --- a/src/r3/r3-component/r3-component-material.js +++ b/src/r3/r3-component/r3-component-material.js @@ -98,6 +98,12 @@ class ComponentMaterial extends Component { //GENERATED_REQUIRED_COMPONENTS_START //GENERATED_REQUIRED_COMPONENTS_END + //GENERATED_AFTER_REQUIRED_COMPONENTS_START + for (let r = 0; r < this.required.length; r++) { + this.ready[r] = true; + } + //GENERATED_AFTER_REQUIRED_COMPONENTS_END + //CUSTOM_OPTIONS_INIT_START //CUSTOM_OPTIONS_INIT_END diff --git a/src/r3/r3-component/r3-component-mesh.js b/src/r3/r3-component/r3-component-mesh.js index 4abd9b5..f6cc3a8 100644 --- a/src/r3/r3-component/r3-component-mesh.js +++ b/src/r3/r3-component/r3-component-mesh.js @@ -98,6 +98,12 @@ class ComponentMesh extends Component { //GENERATED_REQUIRED_COMPONENTS_START //GENERATED_REQUIRED_COMPONENTS_END + //GENERATED_AFTER_REQUIRED_COMPONENTS_START + for (let r = 0; r < this.required.length; r++) { + this.ready[r] = true; + } + //GENERATED_AFTER_REQUIRED_COMPONENTS_END + //CUSTOM_OPTIONS_INIT_START //CUSTOM_OPTIONS_INIT_END diff --git a/src/r3/r3-component/r3-component-plane-geometry.js b/src/r3/r3-component/r3-component-plane-geometry.js index 6758873..3a245e3 100644 --- a/src/r3/r3-component/r3-component-plane-geometry.js +++ b/src/r3/r3-component/r3-component-plane-geometry.js @@ -99,6 +99,12 @@ class ComponentPlaneGeometry extends ComponentBufferGeometry { //GENERATED_REQUIRED_COMPONENTS_START //GENERATED_REQUIRED_COMPONENTS_END + //GENERATED_AFTER_REQUIRED_COMPONENTS_START + for (let r = 0; r < this.required.length; r++) { + this.ready[r] = true; + } + //GENERATED_AFTER_REQUIRED_COMPONENTS_END + //CUSTOM_OPTIONS_INIT_START //CUSTOM_OPTIONS_INIT_END diff --git a/src/r3/r3-component/r3-component-texture.js b/src/r3/r3-component/r3-component-texture.js index 98bda86..6858f27 100644 --- a/src/r3/r3-component/r3-component-texture.js +++ b/src/r3/r3-component/r3-component-texture.js @@ -98,6 +98,12 @@ class ComponentTexture extends Component { //GENERATED_REQUIRED_COMPONENTS_START //GENERATED_REQUIRED_COMPONENTS_END + //GENERATED_AFTER_REQUIRED_COMPONENTS_START + for (let r = 0; r < this.required.length; r++) { + this.ready[r] = true; + } + //GENERATED_AFTER_REQUIRED_COMPONENTS_END + //CUSTOM_OPTIONS_INIT_START //CUSTOM_OPTIONS_INIT_END diff --git a/src/r3/r3-component/r3-component-touch.js b/src/r3/r3-component/r3-component-touch.js index 38cc180..2f62e68 100644 --- a/src/r3/r3-component/r3-component-touch.js +++ b/src/r3/r3-component/r3-component-touch.js @@ -147,6 +147,12 @@ class ComponentTouch extends ComponentInput { ) //GENERATED_REQUIRED_COMPONENTS_END + //GENERATED_AFTER_REQUIRED_COMPONENTS_START + for (let r = 0; r < this.required.length; r++) { + this.ready[r] = true; + } + //GENERATED_AFTER_REQUIRED_COMPONENTS_END + //CUSTOM_OPTIONS_INIT_START //CUSTOM_OPTIONS_INIT_END diff --git a/src/r3/r3-entity/r3-entity-slider.js b/src/r3/r3-entity/r3-entity-slider.js index 7256e57..7edea1c 100644 --- a/src/r3/r3-entity/r3-entity-slider.js +++ b/src/r3/r3-entity/r3-entity-slider.js @@ -256,6 +256,12 @@ class EntitySlider extends Entity { ) //GENERATED_REQUIRED_COMPONENTS_END + //GENERATED_AFTER_REQUIRED_COMPONENTS_START + for (let r = 0; r < this.required.length; r++) { + this.ready[r] = true; + } + //GENERATED_AFTER_REQUIRED_COMPONENTS_END + //CUSTOM_OPTIONS_INIT_START //CUSTOM_OPTIONS_INIT_END diff --git a/src/r3/r3-event.js b/src/r3/r3-event.js index c48f422..1ba5d48 100644 --- a/src/r3/r3-event.js +++ b/src/r3/r3-event.js @@ -241,22 +241,31 @@ class Event { subscriptionIds.map( function(subscriptionId) { try { + let result = Event.Subscriptions[eventId][subscriptionId](data); if (clientCallback) { clientCallback(result); } + } catch (error) { + if (clientErrorCallback) { clientErrorCallback(error); } else { console.error(error); throw error; } + } } ) + } else { + if (clientCallback) { + clientCallback(); + } } + //CUSTOM_STATIC_EMIT_METHOD_END } @@ -363,42 +372,44 @@ Event.ENTITY_CREATED = 0xa; Event.ENTITY_INITIALIZED = 0xb; Event.ENTITY_STARTED = 0xc; Event.FINAL_INITIALIZE = 0xd; -Event.GET_API_URL = 0xe; -Event.GET_RUNTIME = 0xf; -Event.GET_WINDOW_SIZE = 0x10; -Event.GRAPHICS_COMPONENT_INITIALIZED = 0x11; -Event.IMAGE_COMPONENT_INITIALIZED = 0x12; -Event.IMAGE_INSTANCE_CREATED = 0x13; -Event.INPUT_COMPONENT_INITIALIZED = 0x14; -Event.INSTANCE_CREATED = 0x15; -Event.INSTANCE_DISPOSED = 0x16; -Event.KEYBOARD_DOWN = 0x17; -Event.KEYBOARD_UP = 0x18; -Event.MOUSE_DOWN = 0x19; -Event.MOUSE_MOVE = 0x1a; -Event.MOUSE_UP = 0x1b; -Event.MOUSE_WHEEL = 0x1c; -Event.OBJECT_CREATED = 0x1d; -Event.OBJECT_PROPERTY_UPDATE = 0x1e; -Event.OBJECT_PROPERTY_UPDATED = 0x1f; -Event.PAUSE = 0x20; -Event.PROJECT_INITIALIZED = 0x21; -Event.RESTART = 0x22; -Event.RUNTIME_CREATED = 0x23; -Event.SLIDER_ENTITY_INITIALIZED = 0x24; -Event.START = 0x25; -Event.TOUCH_CANCEL = 0x26; -Event.TOUCH_COMPONENT_INITIALIZED = 0x27; -Event.TOUCH_END = 0x28; -Event.TOUCH_MOVE = 0x29; -Event.TOUCH_START = 0x2a; -Event.UPDATE_FROM_INSTANCE_AFTER = 0x2b; -Event.UPDATE_FROM_INSTANCE_BEFORE = 0x2c; -Event.UPDATE_INSTANCE_AFTER = 0x2d; -Event.UPDATE_INSTANCE_BEFORE = 0x2e; -Event.UPDATE_INSTANCE_PROPERTY = 0x2f; -Event.UPDATE_PROPERTY_FROM_INSTANCE = 0x30; -Event.MAX_EVENTS = 0x31; +Event.FUTURE_READY_STATE_FALSE = 0xe; +Event.FUTURE_READY_STATE_TRUE = 0xf; +Event.GET_API_URL = 0x10; +Event.GET_RUNTIME = 0x11; +Event.GET_WINDOW_SIZE = 0x12; +Event.GRAPHICS_COMPONENT_INITIALIZED = 0x13; +Event.IMAGE_COMPONENT_INITIALIZED = 0x14; +Event.IMAGE_INSTANCE_CREATED = 0x15; +Event.INPUT_COMPONENT_INITIALIZED = 0x16; +Event.INSTANCE_CREATED = 0x17; +Event.INSTANCE_DISPOSED = 0x18; +Event.KEYBOARD_DOWN = 0x19; +Event.KEYBOARD_UP = 0x1a; +Event.MOUSE_DOWN = 0x1b; +Event.MOUSE_MOVE = 0x1c; +Event.MOUSE_UP = 0x1d; +Event.MOUSE_WHEEL = 0x1e; +Event.OBJECT_CREATED = 0x1f; +Event.OBJECT_PROPERTY_UPDATE = 0x20; +Event.OBJECT_PROPERTY_UPDATED = 0x21; +Event.PAUSE = 0x22; +Event.PROJECT_INITIALIZED = 0x23; +Event.RESTART = 0x24; +Event.RUNTIME_CREATED = 0x25; +Event.SLIDER_ENTITY_INITIALIZED = 0x26; +Event.START = 0x27; +Event.TOUCH_CANCEL = 0x28; +Event.TOUCH_COMPONENT_INITIALIZED = 0x29; +Event.TOUCH_END = 0x2a; +Event.TOUCH_MOVE = 0x2b; +Event.TOUCH_START = 0x2c; +Event.UPDATE_FROM_INSTANCE_AFTER = 0x2d; +Event.UPDATE_FROM_INSTANCE_BEFORE = 0x2e; +Event.UPDATE_INSTANCE_AFTER = 0x2f; +Event.UPDATE_INSTANCE_BEFORE = 0x30; +Event.UPDATE_INSTANCE_PROPERTY = 0x31; +Event.UPDATE_PROPERTY_FROM_INSTANCE = 0x32; +Event.MAX_EVENTS = 0x33; Event.GetEventName = function(eventId) { @@ -416,41 +427,43 @@ Event.GetEventName = function(eventId) { case 0xb : return 'entity_initialized'; case 0xc : return 'entity_started'; case 0xd : return 'final_initialize'; - case 0xe : return 'get_api_url'; - case 0xf : return 'get_runtime'; - case 0x10 : return 'get_window_size'; - case 0x11 : return 'graphics_component_initialized'; - case 0x12 : return 'image_component_initialized'; - case 0x13 : return 'image_instance_created'; - case 0x14 : return 'input_component_initialized'; - case 0x15 : return 'instance_created'; - case 0x16 : return 'instance_disposed'; - case 0x17 : return 'keyboard_down'; - case 0x18 : return 'keyboard_up'; - case 0x19 : return 'mouse_down'; - case 0x1a : return 'mouse_move'; - case 0x1b : return 'mouse_up'; - case 0x1c : return 'mouse_wheel'; - case 0x1d : return 'object_created'; - case 0x1e : return 'object_property_update'; - case 0x1f : return 'object_property_updated'; - case 0x20 : return 'pause'; - case 0x21 : return 'project_initialized'; - case 0x22 : return 'restart'; - case 0x23 : return 'runtime_created'; - case 0x24 : return 'slider_entity_initialized'; - case 0x25 : return 'start'; - case 0x26 : return 'touch_cancel'; - case 0x27 : return 'touch_component_initialized'; - case 0x28 : return 'touch_end'; - case 0x29 : return 'touch_move'; - case 0x2a : return 'touch_start'; - case 0x2b : return 'update_from_instance_after'; - case 0x2c : return 'update_from_instance_before'; - case 0x2d : return 'update_instance_after'; - case 0x2e : return 'update_instance_before'; - case 0x2f : return 'update_instance_property'; - case 0x30 : return 'update_property_from_instance'; + case 0xe : return 'future_ready_state_false'; + case 0xf : return 'future_ready_state_true'; + case 0x10 : return 'get_api_url'; + case 0x11 : return 'get_runtime'; + case 0x12 : return 'get_window_size'; + case 0x13 : return 'graphics_component_initialized'; + case 0x14 : return 'image_component_initialized'; + case 0x15 : return 'image_instance_created'; + case 0x16 : return 'input_component_initialized'; + case 0x17 : return 'instance_created'; + case 0x18 : return 'instance_disposed'; + case 0x19 : return 'keyboard_down'; + case 0x1a : return 'keyboard_up'; + case 0x1b : return 'mouse_down'; + case 0x1c : return 'mouse_move'; + case 0x1d : return 'mouse_up'; + case 0x1e : return 'mouse_wheel'; + case 0x1f : return 'object_created'; + case 0x20 : return 'object_property_update'; + case 0x21 : return 'object_property_updated'; + case 0x22 : return 'pause'; + case 0x23 : return 'project_initialized'; + case 0x24 : return 'restart'; + case 0x25 : return 'runtime_created'; + case 0x26 : return 'slider_entity_initialized'; + case 0x27 : return 'start'; + case 0x28 : return 'touch_cancel'; + case 0x29 : return 'touch_component_initialized'; + case 0x2a : return 'touch_end'; + case 0x2b : return 'touch_move'; + case 0x2c : return 'touch_start'; + case 0x2d : return 'update_from_instance_after'; + case 0x2e : return 'update_from_instance_before'; + case 0x2f : return 'update_instance_after'; + case 0x30 : return 'update_instance_before'; + case 0x31 : return 'update_instance_property'; + case 0x32 : return 'update_property_from_instance'; default : throw new Error('Event type not defined : ' + eventId); } diff --git a/src/r3/r3-object/r3-object.js b/src/r3/r3-object/r3-object.js index 5683563..1bbdcb5 100644 --- a/src/r3/r3-object/r3-object.js +++ b/src/r3/r3-object/r3-object.js @@ -18,12 +18,13 @@ const Utils = require('.././r3-utils'); TEMPLATE_OPTIONS_START id=Utils.RandomId(15) - Each Object receives an 15 digit random ID which uniquely identifies it everywhere (client and server side) name=this.constructor.name + '(' + options.id + ')' - Each Object has a name + ready=[] - Normally all objects are 'ready' to have their instances created, unless it has some required Object which is not present at time of construction and will be assigned later. All objects have multiple sets of 'required' objects which affect its 'ready' state. dirty=false - When dirty is true, it means that this object is in transition from having a child Object to not having this child Object, and will probably end up in an uninitialized state. During the next few clock cycles this child Object will have its parent reference to this Object removed. initialized=false - A boolean which indicates whether or not this Object has initialized initializeDepth=0 - The amount of times this Object passed through initialize() functions parents=[] - All Objects could have parent(s) children=[] - All Objects could have some children - required=[Object] - All Objects could have some required Objects which need to initialize before this Object can initialize + required=[] - All Objects could have some required Objects which need to initialize before this Object can initialize TEMPLATE_OPTIONS_END CUSTOM_OPTIONS_START @@ -87,6 +88,14 @@ class R3Object extends Event { if (typeof options.name === 'undefined') { options.name = this.constructor.name + '(' + options.id + ')'; } + /** + * ready - Normally all objects are 'ready' to have their instances created, unless it has some required + * Object which is not present at time of construction and will be assigned later. All objects + * have multiple sets of 'required' objects which affect its 'ready' state. + */ + if (typeof options.ready === 'undefined') { + options.ready = []; + } /** * dirty - When dirty is true, it means that this object is in transition from having a child Object to * not having this child Object, and will probably end up in an uninitialized state. During the @@ -124,7 +133,7 @@ class R3Object extends Event { * initialize */ if (typeof options.required === 'undefined') { - options.required = [Object]; + options.required = []; } //GENERATED_TEMPLATE_OPTIONS_INIT_END diff --git a/src/r3/r3-system/r3-system-linking.js b/src/r3/r3-system/r3-system-linking.js index 59df184..d6c8ae6 100644 --- a/src/r3/r3-system/r3-system-linking.js +++ b/src/r3/r3-system/r3-system-linking.js @@ -58,7 +58,9 @@ const System = require('./r3-system.js'); CUSTOM_STATIC_METHODS_START SanityChecks(r3Object, property, value) - When an object gets some value assigned to a property, we need to check if this property is a required property, and if so, the value assigned to this property needs to conform to the type restrictions enforced by the requirements objects. SetParentChildRelationships(r3Object, property, value) - When an object gets some value assigned to a property, and it is a required property, we need to ensure that the proper parent / child relationships are maintained - DetermineReadyState(r3Object, property, value) - When an object is assigned some value to one of its required properties, we should determine the 'readiness' state of this R3 Object. Ready objects, can have their instances created. + DetermineFutureReadyState(r3Object, property, value) - When an object is assigned some value to one of its required properties, we should determine the future 'readiness' state of this R3 Object. If an object will fall out of readiness, we need to notify all relevant systems of the eventual demise of this object, so that they have the opportunity to cleanly stop using running instances of this object. + DetermineActualReadyState(r3Object, property, value) - When an object is assigned some value to one of its required properties, we should determine the current 'readiness' state of this R3 Object after its property has assumed the value. If the ready state of an object changed - we need to start / stop this Object or Entity, create / delete instances of the Component + RequirementsValueCheck(requirementProperty, value) - Does a quick check of the value against the requirement ActivateInstances() CUSTOM_STATIC_METHODS_END @@ -290,7 +292,7 @@ class SystemLinking extends System { ); } - throw new TypeError('The property ' + property + ' of this object is not of the correct type'); + throw new TypeError('The child item inside ' + property + '[] of this object is not of the correct type'); } } ); @@ -417,72 +419,191 @@ class SystemLinking extends System { } /** - * DetermineReadyState() - * - When an object is assigned some value to one of its required properties, we should determine the 'readiness' - * state of this R3 Object. Ready objects, can have their instances created. + * DetermineFutureReadyState() + * - When an object is assigned some value to one of its required properties, we should determine the future + * 'readiness' state of this R3 Object. If an object will fall out of readiness, we need to notify all relevant + * systems of the eventual demise of this object, so that they have the opportunity to cleanly stop using running + * instances of this object. * @param r3Object * @param property * @param value */ - static DetermineReadyState( + static DetermineFutureReadyState( r3Object, property, value ) { - //GENERATED_STATIC_DETERMINE_READY_STATE_METHOD_START - //GENERATED_STATIC_DETERMINE_READY_STATE_METHOD_END + //GENERATED_STATIC_DETERMINE_FUTURE_READY_STATE_METHOD_START + //GENERATED_STATIC_DETERMINE_FUTURE_READY_STATE_METHOD_END - //CUSTOM_STATIC_DETERMINE_READY_STATE_METHOD_START + //CUSTOM_STATIC_DETERMINE_FUTURE_READY_STATE_METHOD_START + console.log('Determining future ready state of ' + r3Object.name + ' because of property change : ' + property); - console.log('Determining ready state for ' + r3Object.name); + for (let r = 0; r < r3Object.required.length; r++) { - // if (r3Object.required[property] instanceof Array) { - // - // if (value.length === 0) { - // return false; - // } - // - // for (let i = 0; i < value.length; i++) { - // if (value[i].initialized !== true) { - // return false; - // } - // } - // - // return true; - // - // } else { - // - // if (value === null) { - // return false; - // } else { - // - // if (value.initialized !== true) { - // return false; - // } - // - // return true; - // } - // } + if (r3Object.ready[r]) { + let ready = true; - // for (let requiredProperty in this.required) { - // if (this.required.hasOwnProperty(requiredProperty)) { - // if (requiredProperty === property) { - // if (!isReady(property, value)) { - // this.initialized = false; - // return; - // } - // } else { - // if (!isReady(requiredProperty, this[requiredProperty])) { - // this.initialized = false; - // return; - // } - // } - // } - // } + /** + * This object is currently ready - we need to check if this object will fall out of a ready state + */ + let requirements = r3Object.required[r]; - //CUSTOM_STATIC_DETERMINE_READY_STATE_METHOD_END + if (requirements.hasOwnProperty(property)) { + ready = SystemLinking.RequirementsValueCheck(requirements[property], value); + } + + if (!ready) { + /** + * This object will fall out of readiness state - notify all systems + */ + Event.Emit( + Event.FUTURE_READY_STATE_FALSE, + { + r3Object, + property, + value, + requiredIndex : r + } + ); + } + + } else { + + let ready = true; + + /** + * This object is current *NOT* ready - we need to check if this object will fall into a ready state. + */ + let requirements = r3Object.required[r]; + + for (let requirementProperty in requirements) { + if (requirements.hasOwnProperty(requirementProperty)) { + + if (requirementProperty === property) { + /** + * Compare against the current value and not the r3Object[requirementProperty] + */ + ready = SystemLinking.RequirementsValueCheck(requirements[requirementProperty], value); + } else { + ready = SystemLinking.RequirementsValueCheck(requirements[requirementProperty], r3Object[requirementProperty]); + } + } + } + + if (ready) { + Event.Emit( + Event.FUTURE_READY_STATE_TRUE, + { + r3Object, + property, + value, + requiredIndex: r + } + ); + } + } + } + + //CUSTOM_STATIC_DETERMINE_FUTURE_READY_STATE_METHOD_END + + } + + /** + * DetermineActualReadyState() + * - When an object is assigned some value to one of its required properties, we should determine the current + * 'readiness' state of this R3 Object after its property has assumed the value. If the ready state of an object + * changed - we need to start / stop this Object or Entity, create / delete instances of the Component + * @param r3Object + * @param property + * @param value + */ + static DetermineActualReadyState( + r3Object, + property, + value + ) { + + //GENERATED_STATIC_DETERMINE_ACTUAL_READY_STATE_METHOD_START + //GENERATED_STATIC_DETERMINE_ACTUAL_READY_STATE_METHOD_END + + //CUSTOM_STATIC_DETERMINE_ACTUAL_READY_STATE_METHOD_START + console.log('Determining actual ready state of ' + r3Object.name); + + for (let r = 0; r < r3Object.required.length; r++) { + + let ready = true; + + /** + * This object is currently ready - we need to check if this object will fall out of a ready state + */ + let requirements = r3Object.required[r]; + + for (let property in requirements) { + if (requirements.hasOwnProperty(property)) { + ready = SystemLinking.RequirementsValueCheck(requirements[property], r3Object[property]); + } + } + + r3Object.ready[r] = ready; + } + + //CUSTOM_STATIC_DETERMINE_ACTUAL_READY_STATE_METHOD_END + + } + + /** + * RequirementsValueCheck() + * - Does a quick check of the value against the requirement + * @param requirementProperty + * @param value + */ + static RequirementsValueCheck( + requirementProperty, + value + ) { + + //GENERATED_STATIC_REQUIREMENTS_VALUE_CHECK_METHOD_START + //GENERATED_STATIC_REQUIREMENTS_VALUE_CHECK_METHOD_END + + //CUSTOM_STATIC_REQUIREMENTS_VALUE_CHECK_METHOD_START + + /** + * The property change is one of the required properties of this Object, so it affects the overall + * 'readiness' of this object. + */ + if (requirementProperty instanceof Array) { + + /** + * + */ + if (!(value instanceof Array)) { + return false; + } + + if (value.length === 0) { + return false; + } + + for (let v = 0; v < value.length; v++) { + if (!(value[v] instanceof requirementProperty[0])) { + return false; + } + } + + } else { + + if (!(value instanceof requirementProperty)) { + return false; + } + + } + + return true; + + //CUSTOM_STATIC_REQUIREMENTS_VALUE_CHECK_METHOD_END } @@ -656,9 +777,9 @@ class SystemLinking extends System { SystemLinking.SetParentChildRelationships(r3Object, property, value); /** - * Determine the ready state of the r3Object + * Determine the future ready state of the r3Object */ - SystemLinking.DetermineReadyState(r3Object, property, value); + SystemLinking.DetermineFutureReadyState(r3Object, property, value); /** * The value was unassigned - remove the parent relationships of the existing @@ -702,24 +823,13 @@ class SystemLinking extends System { //GENERATED_STATIC_ON_OBJECT_PROPERTY_UPDATED_METHOD_END //CUSTOM_STATIC_ON_OBJECT_PROPERTY_UPDATED_METHOD_START - let {r3Object} = object; + let {r3Object, property, value} = object; - if (!r3Object.underConstruction) { + /** + * Determine the actual ready state of the r3Object + */ + SystemLinking.DetermineActualReadyState(r3Object, property, value); - /** - * At this point - the object entity would have been brought to a stop - * if it had been transitioned into an uninitialized state by setting one of - * its required properties to a null, empty or undefined state. - * We can safely clear the dirty flag. - */ - - if (r3Object.dirty) { - r3Object.dirty = false; - } - - r3Object.initializeDepth = 0; - r3Object.initialize(); - } //CUSTOM_STATIC_ON_OBJECT_PROPERTY_UPDATED_METHOD_END } diff --git a/src/r3/r3.js b/src/r3/r3.js index b792587..b012f96 100644 --- a/src/r3/r3.js +++ b/src/r3/r3.js @@ -90,12 +90,12 @@ class R3 { /** * static Version - Current R3 version */ -R3.Version = '3.0.255'; +R3.Version = '3.0.261'; /** * static CompileDate - Current compile date of R3 */ -R3.CompileDate = '2021 Oct 02 - 14:30:13 pm'; +R3.CompileDate = '2021 Oct 03 - 07:35:08 am'; //GENERATED_STATIC_OPTIONS_INIT_END diff --git a/src/templates/component_extends_constructor.template b/src/templates/component_extends_constructor.template index 3556f2f..d5311dd 100644 --- a/src/templates/component_extends_constructor.template +++ b/src/templates/component_extends_constructor.template @@ -27,6 +27,9 @@ //GENERATED_REQUIRED_COMPONENTS_START //GENERATED_REQUIRED_COMPONENTS_END + //GENERATED_AFTER_REQUIRED_COMPONENTS_START + //GENERATED_AFTER_REQUIRED_COMPONENTS_END + //CUSTOM_OPTIONS_INIT_START //CUSTOM_OPTIONS_INIT_END diff --git a/src/templates/entity_extends_constructor.template b/src/templates/entity_extends_constructor.template index 2d4a191..5ff2736 100644 --- a/src/templates/entity_extends_constructor.template +++ b/src/templates/entity_extends_constructor.template @@ -34,6 +34,9 @@ //GENERATED_REQUIRED_COMPONENTS_START //GENERATED_REQUIRED_COMPONENTS_END + //GENERATED_AFTER_REQUIRED_COMPONENTS_START + //GENERATED_AFTER_REQUIRED_COMPONENTS_END + //CUSTOM_OPTIONS_INIT_START //CUSTOM_OPTIONS_INIT_END diff --git a/src/templates/generated_after_required_components.template b/src/templates/generated_after_required_components.template new file mode 100644 index 0000000..d710c68 --- /dev/null +++ b/src/templates/generated_after_required_components.template @@ -0,0 +1,3 @@ + for (let r = 0; r < this.required.length; r++) { + this.ready[r] = true; + } \ No newline at end of file diff --git a/src/templates/object_base.template b/src/templates/object_base.template index fe972ff..5fe82d1 100644 --- a/src/templates/object_base.template +++ b/src/templates/object_base.template @@ -16,12 +16,13 @@ const Utils = require('INCLUDE_PATH/r3-utils'); TEMPLATE_OPTIONS_START id=Utils.RandomId(15) - Each Object receives an 15 digit random ID which uniquely identifies it everywhere (client and server side) name=this.constructor.name + '(' + options.id + ')' - Each Object has a name + ready=[] - Normally all objects are 'ready' to have their instances created, unless it has some required Object which is not present at time of construction and will be assigned later. All objects have multiple sets of 'required' objects which affect its 'ready' state. dirty=false - When dirty is true, it means that this object is in transition from having a child Object to not having this child Object, and will probably end up in an uninitialized state. During the next few clock cycles this child Object will have its parent reference to this Object removed. initialized=false - A boolean which indicates whether or not this Object has initialized initializeDepth=0 - The amount of times this Object passed through initialize() functions parents=[] - All Objects could have parent(s) children=[] - All Objects could have some children - required=[Object] - All Objects could have some required Objects which need to initialize before this Object can initialize + required=[] - All Objects could have some required Objects which need to initialize before this Object can initialize TEMPLATE_OPTIONS_END CUSTOM_OPTIONS_START diff --git a/src/templates/token.db b/src/templates/token.db index e4b0954..d7cc18f 100644 --- a/src/templates/token.db +++ b/src/templates/token.db @@ -1,3 +1,4 @@ +GENERATED_AFTER_REQUIRED_COMPONENTS GENERATED_ASYNC_METHOD GENERATED_ASYNC_METHOD_AFTER GENERATED_BUILD_INSTANCE_METHOD @@ -43,7 +44,8 @@ GENERATED_START_METHOD GENERATED_START_METHOD_AFTER GENERATED_STATIC_ACTIVATE_INSTANCES_METHOD GENERATED_STATIC_ASYNC_METHOD -GENERATED_STATIC_DETERMINE_READY_STATE_METHOD +GENERATED_STATIC_DETERMINE_ACTUAL_READY_STATE_METHOD +GENERATED_STATIC_DETERMINE_FUTURE_READY_STATE_METHOD GENERATED_STATIC_EMIT_METHOD GENERATED_STATIC_EVENT_LISTENER_METHODS GENERATED_STATIC_EVENT_LISTENERS_START @@ -130,7 +132,8 @@ CUSTOM_SET_RUNTIME_METHOD CUSTOM_START_METHOD CUSTOM_STATIC_ACTIVATE_INSTANCES_METHOD CUSTOM_STATIC_ASYNC_METHOD -CUSTOM_STATIC_DETERMINE_READY_STATE_METHOD +CUSTOM_STATIC_DETERMINE_ACTUAL_READY_STATE_METHOD +CUSTOM_STATIC_DETERMINE_FUTURE_READY_STATE_METHOD CUSTOM_STATIC_EMIT_METHOD CUSTOM_STATIC_EVENT_LISTENERS CUSTOM_STATIC_METHOD_NAME_UPPERCASE_METHOD diff --git a/test/R3.test.js b/test/R3.test.js index 2c20ef5..75b6316 100644 --- a/test/R3.test.js +++ b/test/R3.test.js @@ -256,12 +256,48 @@ describe('R3 Tests', () => { try { const slider5 = new EntitySlider( { + name : 'slider5', canvas : image1 } ); } catch (err) { assert.isTrue(err instanceof TypeError); } + + // test if delete works on an object + const slider6 = new EntitySlider( + { + name : 'slider6', + canvas : canvas + } + ); + + delete slider6.canvas; + + // assert.deepEqual(canvas.parents, [slider1, slider2]); + + console.log('DELETE AND SPLICE DOES NOT WORK'); + } + ); + + it( + 'Linking system detects future ready state correctly', + () => { + + let touch1 = new ComponentTouch( + { + name : 'touch1' + } + ) + + let canvas = new ComponentCanvas(); + + assert.isFalse(touch1.ready[0]); + + touch1.domComponent = canvas; + + assert.isTrue(touch1.ready[0]); + } ); diff --git a/version b/version index ee8ae56..31ee48a 100644 --- a/version +++ b/version @@ -1 +1 @@ -3.0.255 \ No newline at end of file +3.0.262 \ No newline at end of file