/** * Event Core * @constructor */ GameLib.Event = function() { }; /** * Some nice Events handling * @type {{}} */ GameLib.Event.Subscriptions = {}; GameLib.Event.OnceSubscriptions = {}; /** * Events we can subscribe to and publish */ GameLib.Event.WINDOW_RESIZE = 0x1; GameLib.Event.PARENT_SCENE_CHANGE = 0x2; GameLib.Event.EXCLUDE_FROM_ENVIRONMENT = 0x3; GameLib.Event.INSTANCE_CLONED = 0x4; GameLib.Event.LOAD_IMAGE = 0x5; GameLib.Event.NEW_ENTITY = 0x6; GameLib.Event.MATERIAL_TYPE_CHANGED = 0x7; GameLib.Event.SAVE_COMPONENT = 0x8; GameLib.Event.SAVE_COMPONENT_ERROR = 0x9; GameLib.Event.COMPONENT_SAVED = 0xa; GameLib.Event.LOAD_COMPONENT = 0xb; GameLib.Event.LOAD_COMPONENT_ERROR = 0xc; GameLib.Event.LOGGED_IN = 0xd; GameLib.Event.COMPONENT_CREATED = 0xe; GameLib.Event.COMPONENT_CLONED = 0xf; GameLib.Event.TEXTURE_ANIMATED_CHANGE = 0x10; GameLib.Event.ANIMATE_TEXTURE_INSTANCE = 0x11; GameLib.Event.REMOVE_PARTICLE_ENGINE = 0x12; GameLib.Event.GAME_PAUSE = 0x13; GameLib.Event.SHADER_UPDATE = 0x14; GameLib.Event.PLAY_AUDIO = 0x15; GameLib.Event.MATERIAL_INSTANCE_UPDATED = 0x16; GameLib.Event.PAUSE_AUDIO = 0x17; GameLib.Event.MESH_INSTANCE_UPDATED = 0x18; GameLib.Event.STOP_AUDIO = 0x19; GameLib.Event.LIGHT_INSTANCE_UPDATED = 0x1a; GameLib.Event.DELETE_COMPONENT = 0x1b; GameLib.Event.COMPONENT_DOWNLOAD_COMPLETE = 0x1c; GameLib.Event.COMPONENTS_LINKED = 0x1d; GameLib.Event.UNRESOLVED_DEPENDENCIES_UPDATE = 0x1e; GameLib.Event.REGISTER_UPDATE = 0x1f; GameLib.Event.BUILD_GUI = 0x20; GameLib.Event.REMOVE_MESH = 0x21; GameLib.Event.MESH_SELECTED = 0x22; GameLib.Event.MESH_DESELECTED = 0x23; GameLib.Event.COMPONENT_REGISTER = 0x24; GameLib.Event.IMAGE_NOT_FOUND = 0x25; GameLib.Event.BLENDER_DATA_RECEIVED = 0x26; GameLib.Event.IMAGE_UPLOAD_COMPLETE = 0x27; GameLib.Event.REMOVE_COMPONENT = 0x28; GameLib.Event.KEY_DOWN = 0x29; GameLib.Event.KEY_UP = 0x2a; GameLib.Event.RENDER = 0x2b; GameLib.Event.EVENT_LIST = 0x2c; GameLib.Event.COMPILE_SUCCESS = 0x2d; GameLib.Event.COMPILE_FAILED = 0x2e; GameLib.Event.TEXTURE_INSTANCE_UPDATED = 0x2f; GameLib.Event.EVENT_ID_UPDATE = 0x30; GameLib.Event.MATERIAL_TEXTURES_UPDATED = 0x31; GameLib.Event.DELETE_COMPONENT_ERROR = 0x32; GameLib.Event.COMPONENT_DELETED = 0x33; GameLib.Event.COMPONENT_TYPES_FETCHED = 0x34; GameLib.Event.AUDIO_ENDED = 0x35; GameLib.Event.COMPONENT_LINKED = 0x36; GameLib.Event.DONE_SAVING = 0x37; GameLib.Event.BEFORE_RENDER = 0x38; GameLib.Event.AFTER_RENDER = 0x39; GameLib.Event.ARRAY_ITEM_ADDED = 0x3a; GameLib.Event.INSTANCE_CREATED = 0x3b; GameLib.Event.VISUALIZE = 0x3c; GameLib.Event.STOP_VISUALIZE = 0x3d; GameLib.Event.FETCH_COMPONENT_TYPES = 0x3e; GameLib.Event.FETCH_COMPONENTS = 0x3f; GameLib.Event.GET_API_URL = 0x40; GameLib.Event.GET_RUNTIME = 0x41; GameLib.Event.PARENT_WORLD_CHANGE = 0x42; GameLib.Event.ANIMATE = 0x43; GameLib.Event.ANIMATION_COMPILE_SUCCESS = 0x44; GameLib.Event.ANIMATION_COMPILE_FAILED = 0x45; GameLib.Event.SAVING = 0x46; GameLib.Event.GAME_OVER = 0x47; GameLib.Event.GAME_START = 0x48; GameLib.Event.TOUCH_START = 0x49; GameLib.Event.TOUCH_END = 0x4a; GameLib.Event.TOUCH_MOVE = 0x4b; GameLib.Event.TOUCH_CANCEL = 0x4c; GameLib.Event.GET_REMOTE_API_URL = 0x4d; GameLib.Event.COMPONENT_TYPES_UPDATE = 0x4e; GameLib.Event.DELAYED_INSTANCE_ENCOUNTERED = 0x4f; GameLib.Event.CAST_SOURCE_CHANGED = 0x50; GameLib.Event.RESOLVE_DEPENDENCIES = 0x51; GameLib.Event.NAME_UPDATE = 0x52; GameLib.Event.CANVAS_CHANGE = 0x53; GameLib.Event.AFTER_WINDOW_RESIZE = 0x54; GameLib.Event.LOAD_FONT = 0x55; GameLib.Event.FONT_NOT_FOUND = 0x56; GameLib.Event.STOP_ALL_AUDIO = 0x57; GameLib.Event.REGISTER_DEPENDENCIES = 0x58; GameLib.Event.GAME_LOADED = 0x59; GameLib.Event.COMPONENT_UPDATE = 0x5a; GameLib.Event.LOAD_PROGRESS = 0x5b; GameLib.Event.ENTITY_LOADED = 0x5c; GameLib.Event.MOUSE_DOWN = 0x5d; GameLib.Event.MOUSE_MOVE = 0x5e; GameLib.Event.MOUSE_WHEEL = 0x5f; GameLib.Event.MOUSE_UP = 0x60; GameLib.Event.PARTICLE_INSTANCE_UPDATED = 0x61; GameLib.Event.GAME_DATA = 0x62; GameLib.Event.PAUSE_ALL_AUDIO = 0x63; GameLib.Event.CONTINUE_ALL_AUDIO = 0x64; GameLib.Event.MUTE_AUDIO = 0x65; GameLib.Event.GAME_STARTED = 0x66; GameLib.Event.GAME_PAUSED = 0x67; GameLib.Event.GAME_RESUMED = 0x68; GameLib.Event.CUSTOM_GAME_START = 0x69; GameLib.Event.AUDIO_MUTED = 0x6a; GameLib.Event.AUDIO_UNMUTED = 0x6b; GameLib.Event.RECEIVE_DESTINATION_CHANGED = 0x6c; GameLib.Event.SELECTION_MODE_CHANGE = 0x6d; GameLib.Event.MESH_FACE_SELECTED = 0x6e; GameLib.Event.MESH_FACE_DESELECTED = 0x6f; GameLib.Event.BEFORE_WINDOW_RESIZE = 0x70; GameLib.Event.GET_WINDOW_SIZE = 0x71; GameLib.Event.GET_RENDER_CONFIGURATION = 0x72; GameLib.Event.SET_ACTIVE_RENDER_CONFIGURATION = 0x73; GameLib.Event.REPLACE_COMPONENT = 0x74; GameLib.Event.COMPONENT_REPLACED = 0x75; GameLib.Event.ENGINE_FIRED_PARTICLES_ZERO = 0x76; /** * Returns string name of event ID * @param number * @returns {*} * @constructor */ GameLib.Event.GetEventName = function(number) { switch(number) { case 0x1 : return 'window_resize'; case 0x2 : return 'parent_scene_change'; case 0x3 : return 'unused'; case 0x4 : return 'instance_cloned'; case 0x5 : return 'load_image'; case 0x6 : return 'new_entity'; case 0x7 : return 'material_type_changed'; case 0x8 : return 'save_component'; case 0x9 : return 'save_component_error'; case 0xa : return 'component_saved'; case 0xb : return 'load_component'; case 0xc : return 'load_component_error'; case 0xd : return 'logged_in'; case 0xe : return 'component_created'; case 0xf : return 'component_cloned'; case 0x10 : return 'texture_animated_change'; case 0x11 : return 'animate_texture_instance'; case 0x12 : return 'remove_particle_engine'; case 0x13 : return 'pause'; case 0x14 : return 'shader_update'; case 0x15 : return 'play_audio'; case 0x16 : return 'material_instance_updated'; case 0x17 : return 'pause_audio'; case 0x18 : return 'mesh_instance_updated'; case 0x19 : return 'stop_audio'; case 0x1a : return 'light_instance_updated'; case 0x1b : return 'delete_component'; case 0x1c : return 'component_download_complete'; case 0x1d : return 'components_linked'; case 0x1e : return 'unresolved_dependencies_update'; case 0x1f : return 'register_update'; case 0x20 : return 'build_gui'; case 0x21 : return 'remove_mesh'; case 0x22 : return 'mesh_selected'; case 0x23 : return 'mesh_deselected'; case 0x24 : return 'component_register'; case 0x25 : return 'image_not_found'; case 0x26 : return 'blender_data_received'; case 0x27 : return 'image_upload_complete'; case 0x28 : return 'remove_component'; case 0x29 : return 'key_down'; case 0x2a : return 'key_up'; case 0x2b : return 'render'; case 0x2c : return 'event_list'; case 0x2d : return 'compile_success'; case 0x2e : return 'compile_failed'; case 0x2f : return 'texture_image_updated'; case 0x30 : return 'event_id_update'; case 0x31 : return 'material_textures_updated'; case 0x32 : return 'delete_component_error'; case 0x33 : return 'component_deleted'; case 0x34 : return 'component_types_updated'; case 0x35 : return 'audio_ended'; case 0x36 : return 'component_linked'; case 0x37 : return 'done_saving'; case 0x38 : return 'before_render'; case 0x39 : return 'after_render'; case 0x3a : return 'array_item_added'; case 0x3b : return 'instance_created'; case 0x3c : return 'visualize'; case 0x3d : return 'stop_visualize'; case 0x3e : return 'fetch_component_types'; case 0x3f : return 'fetch_components'; case 0x40 : return 'get_api_url'; case 0x41 : return 'get_runtime'; case 0x42 : return 'parent_world_change'; case 0x43 : return 'animate'; case 0x44 : return 'animation_compile_success'; case 0x45 : return 'animation_compile_failed'; case 0x46 : return 'saving'; case 0x47 : return 'game_over'; case 0x48 : return 'game_start'; case 0x49 : return 'touch_start'; case 0x4a : return 'touch_end'; case 0x4b : return 'touch_move'; case 0x4c : return 'touch_cancel'; case 0x4d : return 'get_remote_api_url'; case 0x4e : return 'component_types_update'; case 0x4f : return 'delayed_instance_encountered'; case 0x50 : return 'cast_source_changed'; case 0x51 : return 'resolve_dependencies';; case 0x52 : return 'name_update'; case 0x53 : return 'dom_element_change'; case 0x54 : return 'after_window_resize'; case 0x55 : return 'load_font'; case 0x56 : return 'font_not_found'; case 0x57 : return 'stop_all_audio'; case 0x58 : return 'register_dependencies'; case 0x59 : return 'game_loaded'; case 0x5a : return 'component_update'; case 0x5b : return 'load_progress'; case 0x5c : return 'entity_loaded'; case 0x5d : return 'mouse_down'; case 0x5e : return 'mouse_move'; case 0x5f : return 'mouse_wheel'; case 0x60 : return 'mouse_up'; case 0x61 : return 'particle_instance_updated'; case 0x62 : return 'game_data'; case 0x63 : return 'pause_all_audio'; case 0x64 : return 'continue_all_audio'; case 0x65 : return 'mute_audio'; case 0x66 : return 'game_started'; case 0x67 : return 'game_paused'; case 0x68 : return 'game_resumed'; case 0x69 : return 'custom_game_start'; case 0x6a : return 'audio_muted'; case 0x6b : return 'audio_unmuted'; case 0x6c : return 'receive_destination_changed'; case 0x6d : return 'selection_mode_change'; case 0x6e : return 'mesh_face_selected'; case 0x6f : return 'mesh_face_deselected'; case 0x70 : return 'before_window_resize'; case 0x71 : return 'get_window_size'; case 0x72 : return 'get_render_configuration'; case 0x73 : return 'set_active_render_configuration'; case 0x74 : return 'replace_component'; case 0x75 : return 'component_replaced'; case 0x76 : return 'engine_fired_particles_zero'; break; } throw new error('unknown event id: ' + number ); }; /** * Subscribe to some events * @param eventName * @param callback */ GameLib.Event.prototype.subscribe = function( eventName, callback ) { return GameLib.Event.Subscribe(eventName, callback.bind(this)); }; // /** // * Stop listening for this event after the callback returns true // * @param eventName // * @param callback // * @returns {{fn, remove: remove}} // */ // GameLib.Event.prototype.subscribeOnce = function( // eventName, // callback // ) { // throw new Error('implement first properly'); // // var fn = callback.bind(this); // // // // if (GameLib.Event.OnceSubscriptions.hasOwnProperty(eventName)) { // // GameLib.Event.OnceSubscriptions[eventName].push(fn); // // } else { // // GameLib.Event.OnceSubscriptions[eventName] = []; // // GameLib.Event.OnceSubscriptions[eventName].push(fn); // // } // // // // /** // // * Return a handle to the caller to allow us to unsubscribe to this event // // */ // // return { // // fn : fn, // // remove : function() { // // GameLib.Event.Subscriptions[eventName].splice( // // GameLib.Event.Subscriptions[eventName].indexOf(fn), // // 1 // // ); // // } // // } // }; /** * * @param eventName * @param data */ /** * Publish some event happened with some data * @param eventName * @param data * @param clientCallback * @param clientErrorCallback * @returns {number} of callbacks executed */ GameLib.Event.prototype.publish = function( eventName, data, clientCallback, clientErrorCallback ) { return GameLib.Event.Emit( eventName, data, clientCallback, clientErrorCallback ); }; /** * Static method call * @param eventName * @param data * @param clientCallback is executed ideally when the event completed * @param clientErrorCallback * @returns {number} of callbacks executed * @constructor */ GameLib.Event.Emit = function( eventName, data, clientCallback, clientErrorCallback ) { var count = 0; if (GameLib.Event.Subscriptions.hasOwnProperty(eventName)) { if (GameLib.Event.Subscriptions[eventName].length === 0) { if (clientCallback) { /** * We execute the client callback immediately since there are no subscriptions to this event */ clientCallback(); } if (clientErrorCallback) { clientErrorCallback({ message : 'No subscriptions for event ' + eventName }) } } /** * We need to execute all the callbacks, but not execute them twice, but also keep in mind they can remove * themselves during execution */ // var length = GameLib.Event.Subscriptions[eventName].length; // // for (var i = 0; i < length; i++) { // // var object = GameLib.Event.Subscriptions[eventName][i]; // // if (object.fn && object.executed === false) { // object.fn(data, clientCallback, clientErrorCallback); // object.executed = true; // } // // if (length !== GameLib.Event.Subscriptions[eventName].length) { // /** // * this callback removed a subscription - reset i and reset the length // */ // i = 0; // length = GameLib.Event.Subscriptions[eventName].length; // } // } // // GameLib.Event.Subscriptions[eventName].map( // function(object){ // object.executed = false; // } // ) GameLib.Event.Subscriptions[eventName].map( function(callback) { if (callback) { callback(data, clientCallback, clientErrorCallback); count++; } } ) } else { if (clientCallback) { /** * We execute the client callback immediately since there are no subscriptions to this event */ clientCallback(); } if (clientErrorCallback) { clientErrorCallback({ message : 'No subscriptions for event ' + eventName }) } } return count; }; GameLib.Event.Subscribe = function( eventName, fn ) { if (GameLib.Event.Subscriptions.hasOwnProperty(eventName)) { GameLib.Event.Subscriptions[eventName].push(fn); // { // fn : fn, // executed : false // } // ); } else { GameLib.Event.Subscriptions[eventName] = []; GameLib.Event.Subscriptions[eventName].push(fn); // { // fn : fn, // executed : false // } // ); } /** * Return a handle to the caller to allow us to unsubscribe to this event */ return { fn : fn, remove : function() { var index = GameLib.Event.Subscriptions[eventName].indexOf(fn); // reduce( // function(result, object, index) { // if (object.fn === fn) { // result = index; // } // return result; // }, // -1 // ); if (index === -1) { throw new Error('could not remove subscription'); } GameLib.Event.Subscriptions[eventName].splice( index, 1 ); } } };