diff --git a/package-lock.json b/package-lock.json index 0bb5932..aec7dae 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2563,6 +2563,11 @@ "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", "dev": true }, + "after": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.1.tgz", + "integrity": "sha1-q11PuIP1loFtNRX495HAr0ht1ic=" + }, "ajv": { "version": "6.12.2", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz", @@ -2819,6 +2824,11 @@ "es-abstract": "^1.17.0-next.1" } }, + "arraybuffer.slice": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz", + "integrity": "sha1-8zshWfBTKj8xB6JywMz70a0peco=" + }, "arrify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", @@ -2936,6 +2946,11 @@ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", "dev": true }, + "aws-sign": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/aws-sign/-/aws-sign-0.2.0.tgz", + "integrity": "sha1-xVAThWyBlOyFSgy+yQqrWgTOOsU=" + }, "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", @@ -3128,6 +3143,14 @@ "lodash.clone": "^4.5.0" } }, + "backoff": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/backoff/-/backoff-2.5.0.tgz", + "integrity": "sha1-9hbtqdPktmuMp/ynn2lXIsX44m8=", + "requires": { + "precond": "0.2" + } + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -3200,6 +3223,11 @@ } } }, + "base64-arraybuffer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.2.tgz", + "integrity": "sha1-R030qfLaJOBd8xWMOx2zw81GoVQ=" + }, "base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -3221,6 +3249,14 @@ "tweetnacl": "^0.14.3" } }, + "better-assert": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", + "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", + "requires": { + "callsite": "1.0.0" + } + }, "big.js": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", @@ -3242,6 +3278,11 @@ "file-uri-to-path": "1.0.0" } }, + "blob": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.2.tgz", + "integrity": "sha1-uJVivWmUr5W6HoEhVVNjM6ojzyQ=" + }, "bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", @@ -3259,6 +3300,14 @@ "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", "dev": true }, + "boom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/boom/-/boom-0.3.8.tgz", + "integrity": "sha1-yM2wQUNZEnQWKMBE7Mcy0dF8Ceo=", + "requires": { + "hoek": "0.7.x" + } + }, "brace-expansion": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", @@ -3548,6 +3597,11 @@ "caller-callsite": "^2.0.0" } }, + "callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=" + }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -3587,6 +3641,16 @@ "rsvp": "^4.8.4" } }, + "card": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/card/-/card-2.5.0.tgz", + "integrity": "sha512-vShS/L9APZtmlo/GrDQApHdpkM8EBbpfCLequdN6epuE2q2Il5w81+j+6U6sh3BTxYD53r7YyE6Vl8zGtEwN5g==", + "requires": { + "node.extend": "~1.1.3", + "payment": "^2.4.0", + "qj": "^2.0.0" + } + }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", @@ -3772,6 +3836,28 @@ "integrity": "sha512-1QL4544moEsDVH9T/l6Cemov/37iv1RtoKf7NJ04A60+4MREXNfx/QvavbH6QoGdsD4N4Mwy49cmaINR/o2mdg==", "dev": true }, + "client": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client/-/client-0.0.1.tgz", + "integrity": "sha1-ZTAeRW3G5fIIphGIY2I0ckK3wrg=", + "requires": { + "backoff": "^2.4.0", + "cookie": "^0.1.2", + "getenv": "~0.3.0", + "q": "~0.9.7", + "restler": "~2.0.1", + "socket.io-client": "~1.0.6", + "underscore": "^1.6.0", + "winston": "^0.7.3" + }, + "dependencies": { + "q": { + "version": "0.9.7", + "resolved": "https://registry.npmjs.org/q/-/q-0.9.7.tgz", + "integrity": "sha1-TeLmyzspCIyeTLwDv51C+5bOL3U=" + } + } + }, "cliui": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", @@ -3992,12 +4078,22 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true }, + "component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=" + }, "component-emitter": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", "dev": true }, + "component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=" + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -4042,6 +4138,16 @@ "safe-buffer": "~5.1.1" } }, + "cookie": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.1.5.tgz", + "integrity": "sha1-armUiksa4hlSzSWIUwpHItQETXw=" + }, + "cookie-jar": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/cookie-jar/-/cookie-jar-0.2.0.tgz", + "integrity": "sha1-ZOzAasl423leS1KQy+SLo3gUAPo=" + }, "copy-descriptor": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", @@ -4184,6 +4290,14 @@ } } }, + "cryptiles": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-0.1.3.tgz", + "integrity": "sha1-GlVnNPBtJLo0hirpy55wmjr7/xw=", + "requires": { + "boom": "0.3.x" + } + }, "crypto-browserify": { "version": "3.12.0", "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", @@ -4579,6 +4693,11 @@ } } }, + "cycle": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", + "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=" + }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", @@ -4979,6 +5098,13 @@ } } }, + "emitter": { + "version": "http://github.com/component/emitter/archive/1.0.1.tar.gz", + "integrity": "sha512-k3Da+QreMb9waaGCHNAHox5QqxnZEYlQmvIVYwQibrI6OpIRyIIyFGgDV5dXRLr1AJ32JLqEh0VxQEq20dFskw==", + "requires": { + "indexof": "0.0.1" + } + }, "emitter-mixin": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/emitter-mixin/-/emitter-mixin-0.0.3.tgz", @@ -5017,6 +5143,64 @@ "once": "^1.4.0" } }, + "engine.io-client": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-1.3.1.tgz", + "integrity": "sha1-HFpl1cWvbQS0TCLD282Vw57RyYk=", + "requires": { + "component-emitter": "1.1.2", + "component-inherit": "0.0.3", + "debug": "0.7.4", + "engine.io-parser": "1.0.6", + "has-cors": "1.0.3", + "indexof": "0.0.1", + "parsejson": "0.0.1", + "parseqs": "0.0.2", + "parseuri": "0.0.2", + "ws": "0.4.31", + "xmlhttprequest": "https://github.com/LearnBoost/node-XMLHttpRequest/archive/0f36d0b5ebc03d85f860d42a64ae9791e1daa433.tar.gz" + }, + "dependencies": { + "commander": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz", + "integrity": "sha1-+mihT2qUXVTbvlDYzbMyDp47GgY=" + }, + "component-emitter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.1.2.tgz", + "integrity": "sha1-KWWU8nU9qmOZbSrwjRWpURbJrsM=" + }, + "debug": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz", + "integrity": "sha1-BuHqgILCyxTjmAbiLi9vdX+Srzk=" + }, + "ws": { + "version": "0.4.31", + "resolved": "https://registry.npmjs.org/ws/-/ws-0.4.31.tgz", + "integrity": "sha1-WkhJ56nM0e1aga60hHyf7fMSKSc=", + "requires": { + "commander": "~0.6.1", + "nan": "~0.3.0", + "options": ">=0.0.5", + "tinycolor": "0.x" + } + } + } + }, + "engine.io-parser": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-1.0.6.tgz", + "integrity": "sha1-04gTFDpBHLO5FBMqsFv5nm96JI4=", + "requires": { + "after": "0.8.1", + "arraybuffer.slice": "0.0.6", + "base64-arraybuffer": "0.1.2", + "blob": "0.0.2", + "utf8": "2.0.0" + } + }, "enhanced-resolve": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.3.0.tgz", @@ -5759,6 +5943,11 @@ "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", "dev": true }, + "eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=" + }, "falafel": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/falafel/-/falafel-2.2.4.tgz", @@ -6088,8 +6277,7 @@ "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "functional-red-black-tree": { "version": "1.0.1", @@ -6152,6 +6340,11 @@ "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", "dev": true }, + "getenv": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/getenv/-/getenv-0.3.0.tgz", + "integrity": "sha1-se8/l+ncVUZ4KFmyIrVlmgx47qo=" + }, "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", @@ -6201,6 +6394,10 @@ "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=", "dev": true }, + "global": { + "version": "https://github.com/component/global/archive/v2.0.1.tar.gz", + "integrity": "sha512-O91OcV/NbdmQJPHaRu2ekSP7bqFRLWgqSwaJvqHPZHUwmHBagQYTOra29+LnzzG3lZkXH1ANzHzfCxtAPM9HMA==" + }, "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -6282,7 +6479,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, "requires": { "function-bind": "^1.1.1" } @@ -6304,6 +6500,29 @@ } } }, + "has-binary-data": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/has-binary-data/-/has-binary-data-0.1.1.tgz", + "integrity": "sha1-4QdJ+4eCilLflvQIZYfrSgOWZDk=", + "requires": { + "isarray": "0.0.1" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + } + } + }, + "has-cors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.0.3.tgz", + "integrity": "sha1-UCrLmzEE2sM90mMOry+IiwuvTLM=", + "requires": { + "global": "https://github.com/component/global/archive/v2.0.1.tar.gz" + } + }, "has-flag": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", @@ -6422,6 +6641,17 @@ "minimalistic-assert": "^1.0.1" } }, + "hawk": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-0.10.2.tgz", + "integrity": "sha1-mzYd7pWpMWQObVBOBWCaj8OsRdI=", + "requires": { + "boom": "0.3.x", + "cryptiles": "0.1.x", + "hoek": "0.7.x", + "sntp": "0.1.x" + } + }, "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -6445,6 +6675,11 @@ "minimalistic-crypto-utils": "^1.0.1" } }, + "hoek": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-0.7.6.tgz", + "integrity": "sha1-YPvZBFV1Qc0rh5Wr8wihs3cOFVo=" + }, "hosted-git-info": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", @@ -6712,6 +6947,11 @@ "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", "dev": true }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -6732,6 +6972,11 @@ "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", "dev": true }, + "is": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/is/-/is-3.3.0.tgz", + "integrity": "sha512-nW24QBoPcFGGHJGUwnfpI7Yc5CdqWNdsyHQszVE/z2pKHXzh7FZ5GWhJqSyaQ9wMkQnsTx+kAI8bHlCX4tKdbg==" + }, "is-absolute-url": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", @@ -8734,6 +8979,11 @@ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", "dev": true }, + "json3": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.2.6.tgz", + "integrity": "sha1-9u/JPAagTemuxTBT3yVZuxniA4s=" + }, "json5": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", @@ -9098,6 +9348,11 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, + "nan": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-0.3.2.tgz", + "integrity": "sha1-DfGTXKsVNpB17xYK0olBB6oU3C0=" + }, "nanomatch": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", @@ -9269,6 +9524,15 @@ "integrity": "sha512-V5QF9noGFl3EymEwUYzO+3NTDpGfQB4ve6Qfnzf3UNydMhjQRVPR1DZTuvWiLzaFJYw2fmDwAfnRNEVb64hSIg==", "dev": true }, + "node.extend": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/node.extend/-/node.extend-1.1.8.tgz", + "integrity": "sha512-L/dvEBwyg3UowwqOUTyDsGBU6kjBQOpOhshio9V3i3BMPv5YUb9+mWNN8MK0IbWqT0AqaTSONZf0aTuMMahWgA==", + "requires": { + "has": "^1.0.3", + "is": "^3.2.1" + } + }, "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -9336,6 +9600,11 @@ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, + "object-component": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", + "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=" + }, "object-copy": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", @@ -9549,6 +9818,11 @@ "word-wrap": "~1.2.3" } }, + "options": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz", + "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=" + }, "ora": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/ora/-/ora-2.1.0.tgz", @@ -9900,6 +10174,30 @@ "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", "dev": true }, + "parsejson": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/parsejson/-/parsejson-0.0.1.tgz", + "integrity": "sha1-mxDGwNglq1ieaFFTgm3go7oni8w=", + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseqs": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.2.tgz", + "integrity": "sha1-nf5wss3aw4i95PNbHyQPpYrb5sc=", + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseuri": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.2.tgz", + "integrity": "sha1-20GHjy1pZHGL6HCzFAlz2Ak74VY=", + "requires": { + "better-assert": "~1.0.0" + } + }, "parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -9969,6 +10267,14 @@ } } }, + "payment": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/payment/-/payment-2.4.0.tgz", + "integrity": "sha512-FjVkqu1GW0epmWRuA7853cfEdjZx61z1vKagcvfvKWeXwEuUlOKr2nkdrCjue5qJWNSzj235pidaK3GsCbY84A==", + "requires": { + "qj": "~2.0.0" + } + }, "pbkdf2": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz", @@ -10027,6 +10333,11 @@ "node-modules-regexp": "^1.0.0" } }, + "pkginfo": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.3.1.tgz", + "integrity": "sha1-Wyn2qB9wcXFC4J52W76rl7T4HiE=" + }, "pn": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", @@ -10678,6 +10989,11 @@ "integrity": "sha512-W1779iVHGfq0Fvh2PROhCe2QhB8mEErgqzo1wpIt36tCgChafP+hbXIhLDOM8ePJrZcFs0vkNEtdibEWVqChqw==", "dev": true }, + "precond": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/precond/-/precond-0.2.3.tgz", + "integrity": "sha1-qpWRvKokkj8eD0hJ0kD0fvwQdaw=" + }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", @@ -10853,6 +11169,11 @@ "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", "dev": true }, + "qj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/qj/-/qj-2.0.0.tgz", + "integrity": "sha1-BU3Tt1zgGHKNI6BgXwMN/aC9FYo=" + }, "qs": { "version": "6.9.4", "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", @@ -11381,6 +11702,11 @@ "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", "dev": true }, + "restler": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/restler/-/restler-2.0.1.tgz", + "integrity": "sha1-WT49T6xrk/r/ocXtDKl/o0IgeMg=" + }, "restore-cursor": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", @@ -11910,6 +12236,66 @@ "kind-of": "^3.2.0" } }, + "sntp": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-0.1.4.tgz", + "integrity": "sha1-XvSBuVGnspr/30r9fyaDj8ESD4Q=", + "requires": { + "hoek": "0.7.x" + } + }, + "socket.io-client": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-1.0.6.tgz", + "integrity": "sha1-yGyz5QerL5baRQC9NPz0ah6d/l4=", + "requires": { + "component-bind": "1.0.0", + "component-emitter": "1.1.2", + "debug": "0.7.4", + "engine.io-client": "1.3.1", + "has-binary-data": "0.1.1", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseuri": "0.0.2", + "socket.io-parser": "2.2.0", + "to-array": "0.1.3" + }, + "dependencies": { + "component-emitter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.1.2.tgz", + "integrity": "sha1-KWWU8nU9qmOZbSrwjRWpURbJrsM=" + }, + "debug": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz", + "integrity": "sha1-BuHqgILCyxTjmAbiLi9vdX+Srzk=" + } + } + }, + "socket.io-parser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-2.2.0.tgz", + "integrity": "sha1-JglgH1nmp/q0NqU749Mz+7/L0wo=", + "requires": { + "debug": "0.7.4", + "emitter": "http://github.com/component/emitter/archive/1.0.1.tar.gz", + "isarray": "0.0.1", + "json3": "3.2.6" + }, + "dependencies": { + "debug": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz", + "integrity": "sha1-BuHqgILCyxTjmAbiLi9vdX+Srzk=" + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + } + } + }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -12018,6 +12404,11 @@ "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", "dev": true }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" + }, "stack-utils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", @@ -12591,12 +12982,22 @@ "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==", "dev": true }, + "tinycolor": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tinycolor/-/tinycolor-0.0.1.tgz", + "integrity": "sha1-MgtaUtg6u1l42Bo+iH1K77FaYWQ=" + }, "tmpl": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=", "dev": true }, + "to-array": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.3.tgz", + "integrity": "sha1-1F2txjY0F/YPKEdP6lDs3btPSZE=" + }, "to-arraybuffer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", @@ -13129,6 +13530,11 @@ } } }, + "underscore": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz", + "integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==" + }, "unicode-canonical-property-names-ecmascript": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", @@ -13311,6 +13717,11 @@ "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", "dev": true }, + "utf8": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/utf8/-/utf8-2.0.0.tgz", + "integrity": "sha1-ec5Z7O2HSAnKuacfxxAsfUXUEY0=" + }, "util": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", @@ -13491,6 +13902,108 @@ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, + "winston": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/winston/-/winston-0.7.3.tgz", + "integrity": "sha1-euMTunP83C7LSqL5zURugphncmY=", + "requires": { + "async": "0.2.x", + "colors": "0.6.x", + "cycle": "1.0.x", + "eyes": "0.1.x", + "pkginfo": "0.3.x", + "request": "2.16.x", + "stack-trace": "0.0.x" + }, + "dependencies": { + "async": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", + "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=" + }, + "colors": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz", + "integrity": "sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w=" + }, + "combined-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz", + "integrity": "sha1-ATfmV7qlp1QcV6w3rF/AfXO03B8=", + "requires": { + "delayed-stream": "0.0.5" + } + }, + "delayed-stream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz", + "integrity": "sha1-1LH0OpPoKW3+AmlPRoC8N6MTxz8=" + }, + "forever-agent": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.2.0.tgz", + "integrity": "sha1-4cJcetROCcOPIzh2x2/MJP+EOx8=" + }, + "form-data": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-0.0.10.tgz", + "integrity": "sha1-2zRaU3jYau6x7V1VO4aawZLS9e0=", + "requires": { + "async": "~0.2.7", + "combined-stream": "~0.0.4", + "mime": "~1.2.2" + } + }, + "json-stringify-safe": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-3.0.0.tgz", + "integrity": "sha1-nbew5TDH8onF6MhDKvGRwv91pbM=" + }, + "mime": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz", + "integrity": "sha1-WCA+7Ybjpe8XrtK32evUfwpg3RA=" + }, + "node-uuid": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", + "integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc=" + }, + "oauth-sign": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.2.0.tgz", + "integrity": "sha1-oOahcV2u0GLzIrYit/5a/RA1tuI=" + }, + "qs": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/qs/-/qs-0.5.6.tgz", + "integrity": "sha1-MbGtBYVnZRxSaSFQa5qHk5EaA4Q=" + }, + "request": { + "version": "2.16.6", + "resolved": "https://registry.npmjs.org/request/-/request-2.16.6.tgz", + "integrity": "sha1-hy/kRa5y3iZrN4edatfclI+gHK0=", + "requires": { + "aws-sign": "~0.2.0", + "cookie-jar": "~0.2.0", + "forever-agent": "~0.2.0", + "form-data": "~0.0.3", + "hawk": "~0.10.2", + "json-stringify-safe": "~3.0.0", + "mime": "~1.2.7", + "node-uuid": "~1.4.0", + "oauth-sign": "~0.2.0", + "qs": "~0.5.4", + "tunnel-agent": "~0.2.0" + } + }, + "tunnel-agent": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.2.0.tgz", + "integrity": "sha1-aFPCr7GyEJ5FYp5JK9419Fnqaeg=" + } + } + }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -13541,6 +14054,10 @@ "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", "dev": true }, + "xmlhttprequest": { + "version": "https://github.com/LearnBoost/node-XMLHttpRequest/archive/0f36d0b5ebc03d85f860d42a64ae9791e1daa433.tar.gz", + "integrity": "sha512-TVSZwoeUQ7OKhb8jnQdSxGFz+lm4MGWmhG0deeYg85VQT74x5LcSrKeXHE0ZIzEycgqQ5mF8r8e1AykA7TpNAQ==" + }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", diff --git a/package.json b/package.json index d74a468..d2cdec4 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,9 @@ "main": "index.js", "scripts": { "test": "jest --verbose", - "start": "tsc --noEmit && cp -ru src/assets dist && parcel src/index.html" + "start": "npm run build && parcel src/index.html", + "build": "tsc --noEmit && cp -ru src/assets dist", + "dev": "npm run build && parcel —no-minify src/index.html" }, "author": "", "license": "ISC", @@ -40,7 +42,9 @@ "@akolos/event-emitter": "^2.0.4", "@akolos/ts-tween": "^1.0.6", "bluebird": "^3.7.2", + "card": "^2.5.0", "clean-webpack-plugin": "^3.0.0", + "client": "0.0.1", "eslint-config-prettier": "^6.11.0", "eslint-plugin-prettier": "^3.1.4", "nouislider": "^14.6.3", diff --git a/src/assets/images/card/backside.png b/src/assets/images/card/backside.png index 78d391b..06cabee 100644 Binary files a/src/assets/images/card/backside.png and b/src/assets/images/card/backside.png differ diff --git a/src/client/client.ts b/src/client/client.ts index 656265a..bc292ff 100644 --- a/src/client/client.ts +++ b/src/client/client.ts @@ -2,24 +2,41 @@ import { Game } from '../game'; import { SoundId } from './audio/sound-id'; import { Renderer } from './renderer/renderer'; import { SuitAssignments } from './renderer/suit-assignments'; -import { loadResources } from './resources'; import { Ui } from './ui'; import { AudioService as audio } from './audio/audio-service'; import { CardLike } from 'card/card-like'; +import { RendererLoader } from './renderer/renderer-loader'; export class Client { private acceptGameInputs = false; private readonly ui = Ui.init(); private lastCardSoundTime = new Date().getTime(); + private rendererPromise: Promise; - private constructor(private readonly renderer: Renderer, private game: Game, private readonly suitAssignments: SuitAssignments) { - this.init(); + private constructor(private game: Game, private readonly suitAssignments: SuitAssignments) { + this.rendererPromise = RendererLoader.load(this.game, suitAssignments); + this.rendererPromise.then((renderer) => { + this.setUpRenderer(renderer); + this.enableUi(renderer); + }); + + RendererLoader.on('progressed', (progress, status) => { + this.ui.updateLoadingStatus(progress, status); + }) + .on('completed', () => { + this.ui.enablePlaybutton(); + }); + } + + public async getDomElement(): Promise { + const renderer = await this.rendererPromise; + return renderer.domElement; } - private init() { + private setUpRenderer(renderer: Renderer) { const suitAssignments = this.suitAssignments; - this.renderer + renderer .on('dealingCards', () => this.acceptGameInputs = false) .on('cardsDelt', () => this.acceptGameInputs = true) .on('cardEntered', card => { @@ -55,6 +72,14 @@ export class Client { } }); + renderer.start(); + + function isCardInP1Hand(card: CardLike, game: Game) { + return card.suit === suitAssignments.player1 && game.cards.inHand.p1.includes(card.rank); + } + } + + private enableUi(renderer: Renderer) { this.ui.on('playButtonClicked', () => { this.acceptGameInputs = true; if (!audio.isMusicPlaying) audio.playMusic(); @@ -64,18 +89,13 @@ export class Client { }) .on('resetButtonClicked', () => { this.game = new Game(); - this.renderer.setGameToRender(this.game); + renderer.setGameToRender(this.game); this.ui.hideResultsToast(); this.ui.updateScore(0, 0); }) .on('volumeChanged', (value: number) => { audio.soundVolume = audio.musicVolume = value; }); - this.ui.enablePlaybutton(); - - function isCardInP1Hand(card: CardLike, game: Game) { - return card.suit === suitAssignments.player1 && game.cards.inHand.p1.includes(card.rank); - } } private playCardSound(soundId: SoundId.CardFlip | SoundId.CardHitTable) { @@ -90,10 +110,9 @@ export class Client { public static async start(suitAssignments: SuitAssignments): Promise { const game = new Game(); - const resources = await loadResources(); - const renderer = new Renderer(resources, game, suitAssignments); - document.body.appendChild(renderer.domElement); - renderer.start(); - return new Client(renderer, game, suitAssignments); + const client = new Client(game, suitAssignments); + const domElement = await client.getDomElement(); + document.body.appendChild(domElement); + return client; } } diff --git a/src/client/renderer/card-object3d/card-object3d-factory.ts b/src/client/renderer/card-object3d/card-object3d-factory.ts index 9afafb3..a771d67 100644 --- a/src/client/renderer/card-object3d/card-object3d-factory.ts +++ b/src/client/renderer/card-object3d/card-object3d-factory.ts @@ -1,5 +1,5 @@ import * as THREE from 'three'; -import { CardTextureResources } from '../../../client/resources'; +import { CardTextureResources } from '../../resources/resources'; import { Card, CardAbbreviation } from '../../../card/card'; import { CardObject3d } from './card-object3d'; diff --git a/src/client/renderer/renderer-loader.ts b/src/client/renderer/renderer-loader.ts new file mode 100644 index 0000000..a93d14f --- /dev/null +++ b/src/client/renderer/renderer-loader.ts @@ -0,0 +1,38 @@ +import { EventEmitter } from '@akolos/event-emitter'; +import { ResourceLoader } from '../../client/resources/resource-loader'; +import { Game } from '../../game'; +import { Renderer } from './renderer'; +import { SuitAssignments } from './suit-assignments'; + +export interface RendererLoaderEvents { + progressed: [progress: number, status: string]; + completed: []; +} + + +export class RendererLoader { + + private static instance: Renderer; + + private static ee = new EventEmitter(); + private static emit = RendererLoader.ee.makeDelegate('emit', RendererLoader); + public static readonly on = RendererLoader.ee.makeDelegate('on', RendererLoader.ee.asProtected()); + public static readonly off = RendererLoader.ee.makeDelegate('off', RendererLoader.ee.asProtected()); + + public static async load(game: Game, suitAssignments: SuitAssignments): Promise { + if (this.instance) return this.instance; + + ResourceLoader.on('loadingFile', (url, itemsLoaded, totalItems) => { + const progress = itemsLoaded / totalItems; + RendererLoader.emit('progressed', progress, `Loading file: ${url}`); + }); + ResourceLoader.on('completed', () => { + RendererLoader.emit('progressed', 1, 'Done!'); + RendererLoader.emit('completed'); + }); + + const resources = await ResourceLoader.load(); + return new Renderer(resources, game, suitAssignments); + } + +} diff --git a/src/client/renderer/renderer.ts b/src/client/renderer/renderer.ts index 973b0d2..0c80939 100644 --- a/src/client/renderer/renderer.ts +++ b/src/client/renderer/renderer.ts @@ -6,7 +6,7 @@ import { Suit } from '../../card/suit'; import { CardAnimator } from '../../client/renderer/animation/card-animator'; import { Game, MatchupWinner } from '../../game'; import { Matchup } from '../../game/matchup'; -import { CardTextureResources, Resources } from '../resources'; +import { CardTextureResources, Resources } from '../resources/resources'; import { CardObject3d, MatchupOutcomeMarker } from './card-object3d/card-object3d'; import { createCardObject3dFactory } from './card-object3d/card-object3d-factory'; import { createScene } from './create-scene'; @@ -27,6 +27,7 @@ export interface RendererEvents { const CAMERA_FOV = 70; export class Renderer extends InheritableEventEmitter { + private readonly camera: THREE.PerspectiveCamera; private readonly scene: THREE.Scene; private readonly webGlRenderer: THREE.WebGLRenderer; diff --git a/src/client/resources.ts b/src/client/resources.ts deleted file mode 100644 index f8c65c2..0000000 --- a/src/client/resources.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { Object3D, Texture, TextureLoader, Mesh, MeshPhongMaterial, RepeatWrapping } from 'three'; -import { Suit } from '../card/suit'; -import { objectPromiseAll } from '../util/object-promise-all'; -import { Rank } from '../card'; -import { Card, CardAbbreviation } from '../card/card'; -import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader' - -const IMAGE_DIR_PATH = 'images/'; -const CARD_DIR_PATH = IMAGE_DIR_PATH + 'card/'; - -export interface CardFaceTextureData { - rank: Rank; - suit: Suit; - texture: Texture; -} - -export interface CardTextureResources { - backSideAlpha: Texture; - backSide: Texture; - frontSideAlpha: Texture; - getFront(card: Card): THREE.Texture; -} - -export interface CardTextures { - backSideAlpha: Texture; - backSide: Texture; - frontSideAlpha: Texture; - frontSide: Texture; -} - -export interface Resources { - table: Object3D; - cards: CardTextureResources; - grassTexture: THREE.Texture; -} - -export async function loadResources(): Promise { - const resourcesPromiseObj = { - table: loadTable(), - grassTexture: loadTexture(IMAGE_DIR_PATH + 'grass.png'), - cards: { - backSideAlpha: loadTexture(CARD_DIR_PATH + 'backside_alpha.png'), - backSide: loadTexture(CARD_DIR_PATH + 'backside.png'), - frontSideAlpha: loadTexture(CARD_DIR_PATH + 'frontside_alpha.png'), - getFront: loadCardFrontTextures(), - }, - }; - - return objectPromiseAll(resourcesPromiseObj); -} - -function loadTable(): Promise { - const loadModel: Promise = new Promise((resolve) => { - new OBJLoader().load('models/lowtable.obj', (obj) => { - resolve(obj); - }); - }); - - return new Promise((resolve) => { - Promise.all([loadModel, loadTexture(IMAGE_DIR_PATH + 'wood.png')]).then((value) => { - const object = value[0]; - const texture = value[1]; - texture.offset.set(0, 0); - texture.repeat.set(24, 24); - texture.wrapS = texture.wrapT = RepeatWrapping; - applyTexture(object.children[0], texture); - object.receiveShadow = true; - resolve(object); - }); - }); - - function applyTexture(obj: THREE.Object3D, texture: Texture) { - obj.receiveShadow = true; - if (obj instanceof Mesh) { - (obj.material as MeshPhongMaterial).map = texture; - } - if (obj instanceof Object3D) { - obj.children.forEach((c) => applyTexture(c, texture)); - } - } -} - -const loadCardFrontTextures = async () => { - const cardFilepaths = Card.makeDeckOf().map(c => ({ cardAbbreviation: c.abbreviation, imagePath: getImagePathForCard(c) })); - const texturePromises = cardFilepaths.map((cfp) => loadTexture(cfp.imagePath).then(texture => [cfp.cardAbbreviation, texture] as [CardAbbreviation, THREE.Texture])); - const textures: Array<[CardAbbreviation, THREE.Texture]> = await Promise.all(texturePromises); - const abbrevToTextureMap = new Map(textures); - - return (card: Card) => abbrevToTextureMap.get(card.abbreviation)!; -}; - -function getImagePathForCard(card: Card): string { - return `${CARD_DIR_PATH}${card.rank.name}_of_${card.suit.name}.png`; -} - -const textureLoader = new TextureLoader(); -function loadTexture(path: string): Promise { - return new Promise((resolve) => { - textureLoader.load(path, (texture) => resolve(texture)); - }); -} diff --git a/src/client/resources/resource-loader.ts b/src/client/resources/resource-loader.ts new file mode 100644 index 0000000..c183fc4 --- /dev/null +++ b/src/client/resources/resource-loader.ts @@ -0,0 +1,105 @@ +import { EventEmitter } from '@akolos/event-emitter'; +import * as THREE from 'three'; +import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader'; +import { Card, CardAbbreviation } from '../../card/card'; +import { objectPromiseAll } from '../../util/object-promise-all'; +import { Resources } from './resources'; + +export interface ResourceLoaderEvents { + starting: []; + completed: []; + loadingFile: [url: string, itemsLoaded: number, totalItems: number]; +} + +const IMAGE_DIR_PATH = 'images/'; +const CARD_DIR_PATH = IMAGE_DIR_PATH + 'card/'; +const loadingManager = new THREE.LoadingManager(); +const textureLoader = new THREE.TextureLoader(loadingManager); + +export class ResourceLoader { + private static readonly ee = new EventEmitter(); + public static readonly on = ResourceLoader.ee.makeDelegate('on', ResourceLoader.ee.asProtected()); + public static readonly off = ResourceLoader.ee.makeDelegate('off', ResourceLoader.ee.asProtected()); + + private static resources?: Promise; + + public static load(): Promise { + if (this.resources) return this.resources; + + loadingManager.onProgress = (url, loaded, total) => { + console.log('starting a load!', url, loaded, total); + this.ee.emit('loadingFile', url, loaded, total); + }; + loadingManager.onLoad = () => { + console.log('loaded!'); + this.ee.emit('completed'); + }; + + const resourcesPromiseObj = { + table: loadTable(), + grassTexture: loadTexture(IMAGE_DIR_PATH + 'grass.png'), + cards: { + backSideAlpha: loadTexture(CARD_DIR_PATH + 'backside_alpha.png'), + backSide: loadTexture(CARD_DIR_PATH + 'backside.png'), + frontSideAlpha: loadTexture(CARD_DIR_PATH + 'frontside_alpha.png'), + getFront: loadCardFrontTextures(), + }, + }; + + ResourceLoader.ee.emit('starting'); + this.resources = objectPromiseAll(resourcesPromiseObj); + return this.resources; + } + + private constructor() {} +} + +function loadTable(): Promise { + const loadModel: Promise = new Promise((resolve) => { + new OBJLoader(loadingManager).load('models/lowtable.obj', (obj) => { + resolve(obj); + }); + }); + + return new Promise((resolve) => { + Promise.all([loadModel, loadTexture(IMAGE_DIR_PATH + 'wood.png')]).then((value) => { + const object = value[0]; + const texture = value[1]; + texture.offset.set(0, 0); + texture.repeat.set(24, 24); + texture.wrapS = texture.wrapT = THREE.RepeatWrapping; + applyTexture(object.children[0], texture); + object.receiveShadow = true; + resolve(object); + }); + }); + + function applyTexture(obj: THREE.Object3D, texture: THREE.Texture) { + obj.receiveShadow = true; + if (obj instanceof THREE.Mesh) { + (obj.material as THREE.MeshPhongMaterial).map = texture; + } + if (obj instanceof THREE.Object3D) { + obj.children.forEach((c) => applyTexture(c, texture)); + } + } +} + +const loadCardFrontTextures = async () => { + const cardFilepaths = Card.makeDeckOf().map(c => ({ cardAbbreviation: c.abbreviation, imagePath: getImagePathForCard(c) })); + const texturePromises = cardFilepaths.map((cfp) => loadTexture(cfp.imagePath).then(texture => [cfp.cardAbbreviation, texture] as [CardAbbreviation, THREE.Texture])); + const textures: Array<[CardAbbreviation, THREE.Texture]> = await Promise.all(texturePromises); + const abbrevToTextureMap = new Map(textures); + + return (card: Card) => abbrevToTextureMap.get(card.abbreviation)!; +}; + +function getImagePathForCard(card: Card): string { + return `${CARD_DIR_PATH}${card.rank.name}_of_${card.suit.name}.png`; +} + +function loadTexture(path: string): Promise { + return new Promise((resolve) => { + textureLoader.load(path, (texture) => resolve(texture)); + }); +} diff --git a/src/client/resources/resources.ts b/src/client/resources/resources.ts new file mode 100644 index 0000000..78f1897 --- /dev/null +++ b/src/client/resources/resources.ts @@ -0,0 +1,30 @@ +import { Object3D, Texture } from 'three'; +import { Rank } from '../../card'; +import { Card } from '../../card/card'; +import { Suit } from '../../card/suit'; + +export interface CardFaceTextureData { + rank: Rank; + suit: Suit; + texture: Texture; +} + +export interface CardTextureResources { + backSideAlpha: Texture; + backSide: Texture; + frontSideAlpha: Texture; + getFront(card: Card): THREE.Texture; +} + +export interface CardTextures { + backSideAlpha: Texture; + backSide: Texture; + frontSideAlpha: Texture; + frontSide: Texture; +} + +export interface Resources { + table: Object3D; + cards: CardTextureResources; + grassTexture: THREE.Texture; +} diff --git a/src/client/ui.ts b/src/client/ui.ts index d960d22..b570452 100644 --- a/src/client/ui.ts +++ b/src/client/ui.ts @@ -11,7 +11,6 @@ interface UiEvents { export class Ui extends InheritableEventEmitter { private readonly rulesDialog = el('modal'); - private readonly playButton = el('clickToPlay'); private readonly resetButton = el('resetButton'); private readonly showRulesButton = el('showRules'); private readonly scoreBoard = el('score'); @@ -19,6 +18,10 @@ export class Ui extends InheritableEventEmitter { private readonly volumeSlider = el('volumeSlider'); private readonly volumeValueDisplay = el('volume'); + private readonly playButton = el('playButton'); + private readonly playButtonPrimaryText = el('playButtonPrimaryText'); + private readonly playButtonSecondaryText = el('playButtonSecondaryText'); + private isPlayButtonActive = false; private constructor() { @@ -26,6 +29,7 @@ export class Ui extends InheritableEventEmitter { this.resetButton.addEventListener('click', () => this.emit('resetButtonClicked')); this.showRulesButton.addEventListener('click', () => { + this.playButtonSecondaryText.style.display = 'none'; show(this.rulesDialog); this.emit('rulesButtonClicked'); }); @@ -60,15 +64,18 @@ export class Ui extends InheritableEventEmitter { } public enablePlaybutton() { - this.playButton.classList.add('whiteBorder'); - this.playButton.innerHTML = 'Play'; + this.playButtonPrimaryText.innerHTML = 'Click Here To Play'; + this.playButtonSecondaryText.style.display = 'none'; this.playButton.style.cursor = 'pointer'; this.isPlayButtonActive = true; } - public showRulesDialog() { - show(this.rulesDialog); - }; + public updateLoadingStatus(progress: number, status: string = '') { + const formatted = (progress * 100).toPrecision(3); + this.playButton.style.background = `linear-gradient(to right, green ${formatted}%, black, ${formatted}%, black ${100-Number(formatted)}%)`; + this.playButtonPrimaryText.innerHTML = formatted + '%'; + this.playButtonSecondaryText.innerHTML = status; + } public isRulesDialogShowing(): boolean { const opacity = this.rulesDialog.style.opacity; diff --git a/src/index.html b/src/index.html index 7712f58..2b9cff9 100644 --- a/src/index.html +++ b/src/index.html @@ -1,9 +1,9 @@ + Bastion Breach - - + -
- Player: 0   Computer: 0 -
+ -