Skip to content

Commit 0919c1c

Browse files
committed
Ported files from other projects and made some modifications.
1 parent d344bd0 commit 0919c1c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+2027
-103
lines changed

.gitignore

Lines changed: 2 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1,104 +1,3 @@
1-
# Logs
2-
logs
3-
*.log
4-
npm-debug.log*
5-
yarn-debug.log*
6-
yarn-error.log*
7-
lerna-debug.log*
8-
9-
# Diagnostic reports (https://nodejs.org/api/report.html)
10-
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
11-
12-
# Runtime data
13-
pids
14-
*.pid
15-
*.seed
16-
*.pid.lock
17-
18-
# Directory for instrumented libs generated by jscoverage/JSCover
19-
lib-cov
20-
21-
# Coverage directory used by tools like istanbul
22-
coverage
23-
*.lcov
24-
25-
# nyc test coverage
26-
.nyc_output
27-
28-
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
29-
.grunt
30-
31-
# Bower dependency directory (https://bower.io/)
32-
bower_components
33-
34-
# node-waf configuration
35-
.lock-wscript
36-
37-
# Compiled binary addons (https://nodejs.org/api/addons.html)
38-
build/Release
39-
40-
# Dependency directories
41-
node_modules/
42-
jspm_packages/
43-
44-
# TypeScript v1 declaration files
45-
typings/
46-
47-
# TypeScript cache
48-
*.tsbuildinfo
49-
50-
# Optional npm cache directory
51-
.npm
52-
53-
# Optional eslint cache
54-
.eslintcache
55-
56-
# Microbundle cache
57-
.rpt2_cache/
58-
.rts2_cache_cjs/
59-
.rts2_cache_es/
60-
.rts2_cache_umd/
61-
62-
# Optional REPL history
63-
.node_repl_history
64-
65-
# Output of 'npm pack'
66-
*.tgz
67-
68-
# Yarn Integrity file
69-
.yarn-integrity
70-
71-
# dotenv environment variables file
72-
.env
73-
.env.test
74-
75-
# parcel-bundler cache (https://parceljs.org/)
76-
.cache
77-
78-
# Next.js build output
79-
.next
80-
81-
# Nuxt.js build / generate output
82-
.nuxt
831
dist
84-
85-
# Gatsby files
86-
.cache/
87-
# Comment in the public line in if your project uses Gatsby and *not* Next.js
88-
# https://nextjs.org/blog/next-9-1#public-directory-support
89-
# public
90-
91-
# vuepress build output
92-
.vuepress/dist
93-
94-
# Serverless directories
95-
.serverless/
96-
97-
# FuseBox cache
98-
.fusebox/
99-
100-
# DynamoDB Local files
101-
.dynamodb/
102-
103-
# TernJS port file
104-
.tern-port
2+
node_modules
3+
.npmrc

AliasedAction.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import Action from './actions/Action'
2+
import Resolver from './actions/Resolver'
3+
4+
/**
5+
* AliasedActions are the lowest level of user-facing elements. Actions are executed by the user and are simply
6+
* a wrapper to reference an Action and it's arguments.
7+
*/
8+
class AliasedAction {
9+
10+
/**
11+
* The key of this AliasedAction. Should probably be CAPS_SNAKE_CASE.
12+
*/
13+
key: string
14+
/**
15+
* Array of server identifiers that this AliasedAction is available on.
16+
*/
17+
availableOn: string[] = []
18+
/**
19+
* The Action which this AliasedAction is a wrapper for.
20+
*/
21+
action: Action
22+
23+
/**
24+
* Constructor
25+
* @param key {string} The key of this item.
26+
*/
27+
constructor (key: string) {
28+
this.key = key
29+
30+
}
31+
32+
/**
33+
* Deserialize a JSON-stringified AliasedAction into an AliasedAction object.
34+
* @param json {string} The JSON to deserialize.
35+
* @return {Promise<AliasedAction>} The AliasedAction that was deserialized.
36+
*/
37+
static async deserialize(json: string) : Promise<AliasedAction> {
38+
const obj = JSON.parse(json)
39+
const aa = new AliasedAction(obj.key)
40+
for(const prop in obj) {
41+
if(!obj.hasOwnProperty(prop)) {
42+
continue
43+
}
44+
aa[prop] = obj[prop]
45+
}
46+
aa.action = await Resolver.deserialize(JSON.stringify(obj.action))
47+
return aa
48+
}
49+
}
50+
51+
export default AliasedAction

