diff --git a/.gitignore b/.gitignore index 40151f4..4924c20 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules -distribution \ No newline at end of file +distribution +react-unity-webgl-*.tgz diff --git a/source/UnityContent.ts b/source/UnityContent.ts index 7772b12..6ed6236 100644 --- a/source/UnityContent.ts +++ b/source/UnityContent.ts @@ -1,11 +1,20 @@ import IUnityConfig from "./interfaces/IUnityConfig"; -import IUnityEvent from "./interfaces/IUnityEvent"; import UnityComponent from "./components/Unity"; +import UnityEvents from "./UnityEvents"; import "./declarations/UnityLoader"; import "./declarations/UnityInstance"; -import "./declarations/ReactUnityWebgl"; +import "./declarations/ReactUnityWebGL"; import { loggingService } from "./services/LoggingService"; +// event names on which this.triggerUnityEvent() is called +const InstanceEventNames: string[] = [ + 'error', + 'loaded', + 'progress', + 'quitted', + 'resized', +]; + export default class UnityContent { /** * the relative path to the build json file generated by Unity. @@ -43,11 +52,18 @@ export default class UnityContent { public unityConfig: IUnityConfig; /** - * The registered Unity Events. - * @type {IUnityEvent[]} - * @public + * The registered instance Unity Events. + * @type {UnityEvents} + * @private */ - private unityEvents: IUnityEvent[]; + private unityInstanceEvents: UnityEvents; + + /** + * The registered global Unity Events associated with ReactUnityWebGL object. + * @type {UnityEvents} + * @private + */ + static unityGlobalEvents: UnityEvents = new UnityEvents(); /** * The unique ID helps seperating multiple @@ -82,7 +98,7 @@ export default class UnityContent { this.buildJsonPath = buildJsonPath; this.unityLoaderJsPath = unityLoaderJsPath; this.uniqueID = ++UnityContent.uniqueID; - this.unityEvents = []; + this.unityInstanceEvents = new UnityEvents(); this.unityConfig = { modules: _unityConfig.modules || {}, unityVersion: _unityConfig.unityVersion || "undefined", @@ -169,13 +185,20 @@ export default class UnityContent { * @public */ public on(eventName: string, eventCallback: Function): any { - this.unityEvents.push({ - eventName: eventName, - eventCallback: eventCallback - }); - (window as any).ReactUnityWebGL[eventName] = (parameter: any) => { - return eventCallback(parameter); - }; + if (InstanceEventNames.find(name => name === eventName)) { + // instance event - add to instance events + this.unityInstanceEvents.AddEventListener(eventName, eventCallback); + + } else { + // ReactUnityWebGL event - add to class events + UnityContent.unityGlobalEvents.AddEventListener(eventName, eventCallback); + + // install global event handler (if necessary) + if (typeof (window as any).ReactUnityWebGL[eventName] === 'undefined') { + (window as any).ReactUnityWebGL[eventName] = (parameter: any) => + UnityContent.unityGlobalEvents.DispatchEvent(eventName, parameter); + } + } } /** @@ -186,8 +209,6 @@ export default class UnityContent { * @public */ public triggerUnityEvent(eventName: string, eventValue?: any): void { - for (let _i = 0; _i < this.unityEvents.length; _i++) - if (this.unityEvents[_i].eventName === eventName) - this.unityEvents[_i].eventCallback(eventValue); + this.unityInstanceEvents.DispatchEvent(eventName, eventValue); } } diff --git a/source/UnityEvents.ts b/source/UnityEvents.ts new file mode 100644 index 0000000..e9da6e7 --- /dev/null +++ b/source/UnityEvents.ts @@ -0,0 +1,49 @@ +export default class UnityEvents { + /** + * Mapping event name to list of callbacks + * @type {Map} + * @private + */ + private map: Map; + + constructor() { + this.map = new Map(); + } + + /** + * Adds a callback for eventName + * @param eventName the event name. + * @param callback false the public method name. + */ + public AddEventListener( + eventName: string, + callback: Function + ): void { + if (!this.map.has(eventName)) { + this.map.set(eventName, []); + } + this.map.get(eventName)!.push(callback); + } + + /** + * Dispatch eventName to all registered callbacks + * @param eventName the event name + * @param parameter the event parameter + */ + public DispatchEvent( + eventName: string, + parameter: any + ): void { + if (!this.map.has(eventName)) return; + + // the first callack that returns true aborts dispatch + this.map.get(eventName)!.find(callback => { + try { + return callback(parameter); + } catch (e) { + // ignore errors and keep on dispatching the event + return; + } + }); + } +} diff --git a/source/components/Unity.ts b/source/components/Unity.ts index a6a0a5c..307e782 100644 --- a/source/components/Unity.ts +++ b/source/components/Unity.ts @@ -5,7 +5,7 @@ import UnityContent from "../UnityContent"; import UnityLoaderService from "../services/UnityLoaderService"; import "../declarations/UnityLoader"; import "../declarations/UnityInstance"; -import "../declarations/ReactUnityWebgl"; +import "../declarations/ReactUnityWebGL"; export default class Unity extends React.Component { /** diff --git a/source/interfaces/IUnityEvent.ts b/source/interfaces/IUnityEvent.ts deleted file mode 100644 index c713885..0000000 --- a/source/interfaces/IUnityEvent.ts +++ /dev/null @@ -1,14 +0,0 @@ -export default interface IUnityEvent { - /** - * The events name. It will be triggered by the name. - * @type {string} - */ - eventName: string; - - /** - * The events callback. This event will be triggered - * when the - * @type {Function} - */ - eventCallback: Function; -}