├── .gitignore
├── .npmignore
├── API.md
├── LICENSE
├── README.md
├── client.js
├── package-lock.json
├── package.json
└── src
└── LiveSplitClient.js
/.gitignore:
--------------------------------------------------------------------------------
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
83 | 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
105 |
106 | # Additional repo ignore
107 | tools/
108 |
109 | dev.js
110 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
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
83 | 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
105 |
106 | # Additional repo ignore
107 | tools/
--------------------------------------------------------------------------------
/API.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## LiveSplitClient
4 | Node.js client for the LiveSplit Server running instance
5 |
6 | **Kind**: global class
7 |
8 | * [LiveSplitClient](#LiveSplitClient)
9 | * [new LiveSplitClient(address)](#new_LiveSplitClient_new)
10 | * [.connected](#LiveSplitClient+connected) : boolean
11 | * [.connect()](#LiveSplitClient+connect) ⇒ Promise
12 | * [.disconnect()](#LiveSplitClient+disconnect) ⇒ boolean
13 | * [.send(command, [expectResponse])](#LiveSplitClient+send) ⇒ Promise
\| boolean
14 | * [.startTimer()](#LiveSplitClient+startTimer) ⇒ boolean
15 | * [.startOrSplit()](#LiveSplitClient+startOrSplit) ⇒ boolean
16 | * [.split()](#LiveSplitClient+split) ⇒ boolean
17 | * [.unsplit()](#LiveSplitClient+unsplit) ⇒ boolean
18 | * [.skipSplit()](#LiveSplitClient+skipSplit) ⇒ boolean
19 | * [.pause()](#LiveSplitClient+pause) ⇒ boolean
20 | * [.resume()](#LiveSplitClient+resume) ⇒ boolean
21 | * [.reset()](#LiveSplitClient+reset) ⇒ boolean
22 | * [.initGameTime()](#LiveSplitClient+initGameTime) ⇒ boolean
23 | * [.setGameTime(time)](#LiveSplitClient+setGameTime) ⇒ boolean
24 | * [.setLoadingTimes(time)](#LiveSplitClient+setLoadingTimes) ⇒ boolean
25 | * [.pauseGameTime()](#LiveSplitClient+pauseGameTime) ⇒ boolean
26 | * [.unpauseGameTime()](#LiveSplitClient+unpauseGameTime) ⇒ boolean
27 | * [.setComparison(comparison)](#LiveSplitClient+setComparison) ⇒ boolean
28 | * [.getDelta([comparison])](#LiveSplitClient+getDelta) ⇒ Promise
29 | * [.getLastSplitTime()](#LiveSplitClient+getLastSplitTime) ⇒ Promise
30 | * [.getComparisonSplitTime()](#LiveSplitClient+getComparisonSplitTime) ⇒ Promise
31 | * [.getCurrentTime()](#LiveSplitClient+getCurrentTime) ⇒ Promise
32 | * [.getFinalTime([comparison])](#LiveSplitClient+getFinalTime) ⇒ Promise
33 | * [.getPredictedTime([comparison])](#LiveSplitClient+getPredictedTime) ⇒ Promise
34 | * [.getBestPossibleTime()](#LiveSplitClient+getBestPossibleTime) ⇒ Promise
35 | * [.getSplitIndex()](#LiveSplitClient+getSplitIndex) ⇒ Promise
36 | * [.getCurrentSplitName()](#LiveSplitClient+getCurrentSplitName) ⇒ Promise
37 | * [.getPreviousSplitName()](#LiveSplitClient+getPreviousSplitName) ⇒ Promise
38 | * [.getCurrentTimerPhase()](#LiveSplitClient+getCurrentTimerPhase) ⇒ Promise
39 | * [.getAll()](#LiveSplitClient+getAll) ⇒ Promise
40 |
41 |
42 |
43 | ### new LiveSplitClient(address)
44 |
45 | | Param | Type | Description |
46 | | --- | --- | --- |
47 | | address | string
| Connection address, like: 127.0.0.1:1234 |
48 |
49 |
50 |
51 | ### liveSplitClient.connected : boolean
52 | Client connection status.
53 |
54 | **Kind**: instance property of [LiveSplitClient
](#LiveSplitClient)
55 |
56 |
57 | ### liveSplitClient.connect() ⇒ Promise
58 | Performs connection attempt to the LiveSplit Server instance.
59 |
60 | **Kind**: instance method of [LiveSplitClient
](#LiveSplitClient)
61 | **Returns**: Promise
- Connection result or error.
62 |
63 |
64 | ### liveSplitClient.disconnect() ⇒ boolean
65 | Disconnect client from the sever.
66 |
67 | **Kind**: instance method of [LiveSplitClient
](#LiveSplitClient)
68 | **Returns**: boolean
- Disconnection result.
69 |
70 |
71 | ### liveSplitClient.send(command, [expectResponse]) ⇒ Promise
\| boolean
72 | Send command to the LiveSplit Server instance.
73 |
74 | **Kind**: instance method of [LiveSplitClient
](#LiveSplitClient)
75 | **Returns**: Promise
\| boolean
- - Promise if answer was expected, else true.
76 |
77 | | Param | Type | Default | Description |
78 | | --- | --- | --- | --- |
79 | | command | string
| | Existing LiveSplit Server command without linebreaks. |
80 | | [expectResponse] | boolean
| true
| Expect response from the server. |
81 |
82 |
83 |
84 | ### liveSplitClient.startTimer() ⇒ boolean
85 | Start timer
86 |
87 | **Kind**: instance method of [LiveSplitClient
](#LiveSplitClient)
88 |
89 |
90 | ### liveSplitClient.startOrSplit() ⇒ boolean
91 | Start or split
92 |
93 | **Kind**: instance method of [LiveSplitClient
](#LiveSplitClient)
94 |
95 |
96 | ### liveSplitClient.split() ⇒ boolean
97 | Split
98 |
99 | **Kind**: instance method of [LiveSplitClient
](#LiveSplitClient)
100 |
101 |
102 | ### liveSplitClient.unsplit() ⇒ boolean
103 | Unsplit
104 |
105 | **Kind**: instance method of [LiveSplitClient
](#LiveSplitClient)
106 |
107 |
108 | ### liveSplitClient.skipSplit() ⇒ boolean
109 | Skip split
110 |
111 | **Kind**: instance method of [LiveSplitClient
](#LiveSplitClient)
112 |
113 |
114 | ### liveSplitClient.pause() ⇒ boolean
115 | Pause
116 |
117 | **Kind**: instance method of [LiveSplitClient
](#LiveSplitClient)
118 |
119 |
120 | ### liveSplitClient.resume() ⇒ boolean
121 | Resume
122 |
123 | **Kind**: instance method of [LiveSplitClient
](#LiveSplitClient)
124 |
125 |
126 | ### liveSplitClient.reset() ⇒ boolean
127 | Reset
128 |
129 | **Kind**: instance method of [LiveSplitClient
](#LiveSplitClient)
130 |
131 |
132 | ### liveSplitClient.initGameTime() ⇒ boolean
133 | Init game time. Could be called only once according to LiveSplit Server documentation.
134 |
135 | **Kind**: instance method of [LiveSplitClient
](#LiveSplitClient)
136 |
137 |
138 | ### liveSplitClient.setGameTime(time) ⇒ boolean
139 | Set game time
140 |
141 | **Kind**: instance method of [LiveSplitClient
](#LiveSplitClient)
142 |
143 | | Param | Type | Description |
144 | | --- | --- | --- |
145 | | time | string
| Game time |
146 |
147 |
148 |
149 | ### liveSplitClient.setLoadingTimes(time) ⇒ boolean
150 | Set loading times
151 |
152 | **Kind**: instance method of [LiveSplitClient
](#LiveSplitClient)
153 |
154 | | Param | Type | Description |
155 | | --- | --- | --- |
156 | | time | string
| Game time |
157 |
158 |
159 |
160 | ### liveSplitClient.pauseGameTime() ⇒ boolean
161 | Pause game time
162 |
163 | **Kind**: instance method of [LiveSplitClient
](#LiveSplitClient)
164 |
165 |
166 | ### liveSplitClient.unpauseGameTime() ⇒ boolean
167 | Unpause game time
168 |
169 | **Kind**: instance method of [LiveSplitClient
](#LiveSplitClient)
170 |
171 |
172 | ### liveSplitClient.setComparison(comparison) ⇒ boolean
173 | Set comparison
174 |
175 | **Kind**: instance method of [LiveSplitClient
](#LiveSplitClient)
176 |
177 | | Param | Type | Description |
178 | | --- | --- | --- |
179 | | comparison | string
| Comparison |
180 |
181 |
182 |
183 | ### liveSplitClient.getDelta([comparison]) ⇒ Promise
184 | Get delta
185 |
186 | **Kind**: instance method of [LiveSplitClient
](#LiveSplitClient)
187 | **Returns**: Promise
- Command result or null on timeout.
188 |
189 | | Param | Type | Description |
190 | | --- | --- | --- |
191 | | [comparison] | string
| Comparison |
192 |
193 |
194 |
195 | ### liveSplitClient.getLastSplitTime() ⇒ Promise
196 | Get last split time
197 |
198 | **Kind**: instance method of [LiveSplitClient
](#LiveSplitClient)
199 | **Returns**: Promise
- Command result or null on timeout.
200 |
201 |
202 | ### liveSplitClient.getComparisonSplitTime() ⇒ Promise
203 | Get comparison split time
204 |
205 | **Kind**: instance method of [LiveSplitClient
](#LiveSplitClient)
206 | **Returns**: Promise
- Command result or null on timeout.
207 |
208 |
209 | ### liveSplitClient.getCurrentTime() ⇒ Promise
210 | Get current time
211 |
212 | **Kind**: instance method of [LiveSplitClient
](#LiveSplitClient)
213 | **Returns**: Promise
- Command result or null on timeout.
214 |
215 |
216 | ### liveSplitClient.getFinalTime([comparison]) ⇒ Promise
217 | Get final time
218 |
219 | **Kind**: instance method of [LiveSplitClient
](#LiveSplitClient)
220 | **Returns**: Promise
- Command result or null on timeout.
221 |
222 | | Param | Type | Description |
223 | | --- | --- | --- |
224 | | [comparison] | string
| Comparison |
225 |
226 |
227 |
228 | ### liveSplitClient.getPredictedTime([comparison]) ⇒ Promise
229 | Get predicted time
230 |
231 | **Kind**: instance method of [LiveSplitClient
](#LiveSplitClient)
232 | **Returns**: Promise
- Command result or null on timeout.
233 |
234 | | Param | Type | Description |
235 | | --- | --- | --- |
236 | | [comparison] | string
| Comparison |
237 |
238 |
239 |
240 | ### liveSplitClient.getBestPossibleTime() ⇒ Promise
241 | Get best pssible time
242 |
243 | **Kind**: instance method of [LiveSplitClient
](#LiveSplitClient)
244 | **Returns**: Promise
- Command result or null on timeout.
245 |
246 |
247 | ### liveSplitClient.getSplitIndex() ⇒ Promise
248 | Get split index
249 |
250 | **Kind**: instance method of [LiveSplitClient
](#LiveSplitClient)
251 | **Returns**: Promise
- Command result or null on timeout.
252 |
253 |
254 | ### liveSplitClient.getCurrentSplitName() ⇒ Promise
255 | Get current split name
256 |
257 | **Kind**: instance method of [LiveSplitClient
](#LiveSplitClient)
258 | **Returns**: Promise
- Command result or null on timeout.
259 |
260 |
261 | ### liveSplitClient.getPreviousSplitName() ⇒ Promise
262 | Get previous split name
263 |
264 | **Kind**: instance method of [LiveSplitClient
](#LiveSplitClient)
265 | **Returns**: Promise
- Command result or null on timeout.
266 |
267 |
268 | ### liveSplitClient.getCurrentTimerPhase() ⇒ Promise
269 | Get current timer phase
270 |
271 | **Kind**: instance method of [LiveSplitClient
](#LiveSplitClient)
272 | **Returns**: Promise
- Command result or null on timeout.
273 |
274 |
275 | ### liveSplitClient.getAll() ⇒ Promise
276 | Get all available information. Synthetic method that calls every server getter command if possible.
277 |
278 | **Kind**: instance method of [LiveSplitClient
](#LiveSplitClient)
279 | **Returns**: Promise
- Commands execution result or false on timeout.
280 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 satanch
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # node-livesplit-client
2 |
3 | Zero-dependency Node.js client library for the LiveSplit Server.
4 |
5 | ## How to install
6 |
7 | Simply run in your terminal:
8 |
9 | ```sh
10 | npm install livesplit-client
11 | ```
12 |
13 | ## How to use
14 |
15 | * Enable [LiveSplit Server](https://github.com/LiveSplit/LiveSplit?tab=readme-ov-file#the-livesplit-server).
16 | * Then look into this usage example:
17 |
18 | ```js
19 | const LiveSplitClient = require('livesplit-client');
20 |
21 | (async () => {
22 | try {
23 | // Initialize client with LiveSplit Server's IP:PORT
24 | const client = new LiveSplitClient('127.0.0.1:16834');
25 |
26 | // Connect to the server, Promise will be resolved when the connection will be succesfully established
27 | await client.connect();
28 |
29 | // Start timer.
30 | client.startOrSplit();
31 |
32 | // Job done, now we can close this connection
33 | client.disconnect();
34 | } catch (err) {
35 | console.error(err); // Something went wrong
36 | }
37 | })();
38 | ```
39 |
40 | ## Library API
41 |
42 | ### Library docs
43 |
44 | [Click here and you will be navigated to the latest API docs](https://github.com/satanch/node-livesplit-client/blob/main/API.md).
45 |
46 | ### Setting custom timeout
47 |
48 | Default command response timeout is 100 ms. You can set your own timeout:
49 |
50 | ```js
51 | const LiveSplitClient = require('livesplit-client');
52 | const client = new LiveSplitClient('127.0.0.1:16834');
53 | client.timeout = 250; // Timeout in ms
54 | ```
55 |
56 | ### Sending custom commands without library methods
57 |
58 | You could use `client.send('command', expectResponse)`. Please note, that `\r\n` will be automatically added to your command.
59 | If your are expecting the answer, your should specify `true` as second argument of this method. In other case `Promise` will not be returned and you could potentially break answers order.
60 |
61 | ## Extended example
62 |
63 | ```js
64 | const LiveSplitClient = require('livesplit-client');
65 |
66 | (async () => {
67 | try {
68 | // Initialize client with LiveSplit Server's IP:PORT
69 | const client = new LiveSplitClient('127.0.0.1:16834');
70 |
71 | // Connected event
72 | client.on('connected', () => {
73 | console.log('Connected!');
74 | });
75 |
76 | // Disconnected event
77 | client.on('disconnected', () => {
78 | console.log('Disconnected!');
79 | });
80 |
81 | // Error event
82 | client.on('error', (err) => {
83 | console.log(err);
84 | });
85 |
86 | // Raw data reciever
87 | client.on('data', (data) => {
88 | console.log('Debug data:', data);
89 | });
90 |
91 | // Some async sleep sugar for this example
92 | const sleep = (time) => {
93 | return new Promise((r) => {
94 | setTimeout(() => r(), time);
95 | });
96 | };
97 |
98 | // Connect to the server, Promise will be resolved when the connection will be succesfully established
99 | await client.connect();
100 |
101 | // Start timer
102 | client.startOrSplit();
103 |
104 | // Wait for 1 sec
105 | await sleep(1000);
106 |
107 | // Current time after 1 second
108 | const time = await client.getCurrentTime();
109 |
110 | console.log('Current time after 1 sec.:', time); // Blazing fast and accurate numbers
111 |
112 | // Get split name
113 | const splitName = await client.getCurrentSplitName();
114 | console.log('Split name:', splitName);
115 |
116 | // Get all available information
117 | const info = await client.getAll();
118 | console.log('Summary:', info);
119 |
120 | // Pause and reset
121 | await client.pause();
122 | await client.reset();
123 |
124 | // Job done, now we can close this connection
125 | client.disconnect();
126 | } catch (err) {
127 | console.error(err); // Something went wrong
128 | }
129 | })();
130 | ```
131 |
132 | ## Contribution
133 |
134 | Feel free to create issues and PR's. Thank you for your help!
135 |
--------------------------------------------------------------------------------
/client.js:
--------------------------------------------------------------------------------
1 | /*
2 | node-livesplit-client
3 | Developed by satanch
4 | */
5 |
6 | module.exports = require('./src/LiveSplitClient');
7 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "livesplit-client",
3 | "version": "1.0.4",
4 | "lockfileVersion": 3,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "livesplit-client",
9 | "version": "1.0.4",
10 | "license": "MIT"
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "livesplit-client",
3 | "version": "1.0.4",
4 | "description": "LiveSplit Server Node.js client implementation",
5 | "main": "client.js",
6 | "scripts": {
7 | "doc": "jsdoc2md ./src/LiveSplitClient.js > ./API.md"
8 | },
9 | "keywords": [
10 | "livesplit",
11 | "server"
12 | ],
13 | "author": "satanch",
14 | "license": "MIT",
15 | "repository": {
16 | "type" : "git",
17 | "url" : "https://github.com/satanch/node-livesplit-client.git"
18 | },
19 | "homepage": "https://github.com/satanch/node-livesplit-client#readme"
20 | }
21 |
--------------------------------------------------------------------------------
/src/LiveSplitClient.js:
--------------------------------------------------------------------------------
1 | const net = require('net');
2 | const EventEmitter = require('events');
3 | const { deprecate } = require('util');
4 |
5 | /**
6 | * Node.js client for the LiveSplit Server running instance
7 | * @constructor
8 | * @param {string} address - Connection address, like: 127.0.0.1:1234
9 | */
10 | class LiveSplitClient extends EventEmitter {
11 | constructor(address) {
12 | super();
13 |
14 | if (typeof address !== 'string')
15 | throw new TypeError('Invalid argument type! IP:PORT expected.');
16 |
17 | address = address.split(':');
18 |
19 | if (address.length !== 2)
20 | throw new Error('Failed to parse connection details! IP:PORT expected.');
21 |
22 | this._connectionDetails = {
23 | ip: address[0],
24 | port: parseInt(address[1])
25 | };
26 |
27 | this._connected = false;
28 | this.timeout = 100;
29 | this._processingCommands = false;
30 | this._commands = [];
31 | this._noResponseCommands = [];
32 |
33 | /*
34 | According to: https://github.com/LiveSplit/LiveSplit.Server/blob/a4a57716dce90936606bfc8f8ac84f7623773aa5/README.md#commands
35 |
36 | When using Game Time, it's important that you call "initgametime" once. Once "initgametime" is used, an additional comparison will appear and you can switch to it via the context menu (Compare Against > Game Time). This special comparison will show everything based on the Game Time (every component now shows Game Time based information).
37 | */
38 | this._initGameTimeOnce = false;
39 |
40 | this.getPreviousSplitname = deprecate(this.getPreviousSplitname, 'Method "getPreviousSplitname" is deprecated! Please, use "getPreviousSplitName" (capital letter "N") instead.');
41 |
42 | return this;
43 | }
44 |
45 | /**
46 | * Performs connection attempt to the LiveSplit Server instance.
47 | * @returns {Promise} Connection result or error.
48 | */
49 | connect() {
50 | this._socket = new net.Socket();
51 |
52 | return new Promise((resolve, reject) => {
53 | this._socket.connect(this._connectionDetails.port, this._connectionDetails.ip, () => {
54 | this._connected = true;
55 | this.emit('connected');
56 | resolve(this._connected);
57 | });
58 |
59 | this._socket.on('data', (data) => {
60 | this.emit(
61 | 'data',
62 | data.toString('utf-8').replace('\r\n', '')
63 | );
64 | });
65 |
66 | this._socket.on('error', (err) => {
67 | this.emit('error', err);
68 | reject(err);
69 | });
70 |
71 | this._socket.on('close', () => {
72 | this._connected = false;
73 | this.emit('disconnected');
74 | });
75 | });
76 | }
77 |
78 | /**
79 | * Disconnect client from the sever.
80 | * @returns {boolean} Disconnection result.
81 | */
82 | disconnect() {
83 | if (!this._connected) return false;
84 | this._socket.destroy();
85 | this._connected = false;
86 | return true;
87 | }
88 |
89 | /**
90 | * Client connection status.
91 | * @type {boolean}
92 | */
93 | get connected() {
94 | return this._connected;
95 | }
96 |
97 | /**
98 | * Send command to the LiveSplit Server instance.
99 | * @param {string} command - Existing LiveSplit Server command without linebreaks.
100 | * @param {boolean} [expectResponse=true] - Expect response from the server.
101 | * @returns {Promise|boolean} - Promise if answer was expected, else true.
102 | */
103 | send(command, expectResponse = true) {
104 | if (!this._connected)
105 | throw new Error('Client must be connected to the server!');
106 |
107 | if (typeof command !== 'string')
108 | throw new Error('String expected!');
109 |
110 | this._checkDisallowedSymbols(command);
111 |
112 | command = `${command}\r\n`;
113 |
114 | if (expectResponse) {
115 | let resolve = null;
116 | let promise = new Promise((res) => {
117 | resolve = res;
118 | });
119 |
120 | this._commands.push({
121 | command,
122 | resolve
123 | });
124 |
125 | if (!this._processingCommands)
126 | this._sendNext();
127 |
128 | return promise;
129 | } else {
130 | if (!this._processingCommands)
131 | this._socket.write(command);
132 | else
133 | this._noResponseCommands.push(command);
134 |
135 | return true;
136 | }
137 | }
138 |
139 | _sendNext() {
140 | if (this._commands.length === 0) {
141 | this._processingCommands = false;
142 |
143 | while (this._noResponseCommands.length > 0)
144 | this._socket.write(this._noResponseCommands.pop());
145 |
146 | return;
147 | }
148 |
149 | this._processingCommands = true;
150 |
151 | let next = this._commands[0];
152 |
153 | let timeout = setTimeout(() => {
154 | this._commands.shift();
155 | this.removeListener('data', listener);
156 | next.resolve(null);
157 | this._sendNext();
158 | }, this.timeout);
159 |
160 | let listener = (data) => {
161 | this._commands.shift();
162 | clearTimeout(timeout);
163 | next.resolve(data);
164 | this._sendNext();
165 | };
166 |
167 | this.once('data', listener);
168 | this._socket.write(next.command);
169 | }
170 |
171 | _checkDisallowedSymbols(str) {
172 | if (str.indexOf('\r\n') !== -1)
173 | throw new Error('No newline symbols allowed!');
174 |
175 | return true;
176 | }
177 |
178 | /**
179 | * Start timer
180 | * @returns {boolean}
181 | */
182 | startTimer() {
183 | return this.send('starttimer', false);
184 | }
185 |
186 | /**
187 | * Start or split
188 | * @returns {boolean}
189 | */
190 | startOrSplit() {
191 | return this.send('startorsplit', false);
192 | }
193 |
194 | /**
195 | * Split
196 | * @returns {boolean}
197 | */
198 | split() {
199 | return this.send('split', false);
200 | }
201 |
202 | /**
203 | * Unsplit
204 | * @returns {boolean}
205 | */
206 | unsplit() {
207 | return this.send('unsplit', false);
208 | }
209 |
210 | /**
211 | * Skip split
212 | * @returns {boolean}
213 | */
214 | skipSplit() {
215 | return this.send('skipsplit', false);
216 | }
217 |
218 | /**
219 | * Pause
220 | * @returns {boolean}
221 | */
222 | pause() {
223 | return this.send('pause', false);
224 | }
225 |
226 | /**
227 | * Resume
228 | * @returns {boolean}
229 | */
230 | resume() {
231 | return this.send('resume', false);
232 | }
233 |
234 | /**
235 | * Reset
236 | * @returns {boolean}
237 | */
238 | reset() {
239 | return this.send('reset', false);
240 | }
241 |
242 | /**
243 | * Init game time. Could be called only once according to LiveSplit Server documentation.
244 | * @returns {boolean}
245 | */
246 | initGameTime() {
247 | if (this._initGameTimeOnce) return false;
248 | this._initGameTimeOnce = true;
249 | return this.send('initgametime', false);
250 | }
251 |
252 | /**
253 | * Set game time
254 | * @param {string} time - Game time
255 | * @returns {boolean}
256 | */
257 | setGameTime(time) {
258 | return this.send(`setgametime ${time}`, false);
259 | }
260 |
261 | /**
262 | * Set loading times
263 | * @param {string} time - Game time
264 | * @returns {boolean}
265 | */
266 | setLoadingTimes(time) {
267 | return this.send(`setloadingtimes ${time}`, false);
268 | }
269 |
270 | /**
271 | * Pause game time
272 | * @returns {boolean}
273 | */
274 | pauseGameTime() {
275 | return this.send('pausegametime', false);
276 | }
277 |
278 | /**
279 | * Unpause game time
280 | * @returns {boolean}
281 | */
282 | unpauseGameTime() {
283 | return this.send('unpausegametime', false);
284 | }
285 |
286 | /**
287 | * Set comparison
288 | * @param {string} comparison - Comparison
289 | * @returns {boolean}
290 | */
291 | setComparison(comparison) {
292 | return this.send(`setcomparison ${comparison}`, false);
293 | }
294 |
295 | /**
296 | * Get delta
297 | * @param {string} [comparison] - Comparison
298 | * @returns {Promise} Command result or null on timeout.
299 | */
300 | getDelta(comparison = '') {
301 | if (comparison) comparison = ` ${comparison}`;
302 | return this.send(`getdelta${comparison}`, true);
303 | }
304 |
305 | /**
306 | * Get last split time
307 | * @returns {Promise} Command result or null on timeout.
308 | */
309 | getLastSplitTime() {
310 | return this.send('getlastsplittime', true);
311 | }
312 |
313 | /**
314 | * Get comparison split time
315 | * @returns {Promise} Command result or null on timeout.
316 | */
317 | getComparisonSplitTime() {
318 | return this.send('getcomparisonsplittime', true);
319 | }
320 |
321 | /**
322 | * Get current time
323 | * @returns {Promise} Command result or null on timeout.
324 | */
325 | getCurrentTime() {
326 | return this.send('getcurrenttime', true);
327 | }
328 |
329 | /**
330 | * Get final time
331 | * @param {string} [comparison] - Comparison
332 | * @returns {Promise} Command result or null on timeout.
333 | */
334 | getFinalTime(comparison = '') {
335 | if (comparison) comparison = ` ${comparison}`;
336 | return this.send(`getfinaltime${comparison}`, true);
337 | }
338 |
339 | /**
340 | * Get predicted time
341 | * @param {string} [comparison] - Comparison
342 | * @returns {Promise} Command result or null on timeout.
343 | */
344 | getPredictedTime(comparison = '') {
345 | if (comparison) comparison = ` ${comparison}`;
346 | return this.send(`getpredictedtime${comparison}`, true);
347 | }
348 |
349 | /**
350 | * Get best pssible time
351 | * @returns {Promise} Command result or null on timeout.
352 | */
353 | getBestPossibleTime() {
354 | return this.send('getbestpossibletime', true);
355 | }
356 |
357 | /**
358 | * Get split index
359 | * @returns {Promise} Command result or null on timeout.
360 | */
361 | getSplitIndex() {
362 | return this.send('getsplitindex', true);
363 | }
364 |
365 | /**
366 | * Get current split name
367 | * @returns {Promise} Command result or null on timeout.
368 | */
369 | getCurrentSplitName() {
370 | return this.send('getcurrentsplitname', true);
371 | }
372 |
373 | /**
374 | * Get previous split name
375 | * @returns {Promise} Command result or null on timeout.
376 | */
377 | getPreviousSplitName() {
378 | return this.send('getprevioussplitname', true);
379 | }
380 |
381 | getPreviousSplitname() {
382 | return this.getPreviousSplitName();
383 | }
384 |
385 | /**
386 | * Get current timer phase
387 | * @returns {Promise} Command result or null on timeout.
388 | */
389 | getCurrentTimerPhase() {
390 | return this.send('getcurrenttimerphase', true);
391 | }
392 |
393 | /**
394 | * Get all available information. Synthetic method that calls every server getter command if possible.
395 | * @returns {Promise} Commands execution result or false on timeout.
396 | */
397 | async getAll() {
398 | const output = {};
399 |
400 | for (let method of ['getCurrentTimerPhase', 'getDelta', 'getLastSplitTime', 'getComparisonSplitTime', 'getCurrentTime', 'getFinalTime', 'getPredictedTime', 'getBestPossibleTime', 'getSplitIndex', 'getCurrentSplitName', 'getPreviousSplitName']) {
401 | output[
402 | method.replace('get', '').charAt(0).toLowerCase() + method.replace('get', '').slice(1)
403 | ] = await this[method]();
404 | }
405 |
406 | return output;
407 | }
408 | }
409 |
410 | module.exports = LiveSplitClient;
411 |
--------------------------------------------------------------------------------