Button.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/**
2+
* Buttons are the median user-facing element, between AliasedActions and Screens. Screens contain a list of
3+
* Buttons, and Buttons contain a list of AliasedActions.
4+
*/
5+
class Button {
6+
7+
/**
8+
* The key of this Button. Unique identifier, should probably be CAPS_SNAKE_CASE
9+
*/
10+
key: string
11+
/**
12+
* Array of server identifiers that this Button is available on.
13+
*/
14+
availableOn: string[] = []
15+
/**
16+
* Array of AliasedAction keys which this Button executes. AliasedAction objects are not used directly to reduce
17+
* Action size, remove redundant references to AliasedActions, and due to the async nature in how AliasedActions are
18+
* handled by the client.
19+
*/
20+
actions: string[] = []
21+
/**
22+
* The URL to the image which can be displayed as this Button, specifically on "IMAGES" type Screens.
23+
*/
24+
imageURL = ''
25+
/**
26+
* The translation key for this Button's title.
27+
*/
28+
translationKey = ''
29+
30+
/**
31+
* Constructor
32+
* @param key {string} The key/ID of this item.
33+
*/
34+
constructor (key: string) {
35+
this.key = key
36+
}
37+
38+
/**
39+
* Deserialize a JSON-stringified Button into an Button object.
40+
* @param json {string} The JSON to deserialize.
41+
* @return {Promise<Button>} The Button that was deserialized.
42+
*/
43+
static async deserialize(json: string) : Promise<Button> {
44+
const obj = JSON.parse(json)
45+
const btn = new Button(obj.key)
46+
for(const prop in obj) {
47+
if(!obj.hasOwnProperty(prop)) {
48+
continue
49+
}
50+
btn[prop] = obj[prop]
51+
}
52+
return btn
53+
}
54+
}
55+
56+
export default Button

Screen.ts

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
const ScreenTypes = Object.freeze({
2+
IMAGES: 'IMAGES',
3+
BUTTONS: 'BUTTONS'
4+
})
5+
6+
/**
7+
* A Screen in Quickplay is the highest level of user-facing objects. Screens are a set of Buttons which can be laid
8+
* out in a variety of ways. The client can display these Screens.
9+
*/
10+
class Screen {
11+
12+
/**
13+
* The key of this Screen. Unique identifier, should probably be CAPS_SNAKE_CASE.
14+
*/
15+
key: string
16+
/**
17+
* Array of server identifiers that this Screen is available on.
18+
*/
19+
availableOn: string[] = []
20+
/**
21+
* Array of Button keys which this Screen renders. Button objects are not used directly to reduce Action
22+
* size, remove redundant references to Buttons, and due to the async nature in how Buttons are
23+
* handled by the client.
24+
*/
25+
buttons: string[] = []
26+
/**
27+
* Type of Screen that this Screen is. Should be "IMAGES" or "BUTTONS", in most cases.
28+
* @see ScreenTypes
29+
*/
30+
screenType = ''
31+
/**
32+
* The translation key for this Screen's title.
33+
*/
34+
translationKey = ''
35+
/**
36+
* List of AliasedActions which should be executed when the client clicks this Screen's back button.
37+
*/
38+
backButtonActions: string[] = []
39+
/**
40+
* The URL to the image which can be displayed at the top of this Screen.
41+
*/
42+
imageURL = ''
43+
44+
/**
45+
* Constructor
46+
* @param key {string} The key/ID of this item.
47+
* @param screenType {string} Type of screen that this screen is.
48+
*/
49+
constructor (key: string, screenType: string) {
50+
this.key = key
51+
this.buttons = []
52+
this.screenType = screenType
53+
if(!ScreenTypes[this.screenType]) {
54+
throw new Error('Invalid screen type: Screen type must be IMAGES or BUTTONS.')
55+
}
56+
this.backButtonActions = []
57+
}
58+
59+
/**
60+
* Deserialize a JSON-stringified Screen into an Screen object.
61+
* @param json {string} The JSON to deserialize.
62+
* @return {Promise<Screen>} The Screen that was deserialized.
63+
*/
64+
static async deserialize(json: string) : Promise<Screen> {
65+
const obj = JSON.parse(json)
66+
const screen = new Screen(obj.key, obj.screenType)
67+
for(const prop in obj) {
68+
if(!obj.hasOwnProperty(prop)) {
69+
continue
70+
}
71+
screen[prop] = obj[prop]
72+
}
73+
return screen
74+
}
75+
76+
}
77+
78+
export default Screen
79+
export {ScreenTypes}

