diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..426eb78 --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +**/*.jslib diff --git a/Assets/Plugins/WebSocket.jslib b/Assets/Plugins/WebSocket.jslib index 766700d..4c9c5e7 100644 --- a/Assets/Plugins/WebSocket.jslib +++ b/Assets/Plugins/WebSocket.jslib @@ -29,6 +29,15 @@ SocketCreate: function(url) var array = new Uint8Array(e.data); socket.messages.push(array); } + else if(typeof e.data === "string") { + var reader = new FileReader(); + reader.addEventListener("loadend", function() { + var array = new Uint8Array(reader.result); + socket.messages.push(array); + }); + var blob = new Blob([e.data]); + reader.readAsArrayBuffer(blob); + } }; socket.socket.onclose = function (e) { diff --git a/Assets/Scripts/Constants.cs b/Assets/Scripts/Constants.cs index 55273ce..2d81511 100644 --- a/Assets/Scripts/Constants.cs +++ b/Assets/Scripts/Constants.cs @@ -5,10 +5,10 @@ namespace AssemblyCSharp { public static class Constants { - public const string kServerHostname = "52.59.156.131"; - public const int kServerPort = 41234; + public const string kServerHostname = "sardines-ngj2017.herokuapp.com"; + public const int kServerPort = 443; public const int kClientPort = 41235; - public const int kGameStateUpdateTickMs = 100; + public const int kGameStateUpdateTickMs = 250; public const int kSecondsBetweenFirstHideAndRoundEnd = 10; public const int kSecondsBetweenRoundEndAndNextRoundStart = 5; public const int kNumHidingPlaces = 10; diff --git a/Assets/Scripts/DummyPlayer.cs b/Assets/Scripts/DummyPlayer.cs index f0b96d1..7073897 100644 --- a/Assets/Scripts/DummyPlayer.cs +++ b/Assets/Scripts/DummyPlayer.cs @@ -78,8 +78,7 @@ public void EndTitleScreen() { } void Update () { - QueryUDPConnections (); - QueryWebSocketConnections (); + ReadAndHandleReceivedMessages (); } IEnumerator BackgroundSendGameStateToServerTask() { @@ -102,6 +101,8 @@ private void HandleServerToClientHelloMessage(ServerToClientHelloMessage message if (hidingPlace) { hidingPlace.SetHidingPlaceIndex (message.hidingPlace); } + + status = Status.waitingForPlayers; } private void HandleServerToClientStartMessage(ServerToClientStartMessage message) { @@ -129,31 +130,28 @@ private void HandleServerToClientStartMessage(ServerToClientStartMessage message } } - private void QueryWebSocketConnections() { - string serverMessage; + private void ReadAndHandleReceivedMessages() { + Message serverMessage; if (status == Status.titleScreen) { // don't process websockets return; } - if (serverCommunication.TryGetServerWebSocketMessage (out serverMessage)) { - Debug.Log ("Server sent WS : " + serverMessage); - - if (serverMessage.Contains ("ServerToClientHelloMessage")) { - Debug.Log ("Setting ID and position"); - ServerToClientHelloMessage message = JsonUtility.FromJson (serverMessage); - HandleServerToClientHelloMessage (message); - status = Status.waitingForPlayers; - connectingScreen.enabled = false; - waitingForPlayersScreen.enabled = true; - winScreen.enabled = false; - loseScreen.enabled = false; + if (serverCommunication.TryGetReceivedMessage (out serverMessage)) { + var serverToClientHelloMessage = serverMessage as ServerToClientHelloMessage; + if (serverToClientHelloMessage != null) { + HandleServerToClientHelloMessage (serverToClientHelloMessage); + } + + var serverToClientStartMessage = serverMessage as ServerToClientStartMessage; + if (serverToClientStartMessage != null) { + HandleServerToClientStartMessage (serverToClientStartMessage); } - else if (serverMessage.Contains("ServerToClientStartMessage")) { - ServerToClientStartMessage message = JsonUtility.FromJson (serverMessage); - HandleServerToClientStartMessage (message); + var serverGameStateMessage = serverMessage as ServerGameStateMessage; + if (serverGameStateMessage != null) { + HandleServerGameStateMessage (serverGameStateMessage); } } } @@ -165,33 +163,22 @@ private void SendGameStateMessage() return; } - string text = JsonUtility.ToJson( - new ClientGameStateMessage( - id, - transform.position, - transform.forward, - GetComponent().velocity, - frozen, - gameId - ) + var message = new ClientGameStateMessage( + id, + transform.position, + transform.forward, + GetComponent().velocity, + frozen, + gameId ); - serverCommunication.SendClientUdpMessage (text); + serverCommunication.SendClientMessage (message); } - private void QueryUDPConnections() - { - ServerGameStateMessage message = serverCommunication.CheckForOtherClientGameStates (); - //Debug.Log (message); - if (message == null) { + private void HandleServerGameStateMessage(ServerGameStateMessage message) { + if (message.gameId != gameId) { return; } - if (message.gameId == gameId) { - ProcessOtherPlayers (message); - } - } - - private void ProcessOtherPlayers(ServerGameStateMessage message) { // Debug.Log ("Processing other players, message: " + message); foreach (ClientGameStateMessage client in message.clients) { diff --git a/Assets/Scripts/Messages/ClientGameStateMessage.cs b/Assets/Scripts/Messages/ClientGameStateMessage.cs index f0c7c05..7ef7860 100644 --- a/Assets/Scripts/Messages/ClientGameStateMessage.cs +++ b/Assets/Scripts/Messages/ClientGameStateMessage.cs @@ -11,9 +11,8 @@ namespace AssemblyCSharp { [Serializable] - public class ClientGameStateMessage + public class ClientGameStateMessage : Message { - public string type; public int id; public Vector3Serialisable playerPosition; public Vector3Serialisable playerDirection; @@ -25,7 +24,6 @@ public ClientGameStateMessage (int id, Vector3 position, Vector3 forwardDirectio { this.id = id; this.gameId = gameId; - type = this.GetType().Name; playerPosition = new Vector3Serialisable (position); playerDirection = new Vector3Serialisable (forwardDirection); playerVelocity = new Vector3Serialisable (velocity); diff --git a/Assets/Scripts/Messages/ClientHelloMessage.cs b/Assets/Scripts/Messages/ClientHelloMessage.cs index 609507c..e873194 100644 --- a/Assets/Scripts/Messages/ClientHelloMessage.cs +++ b/Assets/Scripts/Messages/ClientHelloMessage.cs @@ -3,14 +3,8 @@ namespace AssemblyCSharp { [Serializable] - public class ClientHelloMessage + public class ClientHelloMessage : Message { - public string type; - - public ClientHelloMessage () - { - type = this.GetType().Name; - } } } diff --git a/Assets/Scripts/Messages/Message.cs b/Assets/Scripts/Messages/Message.cs new file mode 100644 index 0000000..ff24a7e --- /dev/null +++ b/Assets/Scripts/Messages/Message.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +using System.Text; +using System.Net; +using System.Net.Sockets; +using System.Threading; + +using AssemblyCSharp; + +namespace AssemblyCSharp +{ + [Serializable] + public abstract class Message + { + public string type; + + public Message() { + type = this.GetType().Name; + } + + public string Serialize() { + return JsonUtility.ToJson (this); + } + + public override string ToString() { + return Serialize (); + } + } +} + diff --git a/Assets/Scripts/Messages/Message.cs.meta b/Assets/Scripts/Messages/Message.cs.meta new file mode 100644 index 0000000..c4436b0 --- /dev/null +++ b/Assets/Scripts/Messages/Message.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: aea11a601a42d4a53a65e5fb88272409 +timeCreated: 1493119861 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Messages/MessageParser.cs b/Assets/Scripts/Messages/MessageParser.cs new file mode 100644 index 0000000..7e86ad2 --- /dev/null +++ b/Assets/Scripts/Messages/MessageParser.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +using System.Text; +using System.Net; +using System.Net.Sockets; +using System.Threading; + +using AssemblyCSharp; + +namespace AssemblyCSharp +{ + public class MessageParser + { + private class TypeMessage : Message { + + } + + public Message Parse(string str) { + var typeMessage = JsonUtility.FromJson (str); + switch (typeMessage.type) { + case "ClientGameStateMessage": + return JsonUtility.FromJson (str); + case "ClientHelloMessage": + return JsonUtility.FromJson (str); + case "ServerGameStateMessage": + return JsonUtility.FromJson (str); + case "ServerToClientHelloMessage": + return JsonUtility.FromJson (str); + case "ServerToClientStartMessage": + return JsonUtility.FromJson (str); + default: + Debug.LogError ("Unknown message type!"); + return null; + } + } + } +} + diff --git a/Assets/Scripts/Messages/MessageParser.cs.meta b/Assets/Scripts/Messages/MessageParser.cs.meta new file mode 100644 index 0000000..dcfaf82 --- /dev/null +++ b/Assets/Scripts/Messages/MessageParser.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 66bf263afbeed4d27a9e71f40d4c07aa +timeCreated: 1493119861 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Messages/ServerGameStateMessage.cs b/Assets/Scripts/Messages/ServerGameStateMessage.cs index 254c4f7..8e78a37 100644 --- a/Assets/Scripts/Messages/ServerGameStateMessage.cs +++ b/Assets/Scripts/Messages/ServerGameStateMessage.cs @@ -5,10 +5,9 @@ namespace AssemblyCSharp { [Serializable] - public class ServerGameStateMessage + public class ServerGameStateMessage: Message { public List clients; - public string type; public int gameId; } } diff --git a/Assets/Scripts/Messages/ServerToClientHelloMessage.cs b/Assets/Scripts/Messages/ServerToClientHelloMessage.cs index 97677c3..71f6a2f 100644 --- a/Assets/Scripts/Messages/ServerToClientHelloMessage.cs +++ b/Assets/Scripts/Messages/ServerToClientHelloMessage.cs @@ -3,9 +3,8 @@ namespace AssemblyCSharp { [Serializable] - public class ServerToClientHelloMessage + public class ServerToClientHelloMessage : Message { - public string type; public int id; public int gameId; public Vector3Serialisable playerPosition; diff --git a/Assets/Scripts/Messages/ServerToClientStartMessage.cs b/Assets/Scripts/Messages/ServerToClientStartMessage.cs index 7d3fb0d..7623532 100644 --- a/Assets/Scripts/Messages/ServerToClientStartMessage.cs +++ b/Assets/Scripts/Messages/ServerToClientStartMessage.cs @@ -3,17 +3,15 @@ namespace AssemblyCSharp { [Serializable] - public class ServerToClientStartMessage + public class ServerToClientStartMessage : Message { public int gameId; - public string type; public int hidingPlace; public Vector3Serialisable playerPosition; public ServerToClientStartMessage (int gameId, int hidingPlace, Vector3Serialisable playerPosition) { this.gameId = gameId; - type = this.GetType().Name; this.hidingPlace = hidingPlace; this.playerPosition = playerPosition; } diff --git a/Assets/Scripts/ServerCommunication.cs b/Assets/Scripts/ServerCommunication.cs index 48f9075..2e592d5 100644 --- a/Assets/Scripts/ServerCommunication.cs +++ b/Assets/Scripts/ServerCommunication.cs @@ -1,31 +1,46 @@ -using System.Collections; +#if !(UNITY_WEBGL && !UNITY_EDITOR) +// For hosting on Heroku, everything must be a websocket, +// so alas, this is commented out. +// #define ALLOW_UDP +#endif + +using System.Collections; using System.Collections.Generic; using UnityEngine; using System; using System.Text; +#if ALLOW_UDP using System.Net; using System.Net.Sockets; +#endif using System.Threading; using AssemblyCSharp; -using WebSocketSharp; public class ServerCommunication : MonoBehaviour { + + WebSocket webSocket; + + Queue receivedMessageQueue = new Queue(); + object receivedMessageQueueLock = new object(); + + MessageParser parser = new MessageParser (); + + #if !ALLOW_UDP + void StartNet() { + } + #else Thread receiveThread; IPEndPoint udpEndpoint; UdpClient udpClient; - WebSocket webSocket; - Queue receivedUdpMessageQueue = new Queue(); - Queue receivedWebSocketMessageQueue = new Queue(); + static IPAddress IpV4ForHostname(string hostname) { - object udpLock = new object(); - object wsLock = new object(); + return IPAddress.Parse(Constants.kServerHostname); - static IPAddress IpV4ForHostname(string hostname) { IPHostEntry hostEntry; hostEntry = Dns.GetHostEntry(Constants.kServerHostname); @@ -38,17 +53,48 @@ static IPAddress IpV4ForHostname(string hostname) { return null; } - IEnumerator Start () { + private void BackgroundReceiveUdp() + { + while (true) + { + try + { + IPEndPoint senderEndpoint = new IPEndPoint(IPAddress.Any, 0); + byte[] data = udpClient.Receive(ref senderEndpoint); + string text = Encoding.UTF8.GetString(data); + + var serverMessage = parser.Parse(text); + HandleReceivedMessage(serverMessage); + } + catch (Exception err) + { + print(err.ToString()); + } + } + } + + private void SendClientUdpMessage(Message clientMessage) { + string str = clientMessage.Serialize (); + byte[] data = Encoding.UTF8.GetBytes(str); + udpClient.Send(data, data.Length, udpEndpoint); + } + + void StartNet () { udpClient = new UdpClient(Constants.kClientPort); var serverIpAddr = IpV4ForHostname (Constants.kServerHostname); udpEndpoint = new IPEndPoint (serverIpAddr, Constants.kServerPort); - receiveThread = new Thread(new ThreadStart(BackgroundReceiveData)); + receiveThread = new Thread(new ThreadStart(BackgroundReceiveUdp)); receiveThread.IsBackground = true; receiveThread.Start(); + } + #endif - var builder = new UriBuilder("ws", Constants.kServerHostname, Constants.kServerPort); + IEnumerator Start () { + StartNet (); + + var builder = new UriBuilder("wss", Constants.kServerHostname, Constants.kServerPort); var uri = builder.Uri; Debug.Log (uri); webSocket = new WebSocket(uri); @@ -59,9 +105,8 @@ IEnumerator Start () { string reply = webSocket.RecvString(); if (reply != null) { - lock (wsLock) { - receivedWebSocketMessageQueue.Enqueue (reply); - } + var message = parser.Parse (reply); + HandleReceivedMessage (message); } if (webSocket.error != null) { @@ -78,33 +123,16 @@ void Update () { } - private void BackgroundReceiveData() - { - while (true) - { - try - { - IPEndPoint senderEndpoint = new IPEndPoint(IPAddress.Any, 0); - byte[] data = udpClient.Receive(ref senderEndpoint); - string text = Encoding.UTF8.GetString(data); - - var serverMessage = text; - - lock (udpLock) { - receivedUdpMessageQueue.Enqueue(serverMessage); - } - } - catch (Exception err) - { - print(err.ToString()); - } + private void HandleReceivedMessage(Message message) { + lock (receivedMessageQueueLock) { + receivedMessageQueue.Enqueue (message); } } - public bool TryGetServerUdpMessage(out string serverMessage) { - lock (udpLock) { - if (receivedUdpMessageQueue.Count > 0) { - serverMessage = receivedUdpMessageQueue.Dequeue (); + public bool TryGetReceivedMessage(out Message serverMessage) { + lock (receivedMessageQueueLock) { + if (receivedMessageQueue.Count > 0) { + serverMessage = receivedMessageQueue.Dequeue (); return true; } else { serverMessage = null; @@ -113,26 +141,22 @@ public bool TryGetServerUdpMessage(out string serverMessage) { } } - public void SendClientUdpMessage(string clientMessage) { - byte[] data = Encoding.UTF8.GetBytes(clientMessage); - udpClient.Send(data, data.Length, udpEndpoint); + private void SendClientWebSocketMessage(Message clientMessage) { + string str = clientMessage.Serialize (); + byte[] data = Encoding.UTF8.GetBytes(str); + webSocket.Send (data); } - public bool TryGetServerWebSocketMessage(out string serverMessage) { - lock (wsLock) { - if (receivedWebSocketMessageQueue.Count > 0) { - serverMessage = receivedWebSocketMessageQueue.Dequeue (); - return true; - } else { - serverMessage = null; - return false; - } + public void SendClientMessage(Message clientMessage) { + #if !ALLOW_UDP + SendClientWebSocketMessage (clientMessage); + #else + if (clientMessage is ClientGameStateMessage) { + SendClientUdpMessage (clientMessage); + } else { + SendClientWebSocketMessage (clientMessage); } - } - - public void SendClientWebSocketMessage(string clientMessage) { - byte[] data = Encoding.UTF8.GetBytes(clientMessage); - webSocket.Send (data); + #endif } public static ServerCommunication GetRoot() { @@ -142,15 +166,4 @@ public static ServerCommunication GetRoot() { return serverCommunication; } - - public ServerGameStateMessage CheckForOtherClientGameStates() - { - ServerGameStateMessage jsonObj = null; - string serverMessage; - if (TryGetServerUdpMessage (out serverMessage)) { -// Debug.Log ("Server sent UDP GameState: " + serverMessage); - jsonObj = JsonUtility.FromJson (serverMessage); - } - return jsonObj; - } } diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..22290ed --- /dev/null +++ b/docs/index.html @@ -0,0 +1,11 @@ + + + + + Sardines + + +

Sardines

+Play + + \ No newline at end of file diff --git a/docs/sardines-v1.1.0/Build/UnityLoader.js b/docs/sardines-v1.1.0/Build/UnityLoader.js new file mode 100644 index 0000000..f848153 --- /dev/null +++ b/docs/sardines-v1.1.0/Build/UnityLoader.js @@ -0,0 +1,4 @@ +var UnityLoader=UnityLoader||{compatibilityCheck:function(e,t,r){UnityLoader.SystemInfo.hasWebGL?UnityLoader.SystemInfo.mobile?e.popup("Please note that Unity WebGL is not currently supported on mobiles. Press OK if you wish to continue anyway.",[{text:"OK",callback:t}]):["Firefox","Chrome","Safari"].indexOf(UnityLoader.SystemInfo.browser)==-1?e.popup("Please note that your browser is not currently supported for this Unity WebGL content. Press OK if you wish to continue anyway.",[{text:"OK",callback:t}]):t():e.popup("Your browser does not support WebGL",[{text:"OK",callback:r}])},Blobs:{},loadCode:function(e,t,r){var n=[].slice.call(UnityLoader.Cryptography.md5(e)).map(function(e){return("0"+e.toString(16)).substr(-2)}).join(""),o=document.createElement("script"),a=URL.createObjectURL(new Blob(['UnityLoader["'+n+'"]=',e],{type:"text/javascript"}));UnityLoader.Blobs[a]=r,o.src=a,o.onload=function(){URL.revokeObjectURL(a),t(n)},document.body.appendChild(o)},allocateHeapJob:function(e,t){for(var r=e.TOTAL_STACK||5242880,n=e.TOTAL_MEMORY||(e.buffer?e.buffer.byteLength:268435456),o=65536,a=16777216,i=o;i0;u=c,c=f.indexOf("/",u)+1)e.FS_createPath(f.substring(0,u),f.substring(u,c-1),!0,!0);e.FS_createDataFile(f,null,r.subarray(s,s+d),!0,!0,!0)}e.removeRunDependency("processDataJob"),t.complete()},downloadJob:function(e,t){var r=new XMLHttpRequest;r.open("GET",t.parameters.url),r.responseType="arraybuffer",r.onload=function(){UnityLoader.Compression.decompress(new Uint8Array(r.response),function(e){t.complete(e)})},t.parameters.onprogress&&r.addEventListener("progress",t.parameters.onprogress),t.parameters.onload&&r.addEventListener("load",t.parameters.onload),r.send()},scheduleBuildDownloadJob:function(e,t,r){UnityLoader.Progress.update(e,t),UnityLoader.Job.schedule(e,t,[],UnityLoader.downloadJob,{url:e.resolveBuildUrl(r),onprogress:function(r){UnityLoader.Progress.update(e,t,r)},onload:function(r){UnityLoader.Progress.update(e,t,r)}})},loadModule:function(e){if(e.useWasm=e.wasmCodeUrl&&UnityLoader.SystemInfo.hasWasm,e.useWasm)UnityLoader.scheduleBuildDownloadJob(e,"downloadWasmCode",e.wasmCodeUrl),UnityLoader.Job.schedule(e,"processWasmCode",["downloadWasmCode"],UnityLoader.processWasmCodeJob),UnityLoader.scheduleBuildDownloadJob(e,"downloadWasmFramework",e.wasmFrameworkUrl),UnityLoader.Job.schedule(e,"processWasmFramework",["downloadWasmFramework","processWasmCode","setupIndexedDB"],UnityLoader.processWasmFrameworkJob);else{if(!e.asmCodeUrl)throw"WebAssembly support is not detected in this browser.";UnityLoader.scheduleBuildDownloadJob(e,"downloadAsmCode",e.asmCodeUrl),UnityLoader.Job.schedule(e,"processAsmCode",["downloadAsmCode"],UnityLoader.processAsmCodeJob),UnityLoader.scheduleBuildDownloadJob(e,"downloadAsmMemory",e.asmMemoryUrl),UnityLoader.Job.schedule(e,"processAsmMemory",["downloadAsmMemory"],UnityLoader.processAsmMemoryJob),e.memoryInitializerRequest={addEventListener:function(t,r){e.memoryInitializerRequest.callback=r}},e.asmLibraryUrl&&(e.dynamicLibraries=[e.asmLibraryUrl].map(e.resolveBuildUrl)),UnityLoader.scheduleBuildDownloadJob(e,"downloadAsmFramework",e.asmFrameworkUrl),UnityLoader.Job.schedule(e,"processAsmFramework",["downloadAsmFramework","processAsmCode","setupIndexedDB"],UnityLoader.processAsmFrameworkJob)}UnityLoader.scheduleBuildDownloadJob(e,"downloadData",e.dataUrl),UnityLoader.Job.schedule(e,"setupIndexedDB",[],UnityLoader.setupIndexedDBJob),e.preRun.push(function(){e.addRunDependency("processDataJob"),UnityLoader.Job.schedule(e,"processData",["downloadData"],UnityLoader.processDataJob)})},instantiate:function(e,t,r){function n(e,r){if("string"==typeof e&&!(e=document.getElementById(e)))return!1;e.innerHTML="",e.style.border=e.style.margin=e.style.padding=0,"static"==getComputedStyle(e).getPropertyValue("position")&&(e.style.position="relative"),e.style.width=r.width||e.style.width,e.style.height=r.height||e.style.height,r.container=e;var n=r.Module;return n.canvas=document.createElement("canvas"),n.canvas.style.width="100%",n.canvas.style.height="100%",n.canvas.addEventListener("contextmenu",function(e){e.preventDefault()}),n.canvas.id="#canvas",e.appendChild(n.canvas),UnityLoader.compatibilityCheck(r,function(){var t=new XMLHttpRequest;t.open("GET",r.url,!0),t.responseType="text",t.onload=function(){var r=JSON.parse(t.responseText);for(var o in r)"undefined"==typeof n[o]&&(n[o]=r[o]);e.style.background=n.backgroundUrl?"center/cover url('"+n.resolveBuildUrl(n.backgroundUrl)+"')":n.backgroundColor?" "+n.backgroundColor:"",UnityLoader.loadModule(n)},t.send()},function(){console.log("Instantiation of the '"+t+"' terminated due to the failed compatibility check.")}),!0}var o={url:t,onProgress:UnityLoader.Progress.handler,Module:{preRun:[],postRun:[],print:function(e){console.log(e)},printErr:function(e){console.error(e)},Jobs:{},buildDownloadProgress:{},resolveBuildUrl:function(e){return e.match(/(http|https|ftp|file):\/\//)?e:t.substring(0,t.lastIndexOf("/")+1)+e}},SetFullscreen:function(){if(o.Module.SetFullscreen)return o.Module.SetFullscreen.apply(o.Module,arguments)},SendMessage:function(){if(o.Module.SendMessage)return o.Module.SendMessage.apply(o.Module,arguments)}};o.Module.gameInstance=o,o.popup=function(e,t){return UnityLoader.Error.popup(o,e,t)};for(var a in r)if("Module"==a)for(var i in r[a])o.Module[i]=r[a][i];else o[a]=r[a];return n(e,o)||document.addEventListener("DOMContentLoaded",function(){n(e,o)}),o},SystemInfo:function(){var e,t,r,n="-",o=navigator.appVersion,a=navigator.userAgent,i=navigator.appName,s=""+parseFloat(navigator.appVersion),d=parseInt(navigator.appVersion,10);(t=a.indexOf("Opera"))!=-1?(i="Opera",s=a.substring(t+6),(t=a.indexOf("Version"))!=-1&&(s=a.substring(t+8))):(t=a.indexOf("MSIE"))!=-1?(i="Microsoft Internet Explorer",s=a.substring(t+5)):(t=a.indexOf("Chrome"))!=-1?(i="Chrome",s=a.substring(t+7)):(t=a.indexOf("Safari"))!=-1?(i="Safari",s=a.substring(t+7),(t=a.indexOf("Version"))!=-1&&(s=a.substring(t+8))):(t=a.indexOf("Firefox"))!=-1?(i="Firefox",s=a.substring(t+8)):a.indexOf("Trident/")!=-1?(i="Microsoft Internet Explorer",s=a.substring(a.indexOf("rv:")+3)):(e=a.lastIndexOf(" ")+1)<(t=a.lastIndexOf("/"))&&(i=a.substring(e,t),s=a.substring(t+1),i.toLowerCase()==i.toUpperCase()&&(i=navigator.appName)),(r=s.indexOf(";"))!=-1&&(s=s.substring(0,r)),(r=s.indexOf(" "))!=-1&&(s=s.substring(0,r)),(r=s.indexOf(")"))!=-1&&(s=s.substring(0,r)),d=parseInt(""+s,10),isNaN(d)&&(s=""+parseFloat(navigator.appVersion),d=parseInt(navigator.appVersion,10));var l=/Mobile|mini|Fennec|Android|iP(ad|od|hone)/.test(o),f=n,u=[{s:"Windows 3.11",r:/Win16/},{s:"Windows 95",r:/(Windows 95|Win95|Windows_95)/},{s:"Windows ME",r:/(Win 9x 4.90|Windows ME)/},{s:"Windows 98",r:/(Windows 98|Win98)/},{s:"Windows CE",r:/Windows CE/},{s:"Windows 2000",r:/(Windows NT 5.0|Windows 2000)/},{s:"Windows XP",r:/(Windows NT 5.1|Windows XP)/},{s:"Windows Server 2003",r:/Windows NT 5.2/},{s:"Windows Vista",r:/Windows NT 6.0/},{s:"Windows 7",r:/(Windows 7|Windows NT 6.1)/},{s:"Windows 8.1",r:/(Windows 8.1|Windows NT 6.3)/},{s:"Windows 8",r:/(Windows 8|Windows NT 6.2)/},{s:"Windows 10",r:/(Windows 10|Windows NT 10.0)/},{s:"Windows NT 4.0",r:/(Windows NT 4.0|WinNT4.0|WinNT|Windows NT)/},{s:"Windows ME",r:/Windows ME/},{s:"Android",r:/Android/},{s:"Open BSD",r:/OpenBSD/},{s:"Sun OS",r:/SunOS/},{s:"Linux",r:/(Linux|X11)/},{s:"iOS",r:/(iPhone|iPad|iPod)/},{s:"Mac OS X",r:/Mac OS X/},{s:"Mac OS",r:/(MacPPC|MacIntel|Mac_PowerPC|Macintosh)/},{s:"QNX",r:/QNX/},{s:"UNIX",r:/UNIX/},{s:"BeOS",r:/BeOS/},{s:"OS/2",r:/OS\/2/},{s:"Search Bot",r:/(nuhk|Googlebot|Yammybot|Openbot|Slurp|MSNBot|Ask Jeeves\/Teoma|ia_archiver)/}];for(var c in u){var h=u[c];if(h.r.test(a)){f=h.s;break}}var w=n;switch(/Windows/.test(f)&&(w=/Windows (.*)/.exec(f)[1],f="Windows"),f){case"Mac OS X":w=/Mac OS X (10[\.\_\d]+)/.exec(a)[1];break;case"Android":w=/Android ([\.\_\d]+)/.exec(a)[1];break;case"iOS":w=/OS (\d+)_(\d+)_?(\d+)?/.exec(o),w=w[1]+"."+w[2]+"."+(0|w[3])}return{width:screen.width?screen.width:0,height:screen.height?screen.height:0,browser:i,browserVersion:s,mobile:l,os:f,osVersion:w,language:window.navigator.userLanguage||window.navigator.language,hasWebGL:function(){if(!window.WebGLRenderingContext)return 0;var e=document.createElement("canvas"),t=e.getContext("webgl2");if(!t){var t=e.getContext("experimental-webgl2");if(!t){var t=e.getContext("webgl");return t||(t=e.getContext("experimental-webgl"))?1:0}return 2}return 2}(),hasCursorLock:function(){var e=document.createElement("canvas");return e.requestPointerLock||e.mozRequestPointerLock||e.webkitRequestPointerLock||e.msRequestPointerLock?1:0}(),hasFullscreen:function(){var e=document.createElement("canvas");return(e.requestFullScreen||e.mozRequestFullScreen||e.msRequestFullscreen||e.webkitRequestFullScreen)&&i.indexOf("Safari")==-1?1:0}(),hasWasm:"object"==typeof WebAssembly&&"function"==typeof WebAssembly.validate&&"function"==typeof WebAssembly.compile}}(),Error:{init:function(){return Error.stackTraceLimit=50,window.addEventListener("error",function(e){var t=UnityLoader.Error.getModule(e);if(!t)return UnityLoader.Error.handler(e);var r=t.useWasm?t.wasmSymbolsUrl:t.asmSymbolsUrl;if(!r)return UnityLoader.Error.handler(e,t);var n=new XMLHttpRequest;n.open("GET",t.resolveBuildUrl(r)),n.responseType="arraybuffer",n.onload=function(){UnityLoader.loadCode(UnityLoader.Compression.decompress(new Uint8Array(n.response)),function(r){t.demangleSymbol=UnityLoader[r](),UnityLoader.Error.handler(e,t)})},n.send()}),!0}(),stackTraceFormat:navigator.userAgent.indexOf("Chrome")!=-1?"(\\s+at\\s+)(([\\w\\d_\\.]*?)([\\w\\d_$]+)(/[\\w\\d_\\./]+|))(\\s+\\[.*\\]|)\\s*\\((blob:.*)\\)":"(\\s*)(([\\w\\d_\\.]*?)([\\w\\d_$]+)(/[\\w\\d_\\./]+|))(\\s+\\[.*\\]|)\\s*@(blob:.*)",stackTraceFormatWasm:navigator.userAgent.indexOf("Chrome")!=-1?"((\\s+at\\s*)\\s\\(\\[(\\d+)\\]\\+\\d+\\))()":"((\\s*)wasm-function\\[(\\d+)\\])@(blob:.*)",blobParseRegExp:new RegExp("^(blob:.*)(:\\d+:\\d+)$"),getModule:function(e){var t=e.message.match(new RegExp(this.stackTraceFormat,"g"));for(var r in t){var n=t[r].match(new RegExp("^"+this.stackTraceFormat+"$")),o=n[7].match(this.blobParseRegExp);if(o&&UnityLoader.Blobs[o[1]]&&UnityLoader.Blobs[o[1]].Module)return UnityLoader.Blobs[o[1]].Module}},demangle:function(e,t){var r=e.message;return t?(r=r.replace(new RegExp(this.stackTraceFormat,"g"),function(e){var r=e.match(new RegExp("^"+this.stackTraceFormat+"$")),n=r[7].match(this.blobParseRegExp),o=t.demangleSymbol?t.demangleSymbol(r[4]):r[4],a=n&&UnityLoader.Blobs[n[1]]&&UnityLoader.Blobs[n[1]].url?UnityLoader.Blobs[n[1]].url:"blob";return r[1]+o+(r[2]!=o?" ["+r[2]+"]":"")+" ("+(n?a.substr(a.lastIndexOf("/")+1)+n[2]:r[7])+")"}.bind(this)),t.useWasm&&(r=r.replace(new RegExp(this.stackTraceFormatWasm,"g"),function(e){var r=e.match(new RegExp("^"+this.stackTraceFormatWasm+"$")),n=t.demangleSymbol?t.demangleSymbol(r[3]):r[3],o=r[4].match(this.blobParseRegExp),a=o&&UnityLoader.Blobs[o[1]]&&UnityLoader.Blobs[o[1]].url?UnityLoader.Blobs[o[1]].url:"blob";return(n==r[3]?r[1]:r[2]+n+" [wasm:"+r[3]+"]")+(r[4]?" ("+(o?a.substr(a.lastIndexOf("/")+1)+o[2]:r[4])+")":"")}.bind(this))),r):r},handler:function(e,t){var r=t?this.demangle(e,t):e.message;if(!(t&&t.errorhandler&&t.errorhandler(r,e.filename,e.lineno)||(console.log("Invoking error handler due to\n"+r),"function"==typeof dump&&dump("Invoking error handler due to\n"+r),r.indexOf("UnknownError")!=-1||r.indexOf("Program terminated with exit(0)")!=-1||this.didShowErrorMessage))){var r="An error occured running the Unity content on this page. See your browser JavaScript console for more info. The error was:\n"+r;r.indexOf("DISABLE_EXCEPTION_CATCHING")!=-1?r="An exception has occured, but exception handling has been disabled in this build. If you are the developer of this content, enable exceptions in your project WebGL player settings to be able to catch the exception or see the stack trace.":r.indexOf("Cannot enlarge memory arrays")!=-1?r="Out of memory. If you are the developer of this content, try allocating more memory to your WebGL build in the WebGL player settings.":r.indexOf("Invalid array buffer length")==-1&&r.indexOf("Invalid typed array length")==-1&&r.indexOf("out of memory")==-1||(r="The browser could not allocate enough memory for the WebGL content. If you are the developer of this content, try allocating less memory to your WebGL build in the WebGL player settings."),alert(r),this.didShowErrorMessage=!0}},popup:function(e,t,r){r=r||[{text:"OK"}];var n=document.createElement("div");n.style.cssText="position: absolute; top: 50%; left: 50%; -webkit-transform: translate(-50%, -50%); transform: translate(-50%, -50%); text-align: center; border: 1px solid black; padding: 5px; background: #E8E8E8";var o=document.createElement("span");o.textContent=t,n.appendChild(o),n.appendChild(document.createElement("br"));for(var a=0;a>2]|0;t;e=e+1|0,t=t-1|0)r=o[(r&255^n[e])<<2>>2]^r>>>8^4278190080;o[1024>>2]=r}return{process:a}}({Uint8Array:Uint8Array,Uint32Array:Uint32Array},null,r);t=UnityLoader.Cryptography.crc32.module={buffer:r,HEAPU8:new Uint8Array(r),HEAPU32:new Uint32Array(r),process:n.process,crc32:1024,data:1028};for(var o=0;o<256;o++){for(var a=255^o,i=0;i<8;i++)a=a>>>1^(1&a?3988292384:0);t.HEAPU32[o]=a}}t.HEAPU32[t.crc32>>2]=0;for(var s=0;s>2];return new Uint8Array([l>>24,l>>16,l>>8,l])},md5:function(e){var t=UnityLoader.Cryptography.md5.module;if(!t){var r=new ArrayBuffer(16777216),n=function(e,t,r){"use asm";var n=new e.Uint32Array(r);function o(e,t){e=e|0;t=t|0;var r=0,o=0,a=0,i=0,s=0,d=0,l=0,f=0,u=0,c=0,h=0,w=0;r=n[128]|0,o=n[129]|0,a=n[130]|0,i=n[131]|0;for(;t;e=e+64|0,t=t-1|0){s=r;d=o;l=a;f=i;for(c=0;(c|0)<512;c=c+8|0){w=n[c>>2]|0;r=r+(n[c+4>>2]|0)+(n[e+(w>>>14)>>2]|0)+((c|0)<128?i^o&(a^i):(c|0)<256?a^i&(o^a):(c|0)<384?o^a^i:a^(o|~i))|0;h=(r<<(w&31)|r>>>32-(w&31))+o|0;r=i;i=a;a=o;o=h}r=r+s|0;o=o+d|0;a=a+l|0;i=i+f|0}n[128]=r;n[129]=o;n[130]=a;n[131]=i}return{process:o}}({Uint32Array:Uint32Array},null,r);t=UnityLoader.Cryptography.md5.module={buffer:r,HEAPU8:new Uint8Array(r),HEAPU32:new Uint32Array(r),process:n.process,md5:512,data:576},t.HEAPU32.set(new Uint32Array([7,3614090360,65548,3905402710,131089,606105819,196630,3250441966,262151,4118548399,327692,1200080426,393233,2821735955,458774,4249261313,524295,1770035416,589836,2336552879,655377,4294925233,720918,2304563134,786439,1804603682,851980,4254626195,917521,2792965006,983062,1236535329,65541,4129170786,393225,3225465664,720910,643717713,20,3921069994,327685,3593408605,655369,38016083,983054,3634488961,262164,3889429448,589829,568446438,917513,3275163606,196622,4107603335,524308,1163531501,851973,2850285829,131081,4243563512,458766,1735328473,786452,2368359562,327684,4294588738,524299,2272392833,720912,1839030562,917527,4259657740,65540,2763975236,262155,1272893353,458768,4139469664,655383,3200236656,851972,681279174,11,3936430074,196624,3572445317,393239,76029189,589828,3654602809,786443,3873151461,983056,530742520,131095,3299628645,6,4096336452,458762,1126891415,917519,2878612391,327701,4237533241,786438,1700485571,196618,2399980690,655375,4293915773,65557,2240044497,524294,1873313359,983050,4264355552,393231,2734768916,851989,1309151649,262150,4149444226,720906,3174756917,131087,718787259,589845,3951481745]))}t.HEAPU32.set(new Uint32Array([1732584193,4023233417,2562383102,271733878]),t.md5>>2);for(var o=0;o>6),e.length-o<64){if(a=e.length-o,t.HEAPU8.set(e.subarray(e.length-a,e.length),t.data),o+=a,t.HEAPU8[t.data+a++]=128,a>56){for(var i=a;i<64;i++)t.HEAPU8[t.data+i]=0;t.process(t.data,1),a=0}for(var i=a;i<64;i++)t.HEAPU8[t.data+i]=0;for(var s=e.length,d=0,i=56;i<64;i++,d=(224&s)>>5,s/=256)t.HEAPU8[t.data+i]=((31&s)<<3)+d;t.process(t.data,1)}}return new Uint8Array(t.HEAPU8.subarray(t.md5,t.md5+16))},sha1:function(e){var t=UnityLoader.Cryptography.sha1.module;if(!t){var r=new ArrayBuffer(16777216),n=function(e,t,r){"use asm";var n=new e.Uint32Array(r);function o(e,t){e=e|0;t=t|0;var r=0,o=0,a=0,i=0,s=0,d=0,l=0,f=0,u=0,c=0,h=0,w=0;r=n[80]|0,o=n[81]|0,a=n[82]|0,i=n[83]|0,s=n[84]|0;for(;t;e=e+64|0,t=t-1|0){d=r;l=o;f=a;u=i;c=s;for(w=0;(w|0)<320;w=w+4|0,s=i,i=a,a=o<<30|o>>>2,o=r,r=h){if((w|0)<64){h=n[e+w>>2]|0;h=h<<24&4278190080|h<<8&16711680|h>>>8&65280|h>>>24&255}else{h=n[w-12>>2]^n[w-32>>2]^n[w-56>>2]^n[w-64>>2];h=h<<1|h>>>31}n[w>>2]=h;h=h+((r<<5|r>>>27)+s)+((w|0)<80?(o&a|~o&i|0)+1518500249|0:(w|0)<160?(o^a^i)+1859775393|0:(w|0)<240?(o&a|o&i|a&i)+2400959708|0:(o^a^i)+3395469782|0)|0}r=r+d|0;o=o+l|0;a=a+f|0;i=i+u|0;s=s+c|0}n[80]=r;n[81]=o;n[82]=a;n[83]=i;n[84]=s}return{process:o}}({Uint32Array:Uint32Array},null,r);t=UnityLoader.Cryptography.sha1.module={buffer:r,HEAPU8:new Uint8Array(r),HEAPU32:new Uint32Array(r),process:n.process,sha1:320,data:384}}t.HEAPU32.set(new Uint32Array([1732584193,4023233417,2562383102,271733878,3285377520]),t.sha1>>2);for(var o=0;o>6),e.length-o<64){if(a=e.length-o,t.HEAPU8.set(e.subarray(e.length-a,e.length),t.data),o+=a,t.HEAPU8[t.data+a++]=128,a>56){for(var i=a;i<64;i++)t.HEAPU8[t.data+i]=0;t.process(t.data,1),a=0}for(var i=a;i<64;i++)t.HEAPU8[t.data+i]=0;for(var s=e.length,d=0,i=63;i>=56;i--,d=(224&s)>>5,s/=256)t.HEAPU8[t.data+i]=((31&s)<<3)+d;t.process(t.data,1)}}for(var l=new Uint8Array(20),i=0;i=0&&t.windowBits<16&&(t.windowBits=-t.windowBits,0===t.windowBits&&(t.windowBits=-15)),!(t.windowBits>=0&&t.windowBits<16)||e&&e.windowBits||(t.windowBits+=32),t.windowBits>15&&t.windowBits<48&&0===(15&t.windowBits)&&(t.windowBits|=15),this.err=0,this.msg="",this.ended=!1,this.chunks=[],this.strm=new u,this.strm.avail_out=0;var r=i.inflateInit2(this.strm,t.windowBits);if(r!==l.Z_OK)throw new Error(f[r]);this.header=new c,i.inflateGetHeader(this.strm,this.header)}function o(e,t){var r=new n(t);if(r.push(e,!0),r.err)throw r.msg||f[r.err];return r.result}function a(e,t){return t=t||{},t.raw=!0,o(e,t)}var i=e("./zlib/inflate"),s=e("./utils/common"),d=e("./utils/strings"),l=e("./zlib/constants"),f=e("./zlib/messages"),u=e("./zlib/zstream"),c=e("./zlib/gzheader"),h=Object.prototype.toString;n.prototype.push=function(e,t){var r,n,o,a,f,u,c=this.strm,w=this.options.chunkSize,p=this.options.dictionary,m=!1;if(this.ended)return!1;n=t===~~t?t:t===!0?l.Z_FINISH:l.Z_NO_FLUSH,"string"==typeof e?c.input=d.binstring2buf(e):"[object ArrayBuffer]"===h.call(e)?c.input=new Uint8Array(e):c.input=e,c.next_in=0,c.avail_in=c.input.length;do{if(0===c.avail_out&&(c.output=new s.Buf8(w),c.next_out=0,c.avail_out=w),r=i.inflate(c,l.Z_NO_FLUSH),r===l.Z_NEED_DICT&&p&&(u="string"==typeof p?d.string2buf(p):"[object ArrayBuffer]"===h.call(p)?new Uint8Array(p):p,r=i.inflateSetDictionary(this.strm,u)),r===l.Z_BUF_ERROR&&m===!0&&(r=l.Z_OK,m=!1),r!==l.Z_STREAM_END&&r!==l.Z_OK)return this.onEnd(r),this.ended=!0,!1;c.next_out&&(0!==c.avail_out&&r!==l.Z_STREAM_END&&(0!==c.avail_in||n!==l.Z_FINISH&&n!==l.Z_SYNC_FLUSH)||("string"===this.options.to?(o=d.utf8border(c.output,c.next_out),a=c.next_out-o,f=d.buf2string(c.output,o),c.next_out=a,c.avail_out=w-a,a&&s.arraySet(c.output,c.output,o,a,0),this.onData(f)):this.onData(s.shrinkBuf(c.output,c.next_out)))),0===c.avail_in&&0===c.avail_out&&(m=!0)}while((c.avail_in>0||0===c.avail_out)&&r!==l.Z_STREAM_END);return r===l.Z_STREAM_END&&(n=l.Z_FINISH),n===l.Z_FINISH?(r=i.inflateEnd(this.strm),this.onEnd(r),this.ended=!0,r===l.Z_OK):n!==l.Z_SYNC_FLUSH||(this.onEnd(l.Z_OK),c.avail_out=0,!0)},n.prototype.onData=function(e){this.chunks.push(e)},n.prototype.onEnd=function(e){e===l.Z_OK&&("string"===this.options.to?this.result=this.chunks.join(""):this.result=s.flattenChunks(this.chunks)),this.chunks=[],this.err=e,this.msg=this.strm.msg},r.Inflate=n,r.inflate=o,r.inflateRaw=a,r.ungzip=o},"utils/common.js":function(e,t,r){"use strict";var n="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Int32Array;r.assign=function(e){for(var t=Array.prototype.slice.call(arguments,1);t.length;){var r=t.shift();if(r){if("object"!=typeof r)throw new TypeError(r+"must be non-object");for(var n in r)r.hasOwnProperty(n)&&(e[n]=r[n])}}return e},r.shrinkBuf=function(e,t){return e.length===t?e:e.subarray?e.subarray(0,t):(e.length=t,e)};var o={arraySet:function(e,t,r,n,o){if(t.subarray&&e.subarray)return void e.set(t.subarray(r,r+n),o);for(var a=0;a=252?6:d>=248?5:d>=240?4:d>=224?3:d>=192?2:1;s[254]=s[254]=1,r.string2buf=function(e){var t,r,n,a,i,s=e.length,d=0;for(a=0;a>>6,t[i++]=128|63&r):r<65536?(t[i++]=224|r>>>12,t[i++]=128|r>>>6&63,t[i++]=128|63&r):(t[i++]=240|r>>>18,t[i++]=128|r>>>12&63,t[i++]=128|r>>>6&63,t[i++]=128|63&r);return t},r.buf2binstring=function(e){return n(e,e.length)},r.binstring2buf=function(e){for(var t=new o.Buf8(e.length),r=0,n=t.length;r4)l[o++]=65533,r+=i-1;else{for(a&=2===i?31:3===i?15:7;i>1&&r1?l[o++]=65533:a<65536?l[o++]=a:(a-=65536,l[o++]=55296|a>>10&1023,l[o++]=56320|1023&a)}return n(l,o)},r.utf8border=function(e,t){var r;for(t=t||e.length,t>e.length&&(t=e.length),r=t-1;r>=0&&128===(192&e[r]);)r--;return r<0?t:0===r?t:r+s[e[r]]>t?r:t}},"zlib/inflate.js":function(e,t,r){"use strict";function n(e){return(e>>>24&255)+(e>>>8&65280)+((65280&e)<<8)+((255&e)<<24)}function o(){this.mode=0,this.last=!1,this.wrap=0,this.havedict=!1,this.flags=0,this.dmax=0,this.check=0,this.total=0,this.head=null,this.wbits=0,this.wsize=0,this.whave=0,this.wnext=0,this.window=null,this.hold=0,this.bits=0,this.length=0,this.offset=0,this.extra=0,this.lencode=null,this.distcode=null,this.lenbits=0,this.distbits=0,this.ncode=0,this.nlen=0,this.ndist=0,this.have=0,this.next=null,this.lens=new g.Buf16(320),this.work=new g.Buf16(288),this.lendyn=null,this.distdyn=null,this.sane=0,this.back=0,this.was=0}function a(e){var t;return e&&e.state?(t=e.state,e.total_in=e.total_out=t.total=0,e.msg="",t.wrap&&(e.adler=1&t.wrap),t.mode=I,t.last=0,t.havedict=0,t.dmax=32768,t.head=null,t.hold=0,t.bits=0,t.lencode=t.lendyn=new g.Buf32(pe),t.distcode=t.distdyn=new g.Buf32(me),t.sane=1,t.back=-1,O):R}function i(e){var t;return e&&e.state?(t=e.state,t.wsize=0,t.whave=0,t.wnext=0,a(e)):R}function s(e,t){var r,n;return e&&e.state?(n=e.state,t<0?(r=0,t=-t):(r=(t>>4)+1,t<48&&(t&=15)),t&&(t<8||t>15)?R:(null!==n.window&&n.wbits!==t&&(n.window=null),n.wrap=r,n.wbits=t,i(e))):R}function d(e,t){var r,n;return e?(n=new o,e.state=n,n.window=null,r=s(e,t),r!==O&&(e.state=null),r):R}function l(e){return d(e,ge)}function f(e){if(ye){var t;for(m=new g.Buf32(512),b=new g.Buf32(32),t=0;t<144;)e.lens[t++]=8;for(;t<256;)e.lens[t++]=9;for(;t<280;)e.lens[t++]=7;for(;t<288;)e.lens[t++]=8;for(U(k,e.lens,0,288,m,0,e.work,{bits:9}),t=0;t<32;)e.lens[t++]=5;U(E,e.lens,0,32,b,0,e.work,{bits:5}),ye=!1}e.lencode=m,e.lenbits=9,e.distcode=b,e.distbits=5}function u(e,t,r,n){var o,a=e.state;return null===a.window&&(a.wsize=1<=a.wsize?(g.arraySet(a.window,t,r-a.wsize,a.wsize,0),a.wnext=0,a.whave=a.wsize):(o=a.wsize-a.wnext,o>n&&(o=n),g.arraySet(a.window,t,r-n,o,a.wnext),n-=o,n?(g.arraySet(a.window,t,r-n,n,0),a.wnext=n,a.whave=a.wsize):(a.wnext+=o,a.wnext===a.wsize&&(a.wnext=0),a.whave>>8&255,r.check=A(r.check,We,2,0),c=0,h=0,r.mode=F;break}if(r.flags=0,r.head&&(r.head.done=!1),!(1&r.wrap)||(((255&c)<<8)+(c>>8))%31){e.msg="incorrect header check",r.mode=ce;break}if((15&c)!==S){e.msg="unknown compression method",r.mode=ce;break}if(c>>>=4,h-=4,Ue=(15&c)+8,0===r.wbits)r.wbits=Ue;else if(Ue>r.wbits){e.msg="invalid window size",r.mode=ce;break}r.dmax=1<>8&1),512&r.flags&&(We[0]=255&c,We[1]=c>>>8&255,r.check=A(r.check,We,2,0)),c=0,h=0,r.mode=P;case P:for(;h<32;){if(0===d)break e;d--,c+=o[i++]<>>8&255,We[2]=c>>>16&255,We[3]=c>>>24&255,r.check=A(r.check,We,4,0)),c=0,h=0,r.mode=V;case V:for(;h<16;){if(0===d)break e;d--,c+=o[i++]<>8),512&r.flags&&(We[0]=255&c,We[1]=c>>>8&255,r.check=A(r.check,We,2,0)),c=0,h=0,r.mode=D;case D:if(1024&r.flags){for(;h<16;){if(0===d)break e;d--,c+=o[i++]<>>8&255,r.check=A(r.check,We,2,0)),c=0,h=0}else r.head&&(r.head.extra=null);r.mode=Z;case Z:if(1024&r.flags&&(m=r.length,m>d&&(m=d),m&&(r.head&&(Ue=r.head.extra_len-r.length,r.head.extra||(r.head.extra=new Array(r.head.extra_len)),g.arraySet(r.head.extra,o,i,m,Ue)),512&r.flags&&(r.check=A(r.check,o,m,i)),d-=m,i+=m,r.length-=m),r.length))break e;r.length=0,r.mode=q;case q:if(2048&r.flags){if(0===d)break e;m=0;do Ue=o[i+m++],r.head&&Ue&&r.length<65536&&(r.head.name+=String.fromCharCode(Ue));while(Ue&&m>9&1,r.head.done=!0),e.adler=r.check=0,r.mode=j;break;case J:for(;h<32;){if(0===d)break e;d--,c+=o[i++]<>>=7&h,h-=7&h,r.mode=le;break}for(;h<3;){if(0===d)break e;d--,c+=o[i++]<>>=1,h-=1,3&c){case 0:r.mode=K;break;case 1:if(f(r),r.mode=re,t===L){c>>>=2,h-=2;break e}break;case 2:r.mode=$;break;case 3:e.msg="invalid block type",r.mode=ce}c>>>=2,h-=2;break;case K:for(c>>>=7&h,h-=7&h;h<32;){if(0===d)break e;d--,c+=o[i++]<>>16^65535)){e.msg="invalid stored block lengths",r.mode=ce;break}if(r.length=65535&c,c=0,h=0,r.mode=Q,t===L)break e;case Q:r.mode=_;case _:if(m=r.length){if(m>d&&(m=d),m>l&&(m=l),0===m)break e;g.arraySet(a,o,i,m,s),d-=m,i+=m,l-=m,s+=m,r.length-=m;break}r.mode=j;break;case $:for(;h<14;){if(0===d)break e;d--,c+=o[i++]<>>=5,h-=5,r.ndist=(31&c)+1,c>>>=5,h-=5,r.ncode=(15&c)+4,c>>>=4,h-=4,r.nlen>286||r.ndist>30){e.msg="too many length or distance symbols",r.mode=ce;break}r.have=0,r.mode=ee;case ee:for(;r.have>>=3,h-=3}for(;r.have<19;)r.lens[Le[r.have++]]=0;if(r.lencode=r.lendyn,r.lenbits=7,ke={bits:r.lenbits},xe=U(x,r.lens,0,19,r.lencode,0,r.work,ke),r.lenbits=ke.bits,xe){e.msg="invalid code lengths set",r.mode=ce;break}r.have=0,r.mode=te;case te:for(;r.have>>24,be=Be>>>16&255,ge=65535&Be,!(me<=h);){if(0===d)break e;d--,c+=o[i++]<>>=me,h-=me,r.lens[r.have++]=ge;else{if(16===ge){for(Ee=me+2;h>>=me,h-=me,0===r.have){e.msg="invalid bit length repeat",r.mode=ce;break}Ue=r.lens[r.have-1],m=3+(3&c),c>>>=2,h-=2}else if(17===ge){for(Ee=me+3;h>>=me,h-=me,Ue=0,m=3+(7&c),c>>>=3,h-=3}else{for(Ee=me+7;h>>=me,h-=me,Ue=0,m=11+(127&c),c>>>=7,h-=7}if(r.have+m>r.nlen+r.ndist){e.msg="invalid bit length repeat",r.mode=ce;break}for(;m--;)r.lens[r.have++]=Ue}}if(r.mode===ce)break;if(0===r.lens[256]){e.msg="invalid code -- missing end-of-block",r.mode=ce;break}if(r.lenbits=9,ke={bits:r.lenbits},xe=U(k,r.lens,0,r.nlen,r.lencode,0,r.work,ke),r.lenbits=ke.bits,xe){e.msg="invalid literal/lengths set",r.mode=ce;break}if(r.distbits=6,r.distcode=r.distdyn,ke={bits:r.distbits},xe=U(E,r.lens,r.nlen,r.ndist,r.distcode,0,r.work,ke),r.distbits=ke.bits,xe){e.msg="invalid distances set",r.mode=ce;break}if(r.mode=re,t===L)break e;case re:r.mode=ne;case ne:if(d>=6&&l>=258){e.next_out=s,e.avail_out=l,e.next_in=i,e.avail_in=d,r.hold=c,r.bits=h,v(e,p),s=e.next_out,a=e.output,l=e.avail_out,i=e.next_in,o=e.input,d=e.avail_in,c=r.hold,h=r.bits,r.mode===j&&(r.back=-1);break}for(r.back=0;Be=r.lencode[c&(1<>>24,be=Be>>>16&255,ge=65535&Be,!(me<=h);){if(0===d)break e;d--,c+=o[i++]<>ye)],me=Be>>>24,be=Be>>>16&255,ge=65535&Be,!(ye+me<=h);){if(0===d)break e;d--,c+=o[i++]<>>=ye,h-=ye,r.back+=ye}if(c>>>=me,h-=me,r.back+=me,r.length=ge,0===be){r.mode=de;break}if(32&be){r.back=-1,r.mode=j;break}if(64&be){e.msg="invalid literal/length code",r.mode=ce;break}r.extra=15&be,r.mode=oe;case oe:if(r.extra){for(Ee=r.extra;h>>=r.extra,h-=r.extra,r.back+=r.extra}r.was=r.length,r.mode=ae;case ae:for(;Be=r.distcode[c&(1<>>24,be=Be>>>16&255,ge=65535&Be,!(me<=h);){if(0===d)break e;d--,c+=o[i++]<>ye)],me=Be>>>24,be=Be>>>16&255,ge=65535&Be,!(ye+me<=h);){if(0===d)break e;d--,c+=o[i++]<>>=ye,h-=ye,r.back+=ye}if(c>>>=me,h-=me,r.back+=me,64&be){e.msg="invalid distance code",r.mode=ce;break}r.offset=ge,r.extra=15&be,r.mode=ie;case ie:if(r.extra){for(Ee=r.extra;h>>=r.extra,h-=r.extra,r.back+=r.extra}if(r.offset>r.dmax){e.msg="invalid distance too far back",r.mode=ce;break}r.mode=se;case se:if(0===l)break e;if(m=p-l,r.offset>m){if(m=r.offset-m,m>r.whave&&r.sane){e.msg="invalid distance too far back",r.mode=ce;break}m>r.wnext?(m-=r.wnext,b=r.wsize-m):b=r.wnext-m,m>r.length&&(m=r.length),pe=r.window}else pe=a,b=s-r.offset,m=r.length;m>l&&(m=l),l-=m,r.length-=m;do a[s++]=pe[b++];while(--m);0===r.length&&(r.mode=ne);break;case de:if(0===l)break e;a[s++]=r.length,l--,r.mode=ne;break;case le:if(r.wrap){for(;h<32;){if(0===d)break e;d--,c|=o[i++]<>>16&65535|0,i=0;0!==r;){i=r>2e3?2e3:r,r-=i;do o=o+t[n++]|0,a=a+o|0;while(--i);o%=65521,a%=65521}return o|a<<16|0}t.exports=n},"zlib/crc32.js":function(e,t,r){"use strict";function n(){for(var e,t=[],r=0;r<256;r++){e=r;for(var n=0;n<8;n++)e=1&e?3988292384^e>>>1:e>>>1;t[r]=e}return t}function o(e,t,r,n){var o=a,i=n+r;e^=-1;for(var s=n;s>>8^o[255&(e^t[s])];return e^-1}var a=n();t.exports=o},"zlib/inffast.js":function(e,t,r){"use strict";var n=30,o=12;t.exports=function(e,t){var r,a,i,s,d,l,f,u,c,h,w,p,m,b,g,y,A,v,U,x,k,E,B,W,L;r=e.state,a=e.next_in,W=e.input,i=a+(e.avail_in-5),s=e.next_out,L=e.output,d=s-(t-e.avail_out),l=s+(e.avail_out-257),f=r.dmax,u=r.wsize,c=r.whave,h=r.wnext,w=r.window,p=r.hold,m=r.bits,b=r.lencode,g=r.distcode,y=(1<>>24,p>>>=U,m-=U,U=v>>>16&255,0===U)L[s++]=65535&v;else{if(!(16&U)){if(0===(64&U)){v=b[(65535&v)+(p&(1<>>=U,m-=U),m<15&&(p+=W[a++]<>>24,p>>>=U,m-=U,U=v>>>16&255,!(16&U)){if(0===(64&U)){v=g[(65535&v)+(p&(1<f){e.msg="invalid distance too far back",r.mode=n;break e}if(p>>>=U,m-=U,U=s-d,k>U){if(U=k-U,U>c&&r.sane){e.msg="invalid distance too far back",r.mode=n;break e}if(E=0,B=w,0===h){if(E+=u-U,U2;)L[s++]=B[E++],L[s++]=B[E++],L[s++]=B[E++],x-=3;x&&(L[s++]=B[E++],x>1&&(L[s++]=B[E++]))}else{E=s-k;do L[s++]=L[E++],L[s++]=L[E++],L[s++]=L[E++],x-=3;while(x>2);x&&(L[s++]=L[E++],x>1&&(L[s++]=L[E++]))}break}}break}}while(a>3,a-=x,m-=x<<3,p&=(1<=1&&0===D[R];R--);if(C>R&&(C=R),0===R)return p[m++]=20971520,p[m++]=20971520,g.bits=1,0;for(N=1;N0&&(e===s||1!==R))return-1;for(Z[1]=0,O=1;Oa||e===l&&I>i)return 1;for(;;){E=O-T,b[M]k?(B=q[Y+b[M]],W=P[V+b[M]]):(B=96,W=0),y=1<>T)+A]=E<<24|B<<16|W|0;while(0!==A);for(y=1<>=1;if(0!==y?(F&=y-1,F+=y):F=0,M++,0===--D[O]){if(O===R)break;O=t[r+b[M]]}if(O>C&&(F&U)!==v){for(0===T&&(T=C),x+=N,H=O-T,S=1<a||e===l&&I>i)return 1;v=F&U,p[v]=C<<24|H<<16|x-m|0}}return 0!==F&&(p[x+F]=O-T<<24|64<<16|0),g.bits=C,0}}};for(var r in t)t[r].folder=r.substring(0,r.lastIndexOf("/")+1);var n=function(e){var r=[];return e=e.split("/").every(function(e){return".."==e?r.pop():"."==e||""==e||r.push(e)})?r.join("/"):null,e?t[e]||t[e+".js"]||t[e+"/index.js"]:null},o=function(e,t){return e?n(e.folder+"node_modules/"+t)||o(e.parent,t):null},a=function(e,t){var r=t.match(/^\//)?null:e?t.match(/^\.\.?\//)?n(e.folder+t):o(e,t):n(t);if(!r)throw"module not found: "+t;return r.exports||(r.parent=e,r(a.bind(null,r),r,r.exports={})),r.exports};return a(null,e)},decompress:function(e){this.exports||(this.exports=this.require("inflate.js"));try{return this.exports.inflate(e)}catch(e){}},hasUnityMarker:function(e){var t=10,r="UnityWeb Compressed Content (gzip)";if(t>e.length||31!=e[0]||139!=e[1])return!1;var n=e[3];if(4&n){if(t+2>e.length)return!1;if(t+=2+e[t]+(e[t+1]<<8),t>e.length)return!1}if(8&n){for(;te.length)return!1;t++}return 16&n&&String.fromCharCode.apply(null,e.subarray(t,t+r.length+1))==r+"\0"}},brotli:{require:function(e){var t={"decompress.js":function(e,t,r){t.exports=e("./dec/decode").BrotliDecompressBuffer},"dec/bit_reader.js":function(e,t,r){function n(e){this.buf_=new Uint8Array(a),this.input_=e,this.reset()}const o=4096,a=8224,i=8191,s=new Uint32Array([0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535,131071,262143,524287,1048575,2097151,4194303,8388607,16777215]);n.READ_SIZE=o,n.IBUF_MASK=i,n.prototype.reset=function(){this.buf_ptr_=0,this.val_=0,this.pos_=0,this.bit_pos_=0,this.bit_end_pos_=0,this.eos_=0,this.readMoreInput();for(var e=0;e<4;e++)this.val_|=this.buf_[this.pos_]<<8*e,++this.pos_;return this.bit_end_pos_>0},n.prototype.readMoreInput=function(){if(!(this.bit_end_pos_>256))if(this.eos_){if(this.bit_pos_>this.bit_end_pos_)throw new Error("Unexpected end of input "+this.bit_pos_+" "+this.bit_end_pos_)}else{var e=this.buf_ptr_,t=this.input_.read(this.buf_,e,o);if(t<0)throw new Error("Unexpected end of input");if(t=8;)this.val_>>>=8,this.val_|=this.buf_[this.pos_&i]<<24,++this.pos_,this.bit_pos_=this.bit_pos_-8>>>0,this.bit_end_pos_=this.bit_end_pos_-8>>>0},n.prototype.readBits=function(e){32-this.bit_pos_>>this.bit_pos_&s[e];return this.bit_pos_+=e,t},t.exports=n},"dec/context.js":function(e,t,r){r.lookup=new Uint8Array([0,0,0,0,0,0,0,0,0,4,4,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,12,16,12,12,20,12,16,24,28,12,12,32,12,36,12,44,44,44,44,44,44,44,44,44,44,32,32,24,40,28,12,12,48,52,52,52,48,52,52,52,48,52,52,52,52,52,48,52,52,52,52,52,48,52,52,52,52,52,24,12,28,12,12,12,56,60,60,60,56,60,60,60,56,60,60,60,60,60,56,60,60,60,60,60,56,60,60,60,60,60,24,12,28,12,0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,0,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,56,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7,8,8,8,8,9,9,9,9,10,10,10,10,11,11,11,11,12,12,12,12,13,13,13,13,14,14,14,14,15,15,15,15,16,16,16,16,17,17,17,17,18,18,18,18,19,19,19,19,20,20,20,20,21,21,21,21,22,22,22,22,23,23,23,23,24,24,24,24,25,25,25,25,26,26,26,26,27,27,27,27,28,28,28,28,29,29,29,29,30,30,30,30,31,31,31,31,32,32,32,32,33,33,33,33,34,34,34,34,35,35,35,35,36,36,36,36,37,37,37,37,38,38,38,38,39,39,39,39,40,40,40,40,41,41,41,41,42,42,42,42,43,43,43,43,44,44,44,44,45,45,45,45,46,46,46,46,47,47,47,47,48,48,48,48,49,49,49,49,50,50,50,50,51,51,51,51,52,52,52,52,53,53,53,53,54,54,54,54,55,55,55,55,56,56,56,56,57,57,57,57,58,58,58,58,59,59,59,59,60,60,60,60,61,61,61,61,62,62,62,62,63,63,63,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]),r.lookupOffsets=new Uint16Array([1024,1536,1280,1536,0,256,768,512])},"dec/decode.js":function(e,t,r){function n(e){var t;return 0===e.readBits(1)?16:(t=e.readBits(3),t>0?17+t:(t=e.readBits(3),t>0?8+t:17))}function o(e){if(e.readBits(1)){var t=e.readBits(3);return 0===t?1:e.readBits(t)+(1<1&&0===i)throw new Error("Invalid size byte");o.meta_block_length|=i<<8*n}}else for(n=0;n4&&0===s)throw new Error("Invalid size nibble");o.meta_block_length|=s<<4*n}return++o.meta_block_length,o.input_end||o.is_metadata||(o.is_uncompressed=e.readBits(1)),o}function s(e,t,r){var n;return r.fillBitWindow(),t+=r.val_>>>r.bit_pos_&P,n=e[t].bits-F,n>0&&(r.bit_pos_+=F,t+=e[t].value,t+=r.val_>>>r.bit_pos_&(1<0;){var u,c=0;if(n.readMoreInput(),n.fillBitWindow(),c+=n.val_>>>n.bit_pos_&31,n.bit_pos_+=l[c].bits,u=255&l[c].value,u>u);else{var h,w,p=u-14,m=0;if(u===R&&(m=a),s!==m&&(i=0,s=m),h=i,i>0&&(i-=2,i<<=p),i+=n.readBits(p)+3,w=i-h,o+w>t)throw new Error("[ReadHuffmanCodeLengths] symbol + repeat_delta > num_symbols");for(var b=0;b0;++s){var b,g=Z[s],y=0;n.fillBitWindow(), +y+=n.val_>>>n.bit_pos_&15,n.bit_pos_+=m[y].bits,b=m[y].value,h[g]=b,0!==b&&(w-=32>>b,++p)}if(1!==p&&0!==w)throw new Error("[ReadHuffmanCode] invalid num_codes or space");d(h,e,i,n)}if(a=W(t,r,F,i,e),0===a)throw new Error("[ReadHuffmanCode] BuildHuffmanTable failed: ");return a}function f(e,t,r){var n,o;return n=s(e,t,r),o=O.kBlockLengthPrefixCode[n].nbits,O.kBlockLengthPrefixCode[n].offset+r.readBits(o)}function u(e,t,r){var n;return e>>5]),this.htrees=new Uint32Array(t)}function p(e,t){var r,n,a,i={num_htrees:null,context_map:null},d=0;t.readMoreInput();var f=i.num_htrees=o(t)+1,u=i.context_map=new Uint8Array(e);if(f<=1)return i;for(r=t.readBits(1),r&&(d=t.readBits(4)+1),n=[],a=0;a=e)throw new Error("[DecodeContextMap] i >= context_map_size");u[a]=0,++a}else u[a]=c-d,++a}return t.readBits(1)&&h(u,e),i}function m(e,t,r,n,o,a,i){var d,l=2*r,f=r,u=s(t,r*V,i);d=0===u?o[l+(1&a[f])]:1===u?o[l+(a[f]-1&1)]+1:u-2,d>=e&&(d-=e),n[r]=d,o[l+(1&a[f])]=d,++a[f]}function b(e,t,r,n,o,a){var i,s=o+1,d=r&o,l=a.pos_&k.IBUF_MASK;if(t<8||a.bit_pos_+(t<<3)0;)a.readMoreInput(),n[d++]=a.readBits(8),d===s&&(e.write(n,s),d=0);else{if(a.bit_end_pos_<32)throw new Error("[CopyUncompressedBlockToOutput] br.bit_end_pos_ < 32");for(;a.bit_pos_<32;)n[d]=a.val_>>>a.bit_pos_,a.bit_pos_+=8,++d,--t;if(i=a.bit_end_pos_-a.bit_pos_>>3,l+i>k.IBUF_MASK){for(var f=k.IBUF_MASK+1-l,u=0;u=s){e.write(n,s),d-=s;for(var u=0;u=s;){if(i=s-d,a.input_.read(n,d,i)t.buffer.length){var Ae=new Uint8Array(x+re);Ae.set(t.buffer),t.buffer=Ae}if(W=ye.input_end,G=ye.is_uncompressed,ye.is_metadata)for(g(U);re>0;--re)U.readMoreInput(),U.readBits(8);else if(0!==re)if(G)U.bit_pos_=U.bit_pos_+7&-8,b(t,re,x,h,c,U),x+=re;else{for(r=0;r<3;++r)ae[r]=o(U)+1,ae[r]>=2&&(l(ae[r]+2,A,r*V,U),l(T,v,r*V,U),ne[r]=f(v,r*V,U),se[r]=1);for(U.readMoreInput(),j=U.readBits(2),X=q+(U.readBits(4)<0;){var xe,ke,Ee,Be,We,Le,Oe,Me,Ne,Re,Ce;for(U.readMoreInput(),0===ne[1]&&(m(ae[1],A,1,oe,ie,se,U),ne[1]=f(v,V,U),te=Y[1].htrees[oe[1]]),--ne[1],xe=s(Y[1].codes,te,U),ke=xe>>6,ke>=2?(ke-=2,Oe=-1):Oe=0,Ee=O.kInsertRangeLut[ke]+(xe>>3&7),Be=O.kCopyRangeLut[ke]+(7&xe),We=O.kInsertLengthPrefixCode[Ee].offset+U.readBits(O.kInsertLengthPrefixCode[Ee].nbits),Le=O.kCopyLengthPrefixCode[Be].offset+U.readBits(O.kCopyLengthPrefixCode[Be].nbits),D=h[x-1&c],Z=h[x-2&c],Re=0;Re4?3:Le-2),me=fe[pe+Ne],Oe=s(Y[2].codes,Y[2].htrees[me],U),Oe>=X){var He,Te,Se;Oe-=X,Te=Oe&K,Oe>>=j,He=(Oe>>1)+1,Se=(2+(1&Oe)<R){if(!(Le>=E.minDictionaryWordLength&&Le<=E.maxDictionaryWordLength))throw new Error("Invalid backward reference. pos: "+x+" distance: "+Me+" len: "+Le+" bytes left: "+re);var Se=E.offsetsByLength[Le],Ie=Me-R-1,Fe=E.sizeBitsByLength[Le],Pe=(1<>Fe;if(Se+=Ve*Le,!(De=y){t.write(h,d);for(var qe=0;qe0&&(F[3&P]=Me,++P),Le>re)throw new Error("Invalid backward reference. pos: "+x+" distance: "+Me+" len: "+Le+" bytes left: "+re);for(Re=0;Re>=1;return(e&r-1)+r}function a(e,t,r,o,a){do o-=r,e[t+o]=new n(a.bits,a.value);while(o>0)}function i(e,t,r){for(var n=1<0;--U[u])f=new n(255&u,65535&A[c++]),a(e,t+h,w,g,f),h=o(h,u);for(m=y-1,p=-1,u=r+1,w=2;u<=s;++u,w<<=1)for(;U[u]>0;--U[u])(h&m)!==p&&(t+=g,b=i(U,u,r),g=1<>r),w,g,f),h=o(h,u);return y}},"dec/prefix.js":function(e,t,r){function n(e,t){this.offset=e,this.nbits=t}r.kBlockLengthPrefixCode=[new n(1,2),new n(5,2),new n(9,2),new n(13,2),new n(17,3),new n(25,3),new n(33,3),new n(41,3),new n(49,4),new n(65,4),new n(81,4),new n(97,4),new n(113,5),new n(145,5),new n(177,5),new n(209,5),new n(241,6),new n(305,6),new n(369,7),new n(497,8),new n(753,9),new n(1265,10),new n(2289,11),new n(4337,12),new n(8433,13),new n(16625,24)],r.kInsertLengthPrefixCode=[new n(0,0),new n(1,0),new n(2,0),new n(3,0),new n(4,0),new n(5,0),new n(6,1),new n(8,1),new n(10,2),new n(14,2),new n(18,3),new n(26,3),new n(34,4),new n(50,4),new n(66,5),new n(98,5),new n(130,6),new n(194,7),new n(322,8),new n(578,9),new n(1090,10),new n(2114,12),new n(6210,14),new n(22594,24)],r.kCopyLengthPrefixCode=[new n(2,0),new n(3,0),new n(4,0),new n(5,0),new n(6,0),new n(7,0),new n(8,0),new n(9,0),new n(10,1),new n(12,1),new n(14,2),new n(18,2),new n(22,3),new n(30,3),new n(38,4),new n(54,4),new n(70,5),new n(102,5),new n(134,6),new n(198,7),new n(326,8),new n(582,9),new n(1094,10),new n(2118,24)],r.kInsertRangeLut=[0,0,8,8,0,16,8,16,16],r.kCopyRangeLut=[0,8,0,8,16,0,16,8,16]},"dec/streams.js":function(e,t,r){function n(e){this.buffer=e,this.pos=0}function o(e){this.buffer=e,this.pos=0}n.prototype.read=function(e,t,r){this.pos+r>this.buffer.length&&(r=this.buffer.length-this.pos);for(var n=0;nthis.buffer.length)throw new Error("Output buffer is not large enough");return this.buffer.set(e.subarray(0,t),this.pos),this.pos+=t,t},r.BrotliOutput=o},"dec/transform.js":function(e,t,r){function n(e,t,r){this.prefix=new Uint8Array(e.length),this.transform=t,this.suffix=new Uint8Array(r.length);for(var n=0;n=97&&e[t]<=122&&(e[t]^=32),1):e[t]<224?(e[t+1]^=32,2):(e[t+2]^=5,3)}var a=e("./dictionary");const i=0,s=1,d=2,l=3,f=4,u=5,c=6,h=7,w=8,p=9,m=10,b=11,g=12,y=13,A=14,v=15,U=16,x=17,k=18,E=20;var B=[new n("",i,""),new n("",i," "),new n(" ",i," "),new n("",g,""),new n("",m," "),new n("",i," the "),new n(" ",i,""),new n("s ",i," "),new n("",i," of "),new n("",m,""),new n("",i," and "),new n("",y,""),new n("",s,""),new n(", ",i," "),new n("",i,", "),new n(" ",m," "),new n("",i," in "),new n("",i," to "),new n("e ",i," "),new n("",i,'"'),new n("",i,"."),new n("",i,'">'),new n("",i,"\n"),new n("",l,""),new n("",i,"]"),new n("",i," for "),new n("",A,""),new n("",d,""),new n("",i," a "),new n("",i," that "),new n(" ",m,""),new n("",i,". "),new n(".",i,""),new n(" ",i,", "),new n("",v,""),new n("",i," with "),new n("",i,"'"),new n("",i," from "),new n("",i," by "),new n("",U,""),new n("",x,""),new n(" the ",i,""),new n("",f,""),new n("",i,". The "),new n("",b,""),new n("",i," on "),new n("",i," as "),new n("",i," is "),new n("",h,""),new n("",s,"ing "),new n("",i,"\n\t"),new n("",i,":"),new n(" ",i,". "),new n("",i,"ed "),new n("",E,""),new n("",k,""),new n("",c,""),new n("",i,"("),new n("",m,", "),new n("",w,""),new n("",i," at "),new n("",i,"ly "),new n(" the ",i," of "),new n("",u,""),new n("",p,""),new n(" ",m,", "),new n("",m,'"'),new n(".",i,"("),new n("",b," "),new n("",m,'">'),new n("",i,'="'),new n(" ",i,"."),new n(".com/",i,""),new n(" the ",i," of the "),new n("",m,"'"),new n("",i,". This "),new n("",i,","),new n(".",i," "),new n("",m,"("),new n("",m,"."),new n("",i," not "),new n(" ",i,'="'),new n("",i,"er "),new n(" ",b," "),new n("",i,"al "),new n(" ",b,""),new n("",i,"='"),new n("",b,'"'),new n("",m,". "),new n(" ",i,"("),new n("",i,"ful "),new n(" ",m,". "),new n("",i,"ive "),new n("",i,"less "),new n("",b,"'"),new n("",i,"est "),new n(" ",m,"."),new n("",b,'">'),new n(" ",i,"='"),new n("",m,","),new n("",i,"ize "),new n("",b,"."),new n("\xc2\xa0",i,""),new n(" ",i,","),new n("",m,'="'),new n("",b,'="'),new n("",i,"ous "),new n("",b,", "),new n("",m,"='"),new n(" ",m,","),new n(" ",b,'="'),new n(" ",b,", "),new n("",b,","),new n("",b,"("),new n("",b,". "),new n(" ",b,"."),new n("",b,"='"),new n(" ",b,". "),new n(" ",m,'="'),new n(" ",b,"='"),new n(" ",m,"='")];r.kTransforms=B,r.kNumTransforms=B.length,r.transformDictionaryWord=function(e,t,r,n,i){var s,d=B[i].prefix,l=B[i].suffix,f=B[i].transform,u=fn&&(u=n);for(var w=0;w0;){var y=o(e,s);s+=y,n-=y}for(var A=0;A0)throw new Error("Invalid string. Length must be a multiple of 4");return"="===e[t-2]?2:"="===e[t-1]?1:0}function o(e){return 3*e.length/4-n(e)}function a(e){var t,r,o,a,i,s,d=e.length;i=n(e),s=new u(3*d/4-i),o=i>0?d-4:d;var l=0;for(t=0,r=0;t>16&255,s[l++]=a>>8&255,s[l++]=255&a;return 2===i?(a=f[e.charCodeAt(t)]<<2|f[e.charCodeAt(t+1)]>>4,s[l++]=255&a):1===i&&(a=f[e.charCodeAt(t)]<<10|f[e.charCodeAt(t+1)]<<4|f[e.charCodeAt(t+2)]>>2,s[l++]=a>>8&255,s[l++]=255&a),s}function i(e){return l[e>>18&63]+l[e>>12&63]+l[e>>6&63]+l[63&e]}function s(e,t,r){for(var n,o=[],a=t;af?f:d+i));return 1===n?(t=e[r-1],o+=l[t>>2],o+=l[t<<4&63],o+="=="):2===n&&(t=(e[r-2]<<8)+e[r-1],o+=l[t>>10],o+=l[t>>4&63],o+=l[t<<2&63],o+="="),a.push(o),a.join("")}r.byteLength=o,r.toByteArray=a,r.fromByteArray=d;for(var l=[],f=[],u="undefined"!=typeof Uint8Array?Uint8Array:Array,c="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",h=0,w=c.length;h>3);if(commentOffset=r+1+2+1+2+(o<<3)+7>>3,17==n||commentOffset>e.length)return!1;for(var a=n+(6+(o<<4)+(t.length-1<<6)<>>=8)if(e[i]!=(255&a))return!1;return String.fromCharCode.apply(null,e.subarray(commentOffset,commentOffset+t.length))==t}},decompress:function(e,t){var r=this.gzip.hasUnityMarker(e)?this.gzip:this.brotli.hasUnityMarker(e)?this.brotli:this.identity;if("function"!=typeof t)return r.decompress(e);if(!r.worker){var n=URL.createObjectURL(new Blob(["this.require = ",r.require,"; this.decompress = ",r.decompress,"; this.onmessage = ",function(e){var t={id:e.data.id,decompressed:this.decompress(e.data.compressed)};postMessage(t,t.decompressed?[t.decompressed.buffer]:[])},"; postMessage({ ready: true });"],{type:"text/javascript"}));r.worker=new Worker(n),r.worker.onmessage=function(e){return e.data.ready?void URL.revokeObjectURL(n):(this.callbacks[e.data.id](e.data.decompressed),void delete this.callbacks[e.data.id])},r.worker.callbacks={},r.worker.nextCallbackId=0}var o=r.worker.nextCallbackId++;r.worker.callbacks[o]=t,r.worker.postMessage({id:o,compressed:e},[e.buffer])}}}; \ No newline at end of file diff --git a/docs/sardines-v1.1.0/Build/sardines-v1.1.0.asm.code.unityweb b/docs/sardines-v1.1.0/Build/sardines-v1.1.0.asm.code.unityweb new file mode 100644 index 0000000..51c38d6 Binary files /dev/null and b/docs/sardines-v1.1.0/Build/sardines-v1.1.0.asm.code.unityweb differ diff --git a/docs/sardines-v1.1.0/Build/sardines-v1.1.0.asm.framework.unityweb b/docs/sardines-v1.1.0/Build/sardines-v1.1.0.asm.framework.unityweb new file mode 100644 index 0000000..81e91d7 Binary files /dev/null and b/docs/sardines-v1.1.0/Build/sardines-v1.1.0.asm.framework.unityweb differ diff --git a/docs/sardines-v1.1.0/Build/sardines-v1.1.0.asm.memory.unityweb b/docs/sardines-v1.1.0/Build/sardines-v1.1.0.asm.memory.unityweb new file mode 100644 index 0000000..ae74e63 Binary files /dev/null and b/docs/sardines-v1.1.0/Build/sardines-v1.1.0.asm.memory.unityweb differ diff --git a/docs/sardines-v1.1.0/Build/sardines-v1.1.0.data.unityweb b/docs/sardines-v1.1.0/Build/sardines-v1.1.0.data.unityweb new file mode 100644 index 0000000..64c7da9 Binary files /dev/null and b/docs/sardines-v1.1.0/Build/sardines-v1.1.0.data.unityweb differ diff --git a/docs/sardines-v1.1.0/Build/sardines-v1.1.0.json b/docs/sardines-v1.1.0/Build/sardines-v1.1.0.json new file mode 100644 index 0000000..59058d6 --- /dev/null +++ b/docs/sardines-v1.1.0/Build/sardines-v1.1.0.json @@ -0,0 +1,9 @@ +{ +"TOTAL_MEMORY": 268435456, +"dataUrl": "sardines-v1.1.0.data.unityweb", +"asmCodeUrl": "sardines-v1.1.0.asm.code.unityweb", +"asmMemoryUrl": "sardines-v1.1.0.asm.memory.unityweb", +"asmFrameworkUrl": "sardines-v1.1.0.asm.framework.unityweb", +"splashScreenStyle": "Dark", +"backgroundColor": "#222C36" +} \ No newline at end of file diff --git a/docs/sardines-v1.1.0/TemplateData/UnityProgress.js b/docs/sardines-v1.1.0/TemplateData/UnityProgress.js new file mode 100644 index 0000000..1ed4372 --- /dev/null +++ b/docs/sardines-v1.1.0/TemplateData/UnityProgress.js @@ -0,0 +1,24 @@ +function UnityProgress(gameInstance, progress) { + if (!gameInstance.Module) + return; + if (!gameInstance.logo) { + gameInstance.logo = document.createElement("div"); + gameInstance.logo.className = "logo " + gameInstance.Module.splashScreenStyle; + gameInstance.container.appendChild(gameInstance.logo); + } + if (!gameInstance.progress) { + gameInstance.progress = document.createElement("div"); + gameInstance.progress.className = "progress " + gameInstance.Module.splashScreenStyle; + gameInstance.progress.empty = document.createElement("div"); + gameInstance.progress.empty.className = "empty"; + gameInstance.progress.appendChild(gameInstance.progress.empty); + gameInstance.progress.full = document.createElement("div"); + gameInstance.progress.full.className = "full"; + gameInstance.progress.appendChild(gameInstance.progress.full); + gameInstance.container.appendChild(gameInstance.progress); + } + gameInstance.progress.full.style.width = (100 * progress) + "%"; + gameInstance.progress.empty.style.width = (100 * (1 - progress)) + "%"; + if (progress == 1) + gameInstance.logo.style.display = gameInstance.progress.style.display = "none"; +} \ No newline at end of file diff --git a/docs/sardines-v1.1.0/TemplateData/favicon.ico b/docs/sardines-v1.1.0/TemplateData/favicon.ico new file mode 100644 index 0000000..dd6bf7e Binary files /dev/null and b/docs/sardines-v1.1.0/TemplateData/favicon.ico differ diff --git a/docs/sardines-v1.1.0/TemplateData/fullscreen.png b/docs/sardines-v1.1.0/TemplateData/fullscreen.png new file mode 100644 index 0000000..22cfc35 Binary files /dev/null and b/docs/sardines-v1.1.0/TemplateData/fullscreen.png differ diff --git a/docs/sardines-v1.1.0/TemplateData/progressEmpty.Dark.png b/docs/sardines-v1.1.0/TemplateData/progressEmpty.Dark.png new file mode 100644 index 0000000..eff4730 Binary files /dev/null and b/docs/sardines-v1.1.0/TemplateData/progressEmpty.Dark.png differ diff --git a/docs/sardines-v1.1.0/TemplateData/progressEmpty.Light.png b/docs/sardines-v1.1.0/TemplateData/progressEmpty.Light.png new file mode 100644 index 0000000..b428ec4 Binary files /dev/null and b/docs/sardines-v1.1.0/TemplateData/progressEmpty.Light.png differ diff --git a/docs/sardines-v1.1.0/TemplateData/progressFull.Dark.png b/docs/sardines-v1.1.0/TemplateData/progressFull.Dark.png new file mode 100644 index 0000000..3e5c8a0 Binary files /dev/null and b/docs/sardines-v1.1.0/TemplateData/progressFull.Dark.png differ diff --git a/docs/sardines-v1.1.0/TemplateData/progressFull.Light.png b/docs/sardines-v1.1.0/TemplateData/progressFull.Light.png new file mode 100644 index 0000000..0064427 Binary files /dev/null and b/docs/sardines-v1.1.0/TemplateData/progressFull.Light.png differ diff --git a/docs/sardines-v1.1.0/TemplateData/progressLogo.Dark.png b/docs/sardines-v1.1.0/TemplateData/progressLogo.Dark.png new file mode 100644 index 0000000..c15fb23 Binary files /dev/null and b/docs/sardines-v1.1.0/TemplateData/progressLogo.Dark.png differ diff --git a/docs/sardines-v1.1.0/TemplateData/progressLogo.Light.png b/docs/sardines-v1.1.0/TemplateData/progressLogo.Light.png new file mode 100644 index 0000000..cdd4f74 Binary files /dev/null and b/docs/sardines-v1.1.0/TemplateData/progressLogo.Light.png differ diff --git a/docs/sardines-v1.1.0/TemplateData/style.css b/docs/sardines-v1.1.0/TemplateData/style.css new file mode 100644 index 0000000..498a680 --- /dev/null +++ b/docs/sardines-v1.1.0/TemplateData/style.css @@ -0,0 +1,18 @@ +.webgl-content * {border: 0; margin: 0; padding: 0} +.webgl-content {position: absolute; top: 50%; left: 50%; -webkit-transform: translate(-50%, -50%); transform: translate(-50%, -50%);} + +.webgl-content .logo, .progress {position: absolute; left: 50%; top: 50%; -webkit-transform: translate(-50%, -50%); transform: translate(-50%, -50%);} +.webgl-content .logo {background: url('progressLogo.Light.png') no-repeat center / contain; width: 154px; height: 130px;} +.webgl-content .progress {height: 18px; width: 141px; margin-top: 90px;} +.webgl-content .progress .empty {background: url('progressEmpty.Light.png') no-repeat right / cover; float: right; width: 100%; height: 100%; display: inline-block;} +.webgl-content .progress .full {background: url('progressFull.Light.png') no-repeat left / cover; float: left; width: 0%; height: 100%; display: inline-block;} + +.webgl-content .logo.Dark {background-image: url('progressLogo.Dark.png');} +.webgl-content .progress.Dark .empty {background-image: url('progressEmpty.Dark.png');} +.webgl-content .progress.Dark .full {background-image: url('progressFull.Dark.png');} + +.webgl-content .footer {margin-top: 5px; height: 38px; line-height: 38px; font-family: Helvetica, Verdana, Arial, sans-serif; font-size: 18px;} +.webgl-content .footer .webgl-logo, .title, .fullscreen {height: 100%; display: inline-block; background: transparent center no-repeat;} +.webgl-content .footer .webgl-logo {background-image: url('webgl-logo.png'); width: 204px; float: left;} +.webgl-content .footer .title {margin-right: 10px; float: right;} +.webgl-content .footer .fullscreen {background-image: url('fullscreen.png'); width: 38px; float: right;} \ No newline at end of file diff --git a/docs/sardines-v1.1.0/TemplateData/webgl-logo.png b/docs/sardines-v1.1.0/TemplateData/webgl-logo.png new file mode 100644 index 0000000..8af9ba6 Binary files /dev/null and b/docs/sardines-v1.1.0/TemplateData/webgl-logo.png differ diff --git a/docs/sardines-v1.1.0/index.html b/docs/sardines-v1.1.0/index.html new file mode 100644 index 0000000..3b81a71 --- /dev/null +++ b/docs/sardines-v1.1.0/index.html @@ -0,0 +1,25 @@ + + + + + + Unity WebGL Player | nordic-game-jam-2017 + + + + + + + +
+
+ +
+ + \ No newline at end of file diff --git a/server/admin.js b/server/admin.js index 6fd7822..6e7181a 100644 --- a/server/admin.js +++ b/server/admin.js @@ -1,12 +1,9 @@ import {kServerAdminPort} from './constants'; -import { - selectPlayers -} from './gameState/selectors'; const SocketIo = require('socket.io'); const express = require('express'); const http = require('http'); -export default function createAdminServer (subscribe, getState, onStartGamePressed) { +export default function createAdminServer (onWsCreated, onConnection, onStartGamePressed) { const app = express(); app.use(express.static('server/admin')); @@ -19,27 +16,12 @@ export default function createAdminServer (subscribe, getState, onStartGamePress }); io.on('connection', function (client) { - updateAdminClient(client); + onConnection(client); client.on('startGame', function () { onStartGamePressed(); }); }); - function updateAdminClient (client) { - const state = getState(); - const players = selectPlayers(state); - - const message = JSON.stringify({ - numPlayers: players.length, - numFrozenPlayers: players.filter(player => player.frozen).length - }); - - console.log('update admin clients', message); - client.emit('state change', message); - } - - subscribe(() => { - updateAdminClient(io); - }); + onWsCreated(io); } diff --git a/server/constants.js b/server/constants.js index d87a19b..89745cf 100644 --- a/server/constants.js +++ b/server/constants.js @@ -4,7 +4,8 @@ export const kServerAddr = '127.0.0.1'; export const kClientPort = 41235; export const kClientTestPort = 41236; export const kServerAdminPort = 41233; -export const kGameStateUpdateTickMs = 100; +export const kGameStateUpdateTickMs = 250; +export const kAdminUpdateTickMs = 1000; export const kSecondsBetweenFirstHideAndRoundEnd = 10; export const kSecondsBetweenRoundEndAndNextRoundStart = 5; export const kNumHidingPlaces = 10; diff --git a/server/gameState/actions.js b/server/gameState/actions.js index 4759786..0c8471f 100644 --- a/server/gameState/actions.js +++ b/server/gameState/actions.js @@ -3,6 +3,9 @@ export const WS_MESSAGE = 'WS_MESSAGE'; export const WS_DISCONNECT = 'WS_DISCONNECT'; export const UDP_CREATE = 'UDP_CREATE'; export const UDP_MESSAGE = 'UDP_MESSAGE'; + +export const ADMIN_WS_CREATED = 'ADMIN_WS_CREATED'; +export const ADMIN_CONNECTION = 'ADMIN_CONNECTION'; export const ADMIN_START_GAME = 'ADMIN_START_GAME'; export const ADD_PLAYER = 'ADD_PLAYER'; diff --git a/server/gameState/calls.js b/server/gameState/calls.js index 750b095..a69ee1d 100644 --- a/server/gameState/calls.js +++ b/server/gameState/calls.js @@ -14,6 +14,10 @@ export function wsSend (client, message) { client.send(message); } +export function wsEmit (client, message) { + client.send(message); +} + export function delayMs (ms) { return new Promise((resolve) => { setTimeout(resolve, ms); diff --git a/server/gameState/reducers.js b/server/gameState/reducers.js index cd151cf..6ed5941 100644 --- a/server/gameState/reducers.js +++ b/server/gameState/reducers.js @@ -9,7 +9,8 @@ import { FIRST_PLAYER_HIDDEN, LAST_PLAYER_HIDDEN, START_GAME, - RESET_PLAYER + RESET_PLAYER, + ADMIN_WS_CREATED } from './actions'; function udpServerReducer (state = null, action = {}) { @@ -130,11 +131,21 @@ function allPlayersHiddenReducer (state = false, action = {}) { } } +function adminIoReducer (state = null, action = {}) { + switch (action.type) { + case ADMIN_WS_CREATED: + return action.io; + default: + return state; + } +} + export default combineReducers({ players: playerReducer, udpServer: udpServerReducer, gameId: gameIdReducer, hidingPlace: hidingPlaceReducer, anyPlayersHidden: anyPlayersHiddenReducer, - allPlayersHidden: allPlayersHiddenReducer + allPlayersHidden: allPlayersHiddenReducer, + adminIo: adminIoReducer }); diff --git a/server/gameState/sagas.js b/server/gameState/sagas.js index 713342c..779a7b2 100644 --- a/server/gameState/sagas.js +++ b/server/gameState/sagas.js @@ -7,17 +7,20 @@ import { selectGameId, selectHidingPlace, selectAnyPlayersHidden, - selectAllPlayersHidden + selectAllPlayersHidden, + selectAdminIo } from './selectors'; import { udpSend, wsSend, + wsEmit, delaySeconds, getRandomInt, getRandomStartingPosition } from './calls'; import { kGameStateUpdateTickMs, + kAdminUpdateTickMs, kSecondsBetweenFirstHideAndRoundEnd, kSecondsBetweenRoundEndAndNextRoundStart, kNumHidingPlaces @@ -50,21 +53,26 @@ function * wsConnection ({ client }) { player }); + const helloMessage = JSON.stringify({ + type: 'ServerToClientHelloMessage', + id: player.id, + gameId, + playerPosition: player.playerPosition, + playerDirection: player.playerDirection, + playerVelocity: player.playerVelocity, + frozen: player.frozen, + hidingPlace + }); + console.log('sending hello message to client ' + player.id); yield call( wsSend, client, - JSON.stringify({ - type: 'ServerToClientHelloMessage', - id: player.id, - gameId, - playerPosition: player.playerPosition, - playerDirection: player.playerDirection, - playerVelocity: player.playerVelocity, - frozen: player.frozen, - hidingPlace - }) + helloMessage ); + + console.log('sending start message to client ' + player.id); + yield * sendStartGameMessage(player, gameId, hidingPlace, playerPosition); } function * wsDisconnect ({client}) { @@ -125,8 +133,15 @@ function * playerStateUpdate () { }); for (const player of players) { - if (player.id >= 0 && player.udpAddr && player.udpPort) { - yield call(udpSend, udpServer, player.udpAddr, player.udpPort, message); + if (player.id >= 0) { + if (player.udpAddr && player.udpPort) { + yield call(udpSend, udpServer, player.udpAddr, player.udpPort, message); + } else if (player.ws) { + // TODO consider rate limiting this + yield call(wsSend, player.ws, message); + } else { + console.log('no way to send state update'); + } } } @@ -164,6 +179,23 @@ function * timeoutGameEnd (action) { } } +function * sendStartGameMessage (player, gameId, hidingPlace, playerPosition) { + const message = JSON.stringify({ + type: 'ServerToClientStartMessage', + gameId, + hidingPlace, + playerPosition + }); + + if (player.ws) { + yield call( + wsSend, + player.ws, + message + ); + } +} + function * startGame () { const players = yield select(selectPlayers); const oldGameId = yield select(selectGameId); @@ -186,23 +218,30 @@ function * startGame () { id: player.id }); - const message = JSON.stringify({ - type: 'ServerToClientStartMessage', - gameId, - hidingPlace, - playerPosition - }); - - if (player.ws) { - yield call( - wsSend, - player.ws, - message - ); - } + yield * sendStartGameMessage(player, gameId, hidingPlace, playerPosition); } } +function * updateAdminClients (client) { + const players = yield select(selectPlayers); + + const message = JSON.stringify({ + numPlayers: players.length, + numFrozenPlayers: players.filter(player => player.frozen).length + }); + + yield call(wsEmit, client, message); +} + +function * adminConnected ({client}) { + yield * updateAdminClients(client); +} + +function * adminClientUpdate () { + const adminIo = yield select(selectAdminIo); + yield * updateAdminClients(adminIo); +} + function * adminStartGame () { yield put({type: actions.REQUEST_START_GAME}); } @@ -215,5 +254,7 @@ export default function * saga () { yield takeEvery(actions.ADMIN_START_GAME, adminStartGame); yield takeEvery(actions.REQUEST_START_GAME, startGame); yield takeLatest([actions.START_GAME, actions.FIRST_PLAYER_HIDDEN], timeoutGameEnd); - yield throttle(kGameStateUpdateTickMs, [actions.ADD_PLAYER, actions.PLAYER_STATE_UPDATE], playerStateUpdate); + yield throttle(kGameStateUpdateTickMs, [actions.ADD_PLAYER, actions.REMOVE_PLAYER, actions.PLAYER_STATE_UPDATE], playerStateUpdate); + yield throttle(kAdminUpdateTickMs, [actions.ADD_PLAYER, actions.REMOVE_PLAYER, actions.PLAYER_STATE_UPDATE], adminClientUpdate); + yield takeEvery(actions.ADMIN_CONNECTION, adminConnected); } diff --git a/server/gameState/selectors.js b/server/gameState/selectors.js index 11305ae..9e10e33 100644 --- a/server/gameState/selectors.js +++ b/server/gameState/selectors.js @@ -22,3 +22,7 @@ export function selectAnyPlayersHidden (state) { export function selectAllPlayersHidden (state) { return state.allPlayersHidden; } + +export function selectAdminIo (state) { + return state.adminIo; +} diff --git a/server/server.js b/server/server.js index ff4e8d1..74ec879 100644 --- a/server/server.js +++ b/server/server.js @@ -53,8 +53,21 @@ function onUdpError (error) { console.error(error); } +function onAdminWsCreated(io) { + dispatch({ + type: actions.ADMIN_WS_CREATED, + io + }); +} + +function onAdminWsConnected(client) { + dispatch({ + type: actions.ADMIN_CONNECTION, + client + }); +} + function onAdminStartGamePressed () { - console.log('admin start game'); dispatch({ type: actions.ADMIN_START_GAME }); @@ -62,5 +75,5 @@ function onAdminStartGamePressed () { createTcpServer(onWsConnection, onWsMessage, onWsError, onWsDisconnect); createUdpServer(onUdpCreate, onUdpMessage, onUdpError); -createAdminServer(store.subscribe, store.getState, onAdminStartGamePressed); +createAdminServer(onAdminWsCreated, onAdminWsConnected, onAdminStartGamePressed); console.log('Created server'); diff --git a/server/tcp.js b/server/tcp.js index 4094819..af92a61 100644 --- a/server/tcp.js +++ b/server/tcp.js @@ -1,20 +1,25 @@ import { Server } from 'ws'; - import { kServerPort } from './constants'; +const express = require('express'); +const http = require('http'); let playerIdCounter = 0; export default function createWsServer (onNewConnection, onMessage, onError, onDisconnect) { + const app = express(); + app.use(express.static('docs')); + + const httpServer = http.createServer(app); + const server = new Server({ - perMessageDeflate: false, - port: kServerPort + server: httpServer }); server.on('connection', (client) => { client.playerId = playerIdCounter++; onNewConnection(client); client.on('message', (message) => { - onMessage(client, message); + onMessage(client, JSON.parse(message)); }); client.on('error', (err) => { onError(client, err); @@ -24,7 +29,9 @@ export default function createWsServer (onNewConnection, onMessage, onError, onD onDisconnect(client); }); }); - server.on('listening', function () { - console.log(`ws server listening on port ${kServerPort} ...`); + + const port = process.env.PORT || kServerPort; + httpServer.listen(port, function () { + console.log(`ws server listening on port ${port} ...`); }); }