mirror of
https://github.com/scratchfoundation/scratch-vm.git
synced 2024-12-23 06:23:37 -05:00
Merge pull request #1905 from bocoup/update-blocks
Add Vernier's GDX-FOR extension
This commit is contained in:
commit
522b5e1a8e
5 changed files with 753 additions and 60 deletions
128
package-lock.json
generated
128
package-lock.json
generated
|
@ -1088,6 +1088,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"@vernier/godirect": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@vernier/godirect/-/godirect-1.3.0.tgz",
|
||||
"integrity": "sha512-vDdl1yCiKwPm/L/ca87cjSSDoFviWPx7IvT3SQxMqplYsACjCWrcW4yIECBfKuK9ok9cTFrXCSsmnpmDDApI8A=="
|
||||
},
|
||||
"@webassemblyjs/ast": {
|
||||
"version": "1.5.13",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.5.13.tgz",
|
||||
|
@ -1537,7 +1542,7 @@
|
|||
"arr-flatten": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
|
||||
"integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
|
||||
"integrity": "sha1-NgSLv/TntH4TZkQxbJlmnqWukfE=",
|
||||
"dev": true
|
||||
},
|
||||
"arr-union": {
|
||||
|
@ -1713,7 +1718,7 @@
|
|||
},
|
||||
"aws4": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz",
|
||||
"resolved": "http://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz",
|
||||
"integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4="
|
||||
},
|
||||
"babel-code-frame": {
|
||||
|
@ -2177,7 +2182,7 @@
|
|||
},
|
||||
"bl": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "http://registry.npmjs.org/bl/-/bl-1.2.2.tgz",
|
||||
"resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz",
|
||||
"integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
@ -2231,7 +2236,7 @@
|
|||
"bn.js": {
|
||||
"version": "4.11.8",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz",
|
||||
"integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==",
|
||||
"integrity": "sha1-LN4J617jQfSEdGuwMJsyU7GxRC8=",
|
||||
"dev": true
|
||||
},
|
||||
"body-parser": {
|
||||
|
@ -2338,7 +2343,7 @@
|
|||
},
|
||||
"brfs": {
|
||||
"version": "1.6.1",
|
||||
"resolved": "http://registry.npmjs.org/brfs/-/brfs-1.6.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/brfs/-/brfs-1.6.1.tgz",
|
||||
"integrity": "sha512-OfZpABRQQf+Xsmju8XE9bDjs+uU4vLREGolP7bDgcpsI17QREyZ4Bl+2KLxxx1kCgA0fAIhKQBaBYh+PEcCqYQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
@ -2470,7 +2475,7 @@
|
|||
"buffer-indexof": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz",
|
||||
"integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==",
|
||||
"integrity": "sha1-Uvq8xqYG0aADAoAmSO9o9jnaJow=",
|
||||
"dev": true
|
||||
},
|
||||
"buffer-shims": {
|
||||
|
@ -2672,7 +2677,7 @@
|
|||
"cipher-base": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
|
||||
"integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==",
|
||||
"integrity": "sha1-h2Dk7MJy9MNjUy+SbYdKriwTl94=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"inherits": "^2.0.1",
|
||||
|
@ -2797,12 +2802,12 @@
|
|||
"color-support": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
|
||||
"integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==",
|
||||
"integrity": "sha1-k4NDeaHMmgxh+C9S8NBDIiUb1aI=",
|
||||
"dev": true
|
||||
},
|
||||
"colors": {
|
||||
"version": "0.6.2",
|
||||
"resolved": "http://registry.npmjs.org/colors/-/colors-0.6.2.tgz",
|
||||
"resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz",
|
||||
"integrity": "sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w=",
|
||||
"dev": true
|
||||
},
|
||||
|
@ -2945,7 +2950,7 @@
|
|||
"content-type": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
|
||||
"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
|
||||
"integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=",
|
||||
"dev": true
|
||||
},
|
||||
"convert-source-map": {
|
||||
|
@ -3286,7 +3291,7 @@
|
|||
"crypto-browserify": {
|
||||
"version": "3.12.0",
|
||||
"resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz",
|
||||
"integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==",
|
||||
"integrity": "sha1-OWz58xN/A+S45TLFj2mCVOAPgOw=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"browserify-cipher": "^1.0.0",
|
||||
|
@ -4380,7 +4385,7 @@
|
|||
"evp_bytestokey": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",
|
||||
"integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==",
|
||||
"integrity": "sha1-f8vbGY3HGVlDLv4ThCaE4FJaywI=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"md5.js": "^1.3.4",
|
||||
|
@ -4950,7 +4955,7 @@
|
|||
"dependencies": {
|
||||
"commander": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "http://registry.npmjs.org/commander/-/commander-2.1.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.1.0.tgz",
|
||||
"integrity": "sha1-0SG7roYNmZKj1Re6lvVliOR8Z4E=",
|
||||
"dev": true
|
||||
}
|
||||
|
@ -5315,7 +5320,7 @@
|
|||
"string-width": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
|
||||
"integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
|
||||
"integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-fullwidth-code-point": "^2.0.0",
|
||||
|
@ -5509,14 +5514,12 @@
|
|||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
|
@ -5531,20 +5534,17 @@
|
|||
"code-point-at": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"console-control-strings": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
|
@ -5661,8 +5661,7 @@
|
|||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.5",
|
||||
|
@ -5674,7 +5673,6 @@
|
|||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"number-is-nan": "^1.0.0"
|
||||
}
|
||||
|
@ -5689,7 +5687,6 @@
|
|||
"version": "3.0.4",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
|
@ -5697,14 +5694,12 @@
|
|||
"minimist": {
|
||||
"version": "0.0.8",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"minipass": {
|
||||
"version": "2.2.4",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"safe-buffer": "^5.1.1",
|
||||
"yallist": "^3.0.0"
|
||||
|
@ -5723,7 +5718,6 @@
|
|||
"version": "0.5.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"minimist": "0.0.8"
|
||||
}
|
||||
|
@ -5804,8 +5798,7 @@
|
|||
"number-is-nan": {
|
||||
"version": "1.0.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
|
@ -5817,7 +5810,6 @@
|
|||
"version": "1.4.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
|
@ -5939,7 +5931,6 @@
|
|||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"code-point-at": "^1.0.0",
|
||||
"is-fullwidth-code-point": "^1.0.0",
|
||||
|
@ -6857,12 +6848,12 @@
|
|||
"is-buffer": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
|
||||
"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
|
||||
"integrity": "sha1-76ouqdqg16suoTqXsritUf776L4=",
|
||||
"dev": true
|
||||
},
|
||||
"is-builtin-module": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "http://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
|
||||
"integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
@ -7631,7 +7622,7 @@
|
|||
},
|
||||
"magic-string": {
|
||||
"version": "0.22.5",
|
||||
"resolved": "http://registry.npmjs.org/magic-string/-/magic-string-0.22.5.tgz",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.22.5.tgz",
|
||||
"integrity": "sha512-oreip9rJZkzvA8Qzk9HFs8fZGF/u7H/gtrE8EN6RjKJ9kh2HlC+yQ2QezifqTZfGyiuAV0dRv5a+y/8gBb1m9w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
@ -7901,7 +7892,7 @@
|
|||
"miller-rabin": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz",
|
||||
"integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==",
|
||||
"integrity": "sha1-8IA1HIZbDcViqEYpZtqlNUPHik0=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"bn.js": "^4.0.0",
|
||||
|
@ -7911,7 +7902,7 @@
|
|||
"mime": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz",
|
||||
"integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==",
|
||||
"integrity": "sha1-Eh+evEnjdm8xGnbh+hyAA8SwOqY=",
|
||||
"dev": true
|
||||
},
|
||||
"mime-db": {
|
||||
|
@ -8169,7 +8160,7 @@
|
|||
},
|
||||
"multipipe": {
|
||||
"version": "0.3.1",
|
||||
"resolved": "http://registry.npmjs.org/multipipe/-/multipipe-0.3.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.3.1.tgz",
|
||||
"integrity": "sha1-kmJVJXYboE/qoJYFtjgrziyR8R8=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
@ -8335,7 +8326,7 @@
|
|||
"normalize-package-data": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
|
||||
"integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==",
|
||||
"integrity": "sha1-EvlaMH1YNSB1oEkHuErIvpisAS8=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"hosted-git-info": "^2.1.4",
|
||||
|
@ -8419,7 +8410,6 @@
|
|||
"version": "0.1.4",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"kind-of": "^3.0.2",
|
||||
"longest": "^1.0.1",
|
||||
|
@ -9602,8 +9592,7 @@
|
|||
"longest": {
|
||||
"version": "1.0.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"loose-envify": {
|
||||
"version": "1.3.1",
|
||||
|
@ -11270,7 +11259,7 @@
|
|||
"p-map": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz",
|
||||
"integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==",
|
||||
"integrity": "sha1-5OlPMR6rvIYzoeeZCBZfyiYkG2s=",
|
||||
"dev": true
|
||||
},
|
||||
"p-try": {
|
||||
|
@ -11460,7 +11449,7 @@
|
|||
"pluralize": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz",
|
||||
"integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==",
|
||||
"integrity": "sha1-KYuJ34uTsCIdv0Ia0rGx6iP8Z3c=",
|
||||
"dev": true
|
||||
},
|
||||
"pngjs": {
|
||||
|
@ -12128,9 +12117,9 @@
|
|||
}
|
||||
},
|
||||
"scratch-audio": {
|
||||
"version": "0.1.0-prerelease.20181023202904",
|
||||
"resolved": "https://registry.npmjs.org/scratch-audio/-/scratch-audio-0.1.0-prerelease.20181023202904.tgz",
|
||||
"integrity": "sha512-0cf+snpT04RFWFgMsMzbztzNVyh2PkUaT8mjlwNNoIRy5p7yDN3EMC2zGbR71nZMus1tO2EDxqrpan2ix4IWDw==",
|
||||
"version": "0.1.0-prerelease.20190108181031",
|
||||
"resolved": "https://registry.npmjs.org/scratch-audio/-/scratch-audio-0.1.0-prerelease.20190108181031.tgz",
|
||||
"integrity": "sha512-Ygu+pN2u9det8HTIo+2wj8ibqe0QjAA624N9GxC62nrdGH39NxDRJyiwheeuZH/oEjM9RTsCSSOH+C9fXA9ekA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"audio-context": "1.0.1",
|
||||
|
@ -12184,9 +12173,9 @@
|
|||
}
|
||||
},
|
||||
"scratch-render": {
|
||||
"version": "0.1.0-prerelease.20181220195236",
|
||||
"resolved": "https://registry.npmjs.org/scratch-render/-/scratch-render-0.1.0-prerelease.20181220195236.tgz",
|
||||
"integrity": "sha512-FcYezDaztkoQifUG9k4uOsIFbelMt8JaCMpHrQis0QVJmjSuQrCDB3DRUjwpMuyUrmV7B7GdBUvwt65VYPZJ6g==",
|
||||
"version": "0.1.0-prerelease.20190109203013",
|
||||
"resolved": "https://registry.npmjs.org/scratch-render/-/scratch-render-0.1.0-prerelease.20190109203013.tgz",
|
||||
"integrity": "sha512-yrkBuF1zLHrXEHQmbQhpATDxot/wqoN/oDW2aIjzV9ylxCy+zNdGI2XJ9tRy10bCcM5bdC879ROX9fCr+n6FwQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"grapheme-breaker": "0.3.2",
|
||||
|
@ -12196,8 +12185,29 @@
|
|||
"minilog": "3.1.0",
|
||||
"raw-loader": "^0.5.1",
|
||||
"scratch-storage": "^1.0.0",
|
||||
"scratch-svg-renderer": "0.2.0-prerelease.20181220183040",
|
||||
"scratch-svg-renderer": "0.2.0-prerelease.20190109201344",
|
||||
"twgl.js": "4.4.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"base64-js": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.1.tgz",
|
||||
"integrity": "sha512-dwVUVIXsBZXwTuwnXI9RK8sBmgq09NDHzyR9SAph9eqk76gKK2JSQmZARC2zRC81JC2QTtxD0ARU5qTS25gIGw==",
|
||||
"dev": true
|
||||
},
|
||||
"scratch-svg-renderer": {
|
||||
"version": "0.2.0-prerelease.20190109201344",
|
||||
"resolved": "https://registry.npmjs.org/scratch-svg-renderer/-/scratch-svg-renderer-0.2.0-prerelease.20190109201344.tgz",
|
||||
"integrity": "sha512-pRMvQrM5UA2wcqleaXVpFx0Pi6Q3GsRA5elJ0tJksdr6k8HYm5D6sW62VtEtMHjnkQDa+EFyqfHq9IEPnzFjeQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"base64-js": "1.2.1",
|
||||
"base64-loader": "1.0.0",
|
||||
"minilog": "3.1.0",
|
||||
"scratch-render-fonts": "1.0.0-prerelease.20180906193204",
|
||||
"transformation-matrix": "1.14.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"scratch-render-fonts": {
|
||||
|
@ -12450,7 +12460,7 @@
|
|||
"setprototypeof": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
|
||||
"integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==",
|
||||
"integrity": "sha1-0L2FU2iHtv58DYGMuWLZ2RxU5lY=",
|
||||
"dev": true
|
||||
},
|
||||
"sha.js": {
|
||||
|
@ -12767,7 +12777,7 @@
|
|||
"source-list-map": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.0.tgz",
|
||||
"integrity": "sha512-I2UmuJSRr/T8jisiROLU3A3ltr+swpniSmNPI4Ml3ZCX6tVnDsuZzK7F2hl5jTqbZBWCEKlj5HRQiPExXLgE8A==",
|
||||
"integrity": "sha1-qqR0A/eyRakvvJfqCPJQ1gh+0IU=",
|
||||
"dev": true
|
||||
},
|
||||
"source-map": {
|
||||
|
@ -13124,7 +13134,7 @@
|
|||
"string-width": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
|
||||
"integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
|
||||
"integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-fullwidth-code-point": "^2.0.0",
|
||||
|
@ -13542,7 +13552,7 @@
|
|||
"tmp": {
|
||||
"version": "0.0.33",
|
||||
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
|
||||
"integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
|
||||
"integrity": "sha1-bTQzWIl2jSGyvNoKonfO07G/rfk=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"os-tmpdir": "~1.0.2"
|
||||
|
@ -13863,7 +13873,7 @@
|
|||
"dependencies": {
|
||||
"pako": {
|
||||
"version": "0.2.9",
|
||||
"resolved": "http://registry.npmjs.org/pako/-/pako-0.2.9.tgz",
|
||||
"resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz",
|
||||
"integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=",
|
||||
"dev": true
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
"version": "json -f package.json -I -e \"this.repository.sha = '$(git log -n1 --pretty=format:%H)'\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@vernier/godirect": "1.3.0",
|
||||
"arraybuffer-loader": "^1.0.6",
|
||||
"atob": "2.1.2",
|
||||
"btoa": "1.2.1",
|
||||
|
|
|
@ -17,6 +17,7 @@ const Scratch3VideoSensingBlocks = require('../extensions/scratch3_video_sensing
|
|||
const Scratch3Speech2TextBlocks = require('../extensions/scratch3_speech2text');
|
||||
const Scratch3Ev3Blocks = require('../extensions/scratch3_ev3');
|
||||
const Scratch3MakeyMakeyBlocks = require('../extensions/scratch3_makeymakey');
|
||||
const Scratch3GdxForBlocks = require('../extensions/scratch3_gdx_for');
|
||||
|
||||
const builtinExtensions = {
|
||||
pen: Scratch3PenBlocks,
|
||||
|
@ -28,7 +29,8 @@ const builtinExtensions = {
|
|||
videoSensing: Scratch3VideoSensingBlocks,
|
||||
speech2text: Scratch3Speech2TextBlocks,
|
||||
ev3: Scratch3Ev3Blocks,
|
||||
makeymakey: Scratch3MakeyMakeyBlocks
|
||||
makeymakey: Scratch3MakeyMakeyBlocks,
|
||||
gdxfor: Scratch3GdxForBlocks
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
632
src/extensions/scratch3_gdx_for/index.js
Normal file
632
src/extensions/scratch3_gdx_for/index.js
Normal file
|
@ -0,0 +1,632 @@
|
|||
const ArgumentType = require('../../extension-support/argument-type');
|
||||
const BlockType = require('../../extension-support/block-type');
|
||||
const log = require('../../util/log');
|
||||
const Cast = require('../../util/cast');
|
||||
const formatMessage = require('format-message');
|
||||
const MathUtil = require('../../util/math-util');
|
||||
const BLE = require('../../io/ble');
|
||||
const godirect = require('@vernier/godirect/dist/godirect.min.umd.js');
|
||||
const ScratchLinkDeviceAdapter = require('./scratch-link-device-adapter');
|
||||
|
||||
/**
|
||||
* Icon png to be displayed at the left edge of each extension block, encoded as a data URI.
|
||||
* @type {string}
|
||||
*/
|
||||
// eslint-disable-next-line max-len
|
||||
const blockIconURI = 'data:image/png;base64,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';
|
||||
|
||||
/**
|
||||
* Enum for Vernier godirect protocol.
|
||||
* @readonly
|
||||
* @enum {string}
|
||||
*/
|
||||
const BLEUUID = {
|
||||
service: 'd91714ef-28b9-4f91-ba16-f0d9a604f112',
|
||||
commandChar: 'f4bf14a6-c7d5-4b6d-8aa8-df1a7c83adcb',
|
||||
responseChar: 'b41e6675-a329-40e0-aa01-44d2f444babe'
|
||||
};
|
||||
|
||||
/**
|
||||
* Manage communication with a GDX-FOR peripheral over a Scratch Link client socket.
|
||||
*/
|
||||
class GdxFor {
|
||||
|
||||
/**
|
||||
* Construct a GDX-FOR communication object.
|
||||
* @param {Runtime} runtime - the Scratch 3.0 runtime
|
||||
* @param {string} extensionId - the id of the extension
|
||||
*/
|
||||
constructor (runtime, extensionId) {
|
||||
|
||||
/**
|
||||
* The Scratch 3.0 runtime used to trigger the green flag button.
|
||||
* @type {Runtime}
|
||||
* @private
|
||||
*/
|
||||
this._runtime = runtime;
|
||||
|
||||
/**
|
||||
* The BluetoothLowEnergy connection socket for reading/writing peripheral data.
|
||||
* @type {BLE}
|
||||
* @private
|
||||
*/
|
||||
this._scratchLinkSocket = null;
|
||||
|
||||
/**
|
||||
* An @vernier/godirect Device
|
||||
* @type {Device}
|
||||
* @private
|
||||
*/
|
||||
this._device = null;
|
||||
|
||||
this._runtime.registerPeripheralExtension(extensionId, this);
|
||||
|
||||
/**
|
||||
* The id of the extension this peripheral belongs to.
|
||||
*/
|
||||
this._extensionId = extensionId;
|
||||
|
||||
this.disconnect = this.disconnect.bind(this);
|
||||
this._onConnect = this._onConnect.bind(this);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called by the runtime when user wants to scan for a peripheral.
|
||||
*/
|
||||
scan () {
|
||||
if (this._device) {
|
||||
this._device.close();
|
||||
}
|
||||
|
||||
this._scratchLinkSocket = new BLE(this._runtime, this._extensionId, {
|
||||
filters: [
|
||||
{namePrefix: 'GDX-FOR'}
|
||||
],
|
||||
optionalServices: [
|
||||
BLEUUID.service
|
||||
]
|
||||
}, this._onConnect);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the runtime when user wants to connect to a certain peripheral.
|
||||
* @param {number} id - the id of the peripheral to connect to.
|
||||
*/
|
||||
connect (id) {
|
||||
if (this._scratchLinkSocket) {
|
||||
this._scratchLinkSocket.connectPeripheral(id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the runtime when a use exits the connection popup.
|
||||
* Disconnect from the GDX FOR.
|
||||
*/
|
||||
disconnect () {
|
||||
if (this._device) {
|
||||
this._device.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if connected to the goforce device.
|
||||
* @return {boolean} - whether the goforce is connected.
|
||||
*/
|
||||
isConnected () {
|
||||
let connected = false;
|
||||
if (this._scratchLinkSocket) {
|
||||
connected = this._scratchLinkSocket.isConnected();
|
||||
}
|
||||
return connected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts reading data from peripheral after BLE has connected to it.
|
||||
* @private
|
||||
*/
|
||||
_onConnect () {
|
||||
const adapter = new ScratchLinkDeviceAdapter(this._scratchLinkSocket, BLEUUID);
|
||||
godirect.createDevice(adapter, {open: true, startMeasurements: false}).then(device => {
|
||||
this._device = device;
|
||||
this._startMeasurements();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable and begin reading measurements
|
||||
* @private
|
||||
*/
|
||||
_startMeasurements () {
|
||||
this._device.sensors.forEach(sensor => {
|
||||
sensor.setEnabled(true);
|
||||
|
||||
// For now, clear the save sensor values. The unlimited saving
|
||||
// will be fixed in a future @vernier/godirect release.
|
||||
sensor.on('value-changed', changedSensor => {
|
||||
if (changedSensor.values.length > 1000) {
|
||||
changedSensor.clear();
|
||||
}
|
||||
});
|
||||
});
|
||||
this._device.start(10); // Set the period to 10 milliseconds
|
||||
}
|
||||
|
||||
|
||||
getForce () {
|
||||
if (this.isConnected()) {
|
||||
let force = this._device.getSensor(1).value;
|
||||
// Normalize the force, which can be measured between -50 and 50 N,
|
||||
// to be a value between -100 and 100.
|
||||
force = MathUtil.clamp(force * 2, -100, 100);
|
||||
return force;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
getTiltX () {
|
||||
if (this.isConnected()) {
|
||||
let x = this.getAccelerationX();
|
||||
let y = this.getAccelerationY();
|
||||
let z = this.getAccelerationZ();
|
||||
|
||||
let xSign = 1;
|
||||
let ySign = 1;
|
||||
let zSign = 1;
|
||||
|
||||
if (x < 0.0) {
|
||||
x *= -1.0; xSign = -1;
|
||||
}
|
||||
if (y < 0.0) {
|
||||
y *= -1.0; ySign = -1;
|
||||
}
|
||||
if (z < 0.0) {
|
||||
z *= -1.0; zSign = -1;
|
||||
}
|
||||
|
||||
// Compute the yz unit vector
|
||||
const z2 = z * z;
|
||||
const y2 = y * y;
|
||||
let value = z2 + y2;
|
||||
value = Math.sqrt(value);
|
||||
|
||||
// For sufficiently small zy vector values we are essentially at 90 degrees.
|
||||
// The following snaps to 90 and avoids divide-by-zero errors.
|
||||
// The snap factor was derived through observation -- just enough to
|
||||
// still allow single degree steps up to 90 (..., 87, 88, 89, 90).
|
||||
if (value < 0.35) {
|
||||
value = 90;
|
||||
} else {
|
||||
// Compute the x-axis angle
|
||||
value = x / value;
|
||||
value = Math.atan(value);
|
||||
value *= 57.2957795; // convert from rad to deg
|
||||
}
|
||||
// Manage the sign of the result
|
||||
let yzSign = ySign;
|
||||
if (z > y) yzSign = zSign;
|
||||
if (yzSign === -1) value = 180.0 - value;
|
||||
value *= xSign;
|
||||
// Round the result to the nearest degree
|
||||
value += 0.5;
|
||||
return value;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
getTiltY () {
|
||||
if (this.isConnected()) {
|
||||
let x = this.getAccelerationX();
|
||||
let y = this.getAccelerationY();
|
||||
let z = this.getAccelerationZ();
|
||||
|
||||
let xSign = 1;
|
||||
let ySign = 1;
|
||||
let zSign = 1;
|
||||
|
||||
if (x < 0.0) {
|
||||
x *= -1.0; xSign = -1;
|
||||
}
|
||||
if (y < 0.0) {
|
||||
y *= -1.0; ySign = -1;
|
||||
}
|
||||
if (z < 0.0) {
|
||||
z *= -1.0; zSign = -1;
|
||||
}
|
||||
|
||||
// Compute the yz unit vector
|
||||
const z2 = z * z;
|
||||
const x2 = x * x;
|
||||
let value = z2 + x2;
|
||||
value = Math.sqrt(value);
|
||||
|
||||
// For sufficiently small zy vector values we are essentially at 90 degrees.
|
||||
// The following snaps to 90 and avoids divide-by-zero errors.
|
||||
// The snap factor was derived through observation -- just enough to
|
||||
// still allow single degree steps up to 90 (..., 87, 88, 89, 90).
|
||||
if (value < 0.35) {
|
||||
value = 90;
|
||||
} else {
|
||||
// Compute the x-axis angle
|
||||
value = y / value;
|
||||
value = Math.atan(value);
|
||||
value *= 57.2957795; // convert from rad to deg
|
||||
}
|
||||
// Manage the sign of the result
|
||||
let xzSign = xSign;
|
||||
if (z > x) xzSign = zSign;
|
||||
if (xzSign === -1) value = 180.0 - value;
|
||||
value *= ySign;
|
||||
// Round the result to the nearest degree
|
||||
value += 0.5;
|
||||
return value;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
getAccelerationX () {
|
||||
if (this.isConnected()) {
|
||||
return this._device.getSensor(2).value;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
getAccelerationY () {
|
||||
if (this.isConnected()) {
|
||||
return this._device.getSensor(3).value;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
getAccelerationZ () {
|
||||
if (this.isConnected()) {
|
||||
return this._device.getSensor(4).value;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
getSpinSpeedX () {
|
||||
if (this.isConnected()) {
|
||||
return this._device.getSensor(5).value * (180 / Math.PI);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
getSpinSpeedY () {
|
||||
if (this.isConnected()) {
|
||||
return this._device.getSensor(6).value * (180 / Math.PI);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
getSpinSpeedZ () {
|
||||
if (this.isConnected()) {
|
||||
return this._device.getSensor(7).value * (180 / Math.PI);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enum for comparison operations.
|
||||
* @readonly
|
||||
* @enum {string}
|
||||
*/
|
||||
const ComparisonOptions = {
|
||||
LESS_THAN: 'less_than',
|
||||
GREATER_THAN: 'greater_than'
|
||||
};
|
||||
|
||||
/**
|
||||
* Scratch 3.0 blocks to interact with a GDX-FOR peripheral.
|
||||
*/
|
||||
class Scratch3GdxForBlocks {
|
||||
|
||||
/**
|
||||
* @return {string} - the name of this extension.
|
||||
*/
|
||||
static get EXTENSION_NAME () {
|
||||
return 'GDX-FOR';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {string} - the ID of this extension.
|
||||
*/
|
||||
static get EXTENSION_ID () {
|
||||
return 'gdxfor';
|
||||
}
|
||||
|
||||
get DIRECTIONS_MENU () {
|
||||
return [
|
||||
{
|
||||
text: 'x',
|
||||
value: 'x'
|
||||
},
|
||||
{
|
||||
text: 'y',
|
||||
value: 'y'
|
||||
},
|
||||
{
|
||||
text: 'z',
|
||||
value: 'z'
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
get TILT_MENU () {
|
||||
return [
|
||||
{
|
||||
text: 'x',
|
||||
value: 'x'
|
||||
},
|
||||
{
|
||||
text: 'y',
|
||||
value: 'y'
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
get COMPARE_MENU () {
|
||||
return [
|
||||
{
|
||||
text: '<',
|
||||
value: ComparisonOptions.LESS_THAN
|
||||
},
|
||||
{
|
||||
text: '>',
|
||||
value: ComparisonOptions.GREATER_THAN
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct a set of GDX-FOR blocks.
|
||||
* @param {Runtime} runtime - the Scratch 3.0 runtime.
|
||||
*/
|
||||
constructor (runtime) {
|
||||
/**
|
||||
* The Scratch 3.0 runtime.
|
||||
* @type {Runtime}
|
||||
*/
|
||||
this.runtime = runtime;
|
||||
|
||||
// Create a new GdxFor peripheral instance
|
||||
this._peripheral = new GdxFor(this.runtime, Scratch3GdxForBlocks.EXTENSION_ID);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {object} metadata for this extension and its blocks.
|
||||
*/
|
||||
getInfo () {
|
||||
return {
|
||||
id: Scratch3GdxForBlocks.EXTENSION_ID,
|
||||
name: Scratch3GdxForBlocks.EXTENSION_NAME,
|
||||
blockIconURI: blockIconURI,
|
||||
showStatusButton: true,
|
||||
blocks: [
|
||||
{
|
||||
opcode: 'whenAccelerationCompare',
|
||||
text: formatMessage({
|
||||
id: 'gdxfor.whenAccelerationCompare',
|
||||
default: 'when acceleration [COMPARE] [VALUE]',
|
||||
description: 'when the meters/second^2 value measured by the ' +
|
||||
'acceleration sensor is compared to some value'
|
||||
}),
|
||||
blockType: BlockType.HAT,
|
||||
arguments: {
|
||||
COMPARE: {
|
||||
type: ArgumentType.STRING,
|
||||
menu: 'compareOptions',
|
||||
defaultValue: ComparisonOptions.GREATER_THAN
|
||||
},
|
||||
VALUE: {
|
||||
type: ArgumentType.NUMBER,
|
||||
defaultValue: 5
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
opcode: 'whenSpinSpeedCompare',
|
||||
text: formatMessage({
|
||||
id: 'gdxfor.whenSpinSpeedCompare',
|
||||
default: 'when spin speed [COMPARE] [VALUE]',
|
||||
description: 'when the degrees/second value measured by the ' +
|
||||
'gyroscope sensor is compared to some value'
|
||||
}),
|
||||
blockType: BlockType.HAT,
|
||||
arguments: {
|
||||
COMPARE: {
|
||||
type: ArgumentType.STRING,
|
||||
menu: 'compareOptions',
|
||||
defaultValue: ComparisonOptions.GREATER_THAN
|
||||
},
|
||||
VALUE: {
|
||||
type: ArgumentType.NUMBER,
|
||||
defaultValue: 5
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
opcode: 'whenForceCompare',
|
||||
text: formatMessage({
|
||||
id: 'gdxfor.whenForceCompare',
|
||||
default: 'when force [COMPARE] [VALUE]',
|
||||
description: 'when the value measured by the force sensor is compared to some value'
|
||||
}),
|
||||
blockType: BlockType.HAT,
|
||||
arguments: {
|
||||
COMPARE: {
|
||||
type: ArgumentType.STRING,
|
||||
menu: 'compareOptions',
|
||||
defaultValue: ComparisonOptions.GREATER_THAN
|
||||
},
|
||||
VALUE: {
|
||||
type: ArgumentType.NUMBER,
|
||||
defaultValue: 5
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
opcode: 'getAcceleration',
|
||||
text: formatMessage({
|
||||
id: 'gdxfor.getAcceleration',
|
||||
default: 'acceleration [DIRECTION]',
|
||||
description: 'gets acceleration'
|
||||
}),
|
||||
blockType: BlockType.REPORTER,
|
||||
arguments: {
|
||||
DIRECTION: {
|
||||
type: ArgumentType.STRING,
|
||||
menu: 'directionOptions',
|
||||
defaultValue: 'x'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
opcode: 'getSpinSpeed',
|
||||
text: formatMessage({
|
||||
id: 'gdxfor.getSpinSpeed',
|
||||
default: 'spin speed [DIRECTION]',
|
||||
description: 'gets spin speed'
|
||||
}),
|
||||
blockType: BlockType.REPORTER,
|
||||
arguments: {
|
||||
DIRECTION: {
|
||||
type: ArgumentType.STRING,
|
||||
menu: 'directionOptions',
|
||||
defaultValue: 'x'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
opcode: 'getTilt',
|
||||
text: formatMessage({
|
||||
id: 'gdxfor.getTilt',
|
||||
default: 'tilt [TILT]',
|
||||
description: 'gets tilt'
|
||||
}),
|
||||
blockType: BlockType.REPORTER,
|
||||
arguments: {
|
||||
TILT: {
|
||||
type: ArgumentType.STRING,
|
||||
menu: 'tiltOptions',
|
||||
defaultValue: 'x'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
opcode: 'getForce',
|
||||
text: formatMessage({
|
||||
id: 'gdxfor.getForce',
|
||||
default: 'force',
|
||||
description: 'gets force'
|
||||
}),
|
||||
blockType: BlockType.REPORTER
|
||||
}
|
||||
],
|
||||
menus: {
|
||||
directionOptions: this.DIRECTIONS_MENU,
|
||||
compareOptions: this.COMPARE_MENU,
|
||||
tiltOptions: this.TILT_MENU
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} x - x axis vector
|
||||
* @param {number} y - y axis vector
|
||||
* @param {number} z - z axis vector
|
||||
* @return {number} - the magnitude of a three dimension vector.
|
||||
*/
|
||||
magnitude (x, y, z) {
|
||||
return Math.sqrt((x * x) + (y * y) + (z * z));
|
||||
}
|
||||
|
||||
|
||||
whenAccelerationCompare (args) {
|
||||
const currentVal = this.magnitude(
|
||||
this._peripheral.getAccelerationX(),
|
||||
this._peripheral.getAccelerationY(),
|
||||
this._peripheral.getAccelerationZ()
|
||||
);
|
||||
|
||||
switch (args.COMPARE) {
|
||||
case ComparisonOptions.LESS_THAN:
|
||||
return currentVal < Cast.toNumber(args.VALUE);
|
||||
case ComparisonOptions.GREATER_THAN:
|
||||
return currentVal > Cast.toNumber(args.VALUE);
|
||||
default:
|
||||
log.warn(`Unknown comparison operator in whenAccelerationCompare: ${args.COMPARE}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
whenSpinSpeedCompare (args) {
|
||||
const currentVal = this.magnitude(
|
||||
this._peripheral.getSpinSpeedX(),
|
||||
this._peripheral.getSpinSpeedY(),
|
||||
this._peripheral.getSpinSpeedZ()
|
||||
);
|
||||
|
||||
switch (args.COMPARE) {
|
||||
case ComparisonOptions.LESS_THAN:
|
||||
return currentVal < Cast.toNumber(args.VALUE);
|
||||
case ComparisonOptions.GREATER_THAN:
|
||||
return currentVal > Cast.toNumber(args.VALUE);
|
||||
default:
|
||||
log.warn(`Unknown comparison operator in whenSpinSpeedCompare: ${args.COMPARE}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
whenForceCompare (args) {
|
||||
switch (args.COMPARE) {
|
||||
case ComparisonOptions.LESS_THAN:
|
||||
return this._peripheral.getForce() < Cast.toNumber(args.VALUE);
|
||||
case ComparisonOptions.GREATER_THAN:
|
||||
return this._peripheral.getForce() > Cast.toNumber(args.VALUE);
|
||||
default:
|
||||
log.warn(`Unknown comparison operator in whenForceCompare: ${args.COMPARE}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
getAcceleration (args) {
|
||||
switch (args.DIRECTION) {
|
||||
case 'x':
|
||||
return this._peripheral.getAccelerationX();
|
||||
case 'y':
|
||||
return this._peripheral.getAccelerationY();
|
||||
case 'z':
|
||||
return this._peripheral.getAccelerationZ();
|
||||
default:
|
||||
log.warn(`Unknown direction in getAcceleration: ${args.DIRECTION}`);
|
||||
}
|
||||
}
|
||||
getSpinSpeed (args) {
|
||||
switch (args.DIRECTION) {
|
||||
case 'x':
|
||||
return this._peripheral.getSpinSpeedX();
|
||||
case 'y':
|
||||
return this._peripheral.getSpinSpeedY();
|
||||
case 'z':
|
||||
return this._peripheral.getSpinSpeedZ();
|
||||
default:
|
||||
log.warn(`Unknown direction in getSpinSpeed: ${args.DIRECTION}`);
|
||||
}
|
||||
}
|
||||
getTilt (args) {
|
||||
switch (args.TILT) {
|
||||
case 'x':
|
||||
return this._peripheral.getTiltX();
|
||||
case 'y':
|
||||
return this._peripheral.getTiltY();
|
||||
default:
|
||||
log.warn(`Unknown direction in getTilt: ${args.TILT}`);
|
||||
}
|
||||
}
|
||||
getForce () {
|
||||
return this._peripheral.getForce();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Scratch3GdxForBlocks;
|
|
@ -0,0 +1,48 @@
|
|||
const Base64Util = require('../../util/base64-util');
|
||||
|
||||
/**
|
||||
* Adapter class
|
||||
*/
|
||||
class ScratchLinkDeviceAdapter {
|
||||
constructor (scratchLinkSocket, {service, commandChar, responseChar}) {
|
||||
this.scratchLinkSocket = scratchLinkSocket;
|
||||
|
||||
this._service = service;
|
||||
this._commandChar = commandChar;
|
||||
this._responseChar = responseChar;
|
||||
this._onResponse = this._onResponse.bind(this);
|
||||
this._deviceOnResponse = null;
|
||||
}
|
||||
|
||||
get godirectAdapter () {
|
||||
return true;
|
||||
}
|
||||
|
||||
writeCommand (commandBuffer) {
|
||||
const data = Base64Util.uint8ArrayToBase64(commandBuffer);
|
||||
|
||||
return this.scratchLinkSocket
|
||||
.write(this._service, this._commandChar, data, 'base64', true);
|
||||
}
|
||||
|
||||
setup ({onResponse}) {
|
||||
this._deviceOnResponse = onResponse;
|
||||
return this.scratchLinkSocket
|
||||
.startNotifications(this._service, this._responseChar, this._onResponse);
|
||||
|
||||
// TODO:
|
||||
// How do we find out from scratch link if communication closes?
|
||||
}
|
||||
|
||||
_onResponse (base64) {
|
||||
const array = Base64Util.base64ToUint8Array(base64);
|
||||
const response = new DataView(array.buffer);
|
||||
return this._deviceOnResponse(response);
|
||||
}
|
||||
|
||||
close () {
|
||||
return this.scratchLinkSocket.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ScratchLinkDeviceAdapter;
|
Loading…
Reference in a new issue