actions/Action.ts

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import {Buffer} from 'buffer'
2+
3+
/**
4+
* Actions are the core mechanism behind how Quickplay operates. Whenever the client/user
5+
* clicks a button, presses a keybind, receives instructions from the web server, etc.,
6+
* Besides some of the current commands system, the client is not able to do any I/O other than what
7+
* is available through Actions (eventually, ideally all the Quickplay commands would also run Actions).
8+
*
9+
* Actions are serializable in a similar format to Minecraft packets, and can be sent over the wire.
10+
* The structure is as follows:
11+
* When serialized, all Actions must contain at least 2 bytes. These are the first two bytes, which
12+
* are the Action's ID. All subsequent bytes are considered the payload. They can be considered arguments
13+
* to the Action, and are split up into partitions, each of which is one argument. An argument begins
14+
* with the first 4 bytes being the length x of the argument. After those bytes, the next x bytes are
15+
* the actual argument. This signature repeats, until there are no more bytes.
16+
*
17+
* If there are too few bytes in the Action, a RangeError will be thrown. It is possible
18+
* for a serialized Action to be valid, but the subsequent execution of the Action to fail if there were
19+
* not enough arguments provided in the payload.
20+
*
21+
* Actions can also be sent to the web server, providing context to actions/events occurring on the client,
22+
* such as exceptions, connection status, button presses, etc.
23+
*/
24+
class Action {
25+
26+
static id = 0
27+
id = 0
28+
payloadObjs:Buffer[] = []
29+
30+
/**
31+
* Build an action into a Buffer from its ID and payload list.
32+
* @return {Buffer} Built buffer which can be sent over the wire.
33+
*/
34+
build () : Buffer {
35+
let body = Buffer.alloc(2)
36+
body.writeUInt16BE(this.id, 0)
37+
38+
for(let i = 0; i < this.payloadObjs.length; i++) {
39+
const payloadSize = Buffer.alloc(4)
40+
41+
payloadSize.writeInt32BE(this.payloadObjs[i].byteLength, 0)
42+
body = Buffer.concat([body, payloadSize, this.payloadObjs[i]])
43+
}
44+
45+
return body
46+
}
47+
48+
/**
49+
* Add an item to the payload.
50+
* @param obj {Buffer} Item to add.
51+
*/
52+
addPayload (obj: Buffer) : void {
53+
this.payloadObjs.push(obj)
54+
}
55+
56+
/**
57+
* Get an object from the payload at the specified index
58+
* @param index {number} Index of the item to get. Should be >= 0 and < payloadObjs.length
59+
* @return {Buffer} The payload item, or null if it does not exist.
60+
*/
61+
getPayloadObject(index: number) : Buffer {
62+
if(this.payloadObjs.length <= index) {
63+
return null
64+
}
65+
return this.payloadObjs[index]
66+
}
67+
68+
/**
69+
* Get an item from the Payload and convert it to a String in UTF-8.
70+
* @param index {number} Index of the item to get. Must be >= 0 and < payloadObjs.length
71+
* @return {string} Decoded String
72+
*/
73+
getPayloadObjectAsString(index: number) : string {
74+
const obj = this.getPayloadObject(index)
75+
if(obj == null) {
76+
return null
77+
}
78+
return obj.toString()
79+
}
80+
81+
}
82+
83+
export default Action

0 commit comments

Comments
 (0)