@caspertech/node-metaverse 0.7.24 → 0.7.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.editorconfig +817 -817
- package/.eslintrc +224 -224
- package/IdeaCodeStyle.xml +68 -68
- package/LICENSE +21 -21
- package/README.md +78 -78
- package/dist/keepme.txt +0 -0
- package/dist/lib/classes/llsd/LLSDNotationParser.spec.js +46 -46
- package/examples/Camera/Camera.ts +24 -24
- package/examples/ExampleBot.ts +178 -178
- package/examples/Friends/Friends.ts +67 -67
- package/examples/Grid/Name2Key.ts +50 -50
- package/examples/Groups/Group.ts +102 -102
- package/examples/Groups/GroupChat.ts +112 -112
- package/examples/InstantMessages/InstantMessages.ts +41 -41
- package/examples/Inventory/Inventory.ts +175 -175
- package/examples/MFA/MFA.ts +55 -55
- package/examples/Money/Money.ts +63 -63
- package/examples/Objects/TaskInventory.ts +35 -35
- package/examples/Region/Agents.ts +81 -81
- package/examples/Region/Estate.ts +34 -34
- package/examples/Region/Parcels.ts +31 -31
- package/examples/Region/Region.ts +23 -23
- package/examples/Teleports/Teleports.ts +60 -60
- package/package.json +71 -71
package/README.md
CHANGED
|
@@ -1,78 +1,78 @@
|
|
|
1
|
-
# node-metaverse
|
|
2
|
-
|
|
3
|
-
> A node.js interface for Second Life.
|
|
4
|
-
|
|
5
|
-
[](https://badge.fury.io/js/%40caspertech%2Fnode-metaverse)
|
|
6
|
-
[](https://travis-ci.org/CasperTech/node-metaverse)
|
|
7
|
-
[](https://snyk.io/test/npm/@caspertech/node-metaverse)
|
|
8
|
-
|
|
9
|
-
## Install
|
|
10
|
-
|
|
11
|
-
```bash
|
|
12
|
-
npm install --save @caspertech/node-metaverse
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
## Usage
|
|
16
|
-
|
|
17
|
-
Javascript
|
|
18
|
-
|
|
19
|
-
```javascript
|
|
20
|
-
const nmv = require('@caspertech/node-metaverse');
|
|
21
|
-
|
|
22
|
-
const loginParameters = new nmv.LoginParameters();
|
|
23
|
-
loginParameters.firstName = 'firstName';
|
|
24
|
-
loginParameters.lastName = 'lastName';
|
|
25
|
-
loginParameters.password = 'password';
|
|
26
|
-
loginParameters.start = "last";
|
|
27
|
-
|
|
28
|
-
const options = nmv.BotOptionFlags.LiteObjectStore | nmv.BotOptionFlags.StoreMyAttachmentsOnly;
|
|
29
|
-
const bot = new nmv.Bot(loginParameters, options);
|
|
30
|
-
|
|
31
|
-
bot.login().then((response) =>
|
|
32
|
-
{
|
|
33
|
-
console.log("Login complete");
|
|
34
|
-
|
|
35
|
-
//Establish circuit with region
|
|
36
|
-
return bot.connectToSim();
|
|
37
|
-
}).then(() =>
|
|
38
|
-
{
|
|
39
|
-
console.log("Connected");
|
|
40
|
-
}).catch((error) =>
|
|
41
|
-
{
|
|
42
|
-
console.error(error);
|
|
43
|
-
});
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
Typescript
|
|
47
|
-
|
|
48
|
-
```typescript
|
|
49
|
-
import { Bot, BotOptionFlags, LoginParameters } from '@caspertech/node-metaverse';
|
|
50
|
-
|
|
51
|
-
const loginParameters = new LoginParameters();
|
|
52
|
-
loginParameters.firstName = 'firstName';
|
|
53
|
-
loginParameters.lastName = 'lastName';
|
|
54
|
-
loginParameters.password = 'password';
|
|
55
|
-
loginParameters.start = 'last';
|
|
56
|
-
|
|
57
|
-
const options = BotOptionFlags.LiteObjectStore | BotOptionFlags.StoreMyAttachmentsOnly;
|
|
58
|
-
const bot = new Bot(loginParameters, options);
|
|
59
|
-
|
|
60
|
-
bot.login().then((response) =>
|
|
61
|
-
{
|
|
62
|
-
console.log("Login complete");
|
|
63
|
-
|
|
64
|
-
//Establish circuit with region
|
|
65
|
-
return bot.connectToSim();
|
|
66
|
-
}).then(() =>
|
|
67
|
-
{
|
|
68
|
-
console.log("Connected");
|
|
69
|
-
}).catch((error) =>
|
|
70
|
-
{
|
|
71
|
-
console.error(error);
|
|
72
|
-
});
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
## License
|
|
77
|
-
|
|
78
|
-
[MIT](http://vjpr.mit-license.org)
|
|
1
|
+
# node-metaverse
|
|
2
|
+
|
|
3
|
+
> A node.js interface for Second Life.
|
|
4
|
+
|
|
5
|
+
[](https://badge.fury.io/js/%40caspertech%2Fnode-metaverse)
|
|
6
|
+
[](https://travis-ci.org/CasperTech/node-metaverse)
|
|
7
|
+
[](https://snyk.io/test/npm/@caspertech/node-metaverse)
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install --save @caspertech/node-metaverse
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
Javascript
|
|
18
|
+
|
|
19
|
+
```javascript
|
|
20
|
+
const nmv = require('@caspertech/node-metaverse');
|
|
21
|
+
|
|
22
|
+
const loginParameters = new nmv.LoginParameters();
|
|
23
|
+
loginParameters.firstName = 'firstName';
|
|
24
|
+
loginParameters.lastName = 'lastName';
|
|
25
|
+
loginParameters.password = 'password';
|
|
26
|
+
loginParameters.start = "last";
|
|
27
|
+
|
|
28
|
+
const options = nmv.BotOptionFlags.LiteObjectStore | nmv.BotOptionFlags.StoreMyAttachmentsOnly;
|
|
29
|
+
const bot = new nmv.Bot(loginParameters, options);
|
|
30
|
+
|
|
31
|
+
bot.login().then((response) =>
|
|
32
|
+
{
|
|
33
|
+
console.log("Login complete");
|
|
34
|
+
|
|
35
|
+
//Establish circuit with region
|
|
36
|
+
return bot.connectToSim();
|
|
37
|
+
}).then(() =>
|
|
38
|
+
{
|
|
39
|
+
console.log("Connected");
|
|
40
|
+
}).catch((error) =>
|
|
41
|
+
{
|
|
42
|
+
console.error(error);
|
|
43
|
+
});
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Typescript
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
import { Bot, BotOptionFlags, LoginParameters } from '@caspertech/node-metaverse';
|
|
50
|
+
|
|
51
|
+
const loginParameters = new LoginParameters();
|
|
52
|
+
loginParameters.firstName = 'firstName';
|
|
53
|
+
loginParameters.lastName = 'lastName';
|
|
54
|
+
loginParameters.password = 'password';
|
|
55
|
+
loginParameters.start = 'last';
|
|
56
|
+
|
|
57
|
+
const options = BotOptionFlags.LiteObjectStore | BotOptionFlags.StoreMyAttachmentsOnly;
|
|
58
|
+
const bot = new Bot(loginParameters, options);
|
|
59
|
+
|
|
60
|
+
bot.login().then((response) =>
|
|
61
|
+
{
|
|
62
|
+
console.log("Login complete");
|
|
63
|
+
|
|
64
|
+
//Establish circuit with region
|
|
65
|
+
return bot.connectToSim();
|
|
66
|
+
}).then(() =>
|
|
67
|
+
{
|
|
68
|
+
console.log("Connected");
|
|
69
|
+
}).catch((error) =>
|
|
70
|
+
{
|
|
71
|
+
console.error(error);
|
|
72
|
+
});
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
## License
|
|
77
|
+
|
|
78
|
+
[MIT](http://vjpr.mit-license.org)
|
package/dist/keepme.txt
ADDED
|
File without changes
|
|
@@ -7,52 +7,52 @@ const UUID_1 = require("../UUID");
|
|
|
7
7
|
describe('LLSDNotationParser', () => {
|
|
8
8
|
describe('parse', () => {
|
|
9
9
|
it('can parse a complex LLSD Notation document', () => {
|
|
10
|
-
const notationDoc = `{
|
|
11
|
-
'nested_map': {
|
|
12
|
-
'nested_again': {
|
|
13
|
-
'array': [
|
|
14
|
-
i0,
|
|
15
|
-
'string',
|
|
16
|
-
"string2",
|
|
17
|
-
[
|
|
18
|
-
"another",
|
|
19
|
-
"array",
|
|
20
|
-
r4.3,
|
|
21
|
-
i22,
|
|
22
|
-
!,
|
|
23
|
-
{
|
|
24
|
-
'isThis': i42
|
|
25
|
-
}
|
|
26
|
-
]
|
|
27
|
-
]
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
'undef': !,
|
|
31
|
-
'booleans': [
|
|
32
|
-
true,
|
|
33
|
-
false,
|
|
34
|
-
1,
|
|
35
|
-
0,
|
|
36
|
-
T,
|
|
37
|
-
F,
|
|
38
|
-
t,
|
|
39
|
-
f,
|
|
40
|
-
TRUE,
|
|
41
|
-
FALSE
|
|
42
|
-
],
|
|
43
|
-
'integer': i69,
|
|
44
|
-
'negInt': i-69,
|
|
45
|
-
'real': r3.141,
|
|
46
|
-
'realNeg': r-3.141,
|
|
47
|
-
'uuid': ufb54f6b1-8120-40c9-9aa3-f9abef1a168f,
|
|
48
|
-
'string1': "gday\\"mate",
|
|
49
|
-
'string2': 'gday\\'mate',
|
|
50
|
-
'string3': s(11)"hello"there",
|
|
51
|
-
'uri': l"https://secondlife.com/",
|
|
52
|
-
'date': d"2023-11-10T13:32:32.93Z",
|
|
53
|
-
'binary': b64"amVsbHlmaXNo",
|
|
54
|
-
'binary2': b16"6261636F6E62697473",
|
|
55
|
-
'binary3': b(32)"KÚ~¬\béGÀt|Ïh,9µEK¹*;]ÆÁåb/"
|
|
10
|
+
const notationDoc = `{
|
|
11
|
+
'nested_map': {
|
|
12
|
+
'nested_again': {
|
|
13
|
+
'array': [
|
|
14
|
+
i0,
|
|
15
|
+
'string',
|
|
16
|
+
"string2",
|
|
17
|
+
[
|
|
18
|
+
"another",
|
|
19
|
+
"array",
|
|
20
|
+
r4.3,
|
|
21
|
+
i22,
|
|
22
|
+
!,
|
|
23
|
+
{
|
|
24
|
+
'isThis': i42
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
'undef': !,
|
|
31
|
+
'booleans': [
|
|
32
|
+
true,
|
|
33
|
+
false,
|
|
34
|
+
1,
|
|
35
|
+
0,
|
|
36
|
+
T,
|
|
37
|
+
F,
|
|
38
|
+
t,
|
|
39
|
+
f,
|
|
40
|
+
TRUE,
|
|
41
|
+
FALSE
|
|
42
|
+
],
|
|
43
|
+
'integer': i69,
|
|
44
|
+
'negInt': i-69,
|
|
45
|
+
'real': r3.141,
|
|
46
|
+
'realNeg': r-3.141,
|
|
47
|
+
'uuid': ufb54f6b1-8120-40c9-9aa3-f9abef1a168f,
|
|
48
|
+
'string1': "gday\\"mate",
|
|
49
|
+
'string2': 'gday\\'mate',
|
|
50
|
+
'string3': s(11)"hello"there",
|
|
51
|
+
'uri': l"https://secondlife.com/",
|
|
52
|
+
'date': d"2023-11-10T13:32:32.93Z",
|
|
53
|
+
'binary': b64"amVsbHlmaXNo",
|
|
54
|
+
'binary2': b16"6261636F6E62697473",
|
|
55
|
+
'binary3': b(32)"KÚ~¬\béGÀt|Ïh,9µEK¹*;]ÆÁåb/"
|
|
56
56
|
}`;
|
|
57
57
|
const parsed = LLSDNotationParser_1.LLSDNotationParser.parse(notationDoc);
|
|
58
58
|
if (!(parsed instanceof LLSDMap_1.LLSDMap)) {
|
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
import { ExampleBot } from '../ExampleBot';
|
|
2
|
-
import { Vector3 } from '../../lib/classes/Vector3';
|
|
3
|
-
|
|
4
|
-
class Camera extends ExampleBot
|
|
5
|
-
{
|
|
6
|
-
async onConnected(): Promise<void>
|
|
7
|
-
{
|
|
8
|
-
const height = 64;
|
|
9
|
-
this.bot.clientCommands.agent.setCamera(
|
|
10
|
-
new Vector3([128, 128, height]),
|
|
11
|
-
new Vector3([128, 128, 0]),
|
|
12
|
-
256,
|
|
13
|
-
new Vector3([-1.0, 0, 0]),
|
|
14
|
-
new Vector3([0.0, 1.0, 0]));
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
new Camera().run().then(() =>
|
|
19
|
-
{
|
|
20
|
-
|
|
21
|
-
}).catch((err) =>
|
|
22
|
-
{
|
|
23
|
-
console.error(err)
|
|
24
|
-
});
|
|
1
|
+
import { ExampleBot } from '../ExampleBot';
|
|
2
|
+
import { Vector3 } from '../../lib/classes/Vector3';
|
|
3
|
+
|
|
4
|
+
class Camera extends ExampleBot
|
|
5
|
+
{
|
|
6
|
+
async onConnected(): Promise<void>
|
|
7
|
+
{
|
|
8
|
+
const height = 64;
|
|
9
|
+
this.bot.clientCommands.agent.setCamera(
|
|
10
|
+
new Vector3([128, 128, height]),
|
|
11
|
+
new Vector3([128, 128, 0]),
|
|
12
|
+
256,
|
|
13
|
+
new Vector3([-1.0, 0, 0]),
|
|
14
|
+
new Vector3([0.0, 1.0, 0]));
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
new Camera().run().then(() =>
|
|
19
|
+
{
|
|
20
|
+
|
|
21
|
+
}).catch((err) =>
|
|
22
|
+
{
|
|
23
|
+
console.error(err)
|
|
24
|
+
});
|
package/examples/ExampleBot.ts
CHANGED
|
@@ -1,178 +1,178 @@
|
|
|
1
|
-
import { Vector3 } from '../lib';
|
|
2
|
-
import { LoginResponse } from '../lib/classes/LoginResponse';
|
|
3
|
-
import { Bot } from '../lib/Bot';
|
|
4
|
-
import { LoginParameters } from '../lib/classes/LoginParameters';
|
|
5
|
-
import { BotOptionFlags } from '../lib/enums/BotOptionFlags';
|
|
6
|
-
|
|
7
|
-
import * as path from 'path';
|
|
8
|
-
|
|
9
|
-
import Signals = NodeJS.Signals;
|
|
10
|
-
import Timeout = NodeJS.Timeout;
|
|
11
|
-
|
|
12
|
-
export class ExampleBot
|
|
13
|
-
{
|
|
14
|
-
protected masterAvatar = 'd1cd5b71-6209-4595-9bf0-771bf689ce00';
|
|
15
|
-
protected isConnected = false;
|
|
16
|
-
protected isConnecting = false;
|
|
17
|
-
protected loginParamsJsonFile: string;
|
|
18
|
-
protected loginResponse?: LoginResponse;
|
|
19
|
-
protected bot: Bot;
|
|
20
|
-
private reconnectTimer?: Timeout;
|
|
21
|
-
protected loginParameters: LoginParameters;
|
|
22
|
-
|
|
23
|
-
protected stayRegion?: string;
|
|
24
|
-
protected stayPosition?: Vector3;
|
|
25
|
-
protected firstName?: string;
|
|
26
|
-
protected lastName?: string;
|
|
27
|
-
|
|
28
|
-
constructor()
|
|
29
|
-
{
|
|
30
|
-
this.loginParamsJsonFile = path.join(__dirname, '..', '..', 'examples', 'loginParameters.json');
|
|
31
|
-
this.loginParameters = require(this.loginParamsJsonFile);
|
|
32
|
-
this.firstName = this.loginParameters.firstName;
|
|
33
|
-
this.lastName = this.loginParameters.lastName;
|
|
34
|
-
|
|
35
|
-
// If you don't intend to use the object store (i.e you have no interest in inworld objects, textures, etc,
|
|
36
|
-
// using nmv.BotOptionFlags.LiteObjectStore will drastically reduce the footprint and CPU usage.
|
|
37
|
-
//
|
|
38
|
-
// The full object store has a full searchable rtree index, the lite does not.
|
|
39
|
-
//
|
|
40
|
-
// For the minimum footprint, use :
|
|
41
|
-
//
|
|
42
|
-
// const options = nmv.BotOptionFlags.LiteObjectStore | nmv.BotOptionFlags.StoreMyAttachmentsOnly;
|
|
43
|
-
|
|
44
|
-
const options = BotOptionFlags.None;
|
|
45
|
-
|
|
46
|
-
this.bot = new Bot(this.loginParameters, options);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
public async run(): Promise<void>
|
|
50
|
-
{
|
|
51
|
-
const exitHandler = async(options: { exit?: boolean }, err: Error | number | Signals) =>
|
|
52
|
-
{
|
|
53
|
-
if (err && err instanceof Error)
|
|
54
|
-
{
|
|
55
|
-
console.log(err.stack);
|
|
56
|
-
}
|
|
57
|
-
if (this.isConnected)
|
|
58
|
-
{
|
|
59
|
-
console.log('Disconnecting');
|
|
60
|
-
try
|
|
61
|
-
{
|
|
62
|
-
await this.bot.close();
|
|
63
|
-
}
|
|
64
|
-
catch (error)
|
|
65
|
-
{
|
|
66
|
-
console.error('Error when closing client:');
|
|
67
|
-
console.error(error);
|
|
68
|
-
}
|
|
69
|
-
process.exit();
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
if (options.exit)
|
|
73
|
-
{
|
|
74
|
-
process.exit();
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
// Do something when app is closing
|
|
81
|
-
process.on('exit', exitHandler.bind(this, {}));
|
|
82
|
-
|
|
83
|
-
// Catches ctrl+c event
|
|
84
|
-
process.on('SIGINT', exitHandler.bind(this, { exit: true }));
|
|
85
|
-
|
|
86
|
-
// Catches "kill pid"
|
|
87
|
-
process.on('SIGUSR1', exitHandler.bind(this, { exit: true }));
|
|
88
|
-
process.on('SIGUSR2', exitHandler.bind(this, { exit: true }));
|
|
89
|
-
|
|
90
|
-
// Catches uncaught exceptions
|
|
91
|
-
process.on('uncaughtException', exitHandler.bind(this, { exit: true }));
|
|
92
|
-
|
|
93
|
-
// This will tell the bot to keep trying to teleport back to the 'stay' location.
|
|
94
|
-
// You can specify a region and position, such as:
|
|
95
|
-
// bot.stayPut(true, 'Izanagi', new nmv.Vector3([128, 128, 21]));
|
|
96
|
-
// Note that the 'stay' location will be updated if you request or accept a lure (a teleport).
|
|
97
|
-
// If no region is specified, it will be set to the region you log in to.
|
|
98
|
-
this.bot.stayPut(true, this.stayRegion, this.stayPosition);
|
|
99
|
-
|
|
100
|
-
await this.login();
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
protected async onConnected(): Promise<void>
|
|
104
|
-
{
|
|
105
|
-
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
protected async login(): Promise<void>
|
|
109
|
-
{
|
|
110
|
-
if (this.isConnecting)
|
|
111
|
-
{
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
this.isConnecting = true;
|
|
115
|
-
try
|
|
116
|
-
{
|
|
117
|
-
if (this.reconnectTimer !== undefined)
|
|
118
|
-
{
|
|
119
|
-
clearInterval(this.reconnectTimer);
|
|
120
|
-
}
|
|
121
|
-
this.reconnectTimer = setInterval(this.reconnectCheck.bind(this), 60000);
|
|
122
|
-
|
|
123
|
-
console.log('Logging in..');
|
|
124
|
-
this.loginResponse = await this.bot.login();
|
|
125
|
-
|
|
126
|
-
console.log('Login complete');
|
|
127
|
-
|
|
128
|
-
// Establish circuit with region
|
|
129
|
-
await this.bot.connectToSim();
|
|
130
|
-
|
|
131
|
-
console.log('Waiting for event queue');
|
|
132
|
-
await this.bot.waitForEventQueue();
|
|
133
|
-
|
|
134
|
-
this.isConnected = true;
|
|
135
|
-
}
|
|
136
|
-
finally
|
|
137
|
-
{
|
|
138
|
-
this.isConnecting = false;
|
|
139
|
-
}
|
|
140
|
-
return this.connected();
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
private async reconnectCheck(): Promise<void>
|
|
144
|
-
{
|
|
145
|
-
if (!this.isConnected)
|
|
146
|
-
{
|
|
147
|
-
await this.login();
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
private async connected(): Promise<void>
|
|
152
|
-
{
|
|
153
|
-
this.bot.clientEvents.onDisconnected.subscribe((event) =>
|
|
154
|
-
{
|
|
155
|
-
if (event.requested)
|
|
156
|
-
{
|
|
157
|
-
if (this.reconnectTimer !== undefined)
|
|
158
|
-
{
|
|
159
|
-
clearInterval(this.reconnectTimer);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
this.isConnected = false;
|
|
163
|
-
console.log('Disconnected from simulator: ' + event.message);
|
|
164
|
-
});
|
|
165
|
-
await this.onConnected();
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// @ts-ignore
|
|
169
|
-
private async close(): Promise<void>
|
|
170
|
-
{
|
|
171
|
-
if (this.reconnectTimer !== undefined)
|
|
172
|
-
{
|
|
173
|
-
clearInterval(this.reconnectTimer);
|
|
174
|
-
this.reconnectTimer = undefined;
|
|
175
|
-
}
|
|
176
|
-
return this.bot.close();
|
|
177
|
-
}
|
|
178
|
-
}
|
|
1
|
+
import { Vector3 } from '../lib';
|
|
2
|
+
import { LoginResponse } from '../lib/classes/LoginResponse';
|
|
3
|
+
import { Bot } from '../lib/Bot';
|
|
4
|
+
import { LoginParameters } from '../lib/classes/LoginParameters';
|
|
5
|
+
import { BotOptionFlags } from '../lib/enums/BotOptionFlags';
|
|
6
|
+
|
|
7
|
+
import * as path from 'path';
|
|
8
|
+
|
|
9
|
+
import Signals = NodeJS.Signals;
|
|
10
|
+
import Timeout = NodeJS.Timeout;
|
|
11
|
+
|
|
12
|
+
export class ExampleBot
|
|
13
|
+
{
|
|
14
|
+
protected masterAvatar = 'd1cd5b71-6209-4595-9bf0-771bf689ce00';
|
|
15
|
+
protected isConnected = false;
|
|
16
|
+
protected isConnecting = false;
|
|
17
|
+
protected loginParamsJsonFile: string;
|
|
18
|
+
protected loginResponse?: LoginResponse;
|
|
19
|
+
protected bot: Bot;
|
|
20
|
+
private reconnectTimer?: Timeout;
|
|
21
|
+
protected loginParameters: LoginParameters;
|
|
22
|
+
|
|
23
|
+
protected stayRegion?: string;
|
|
24
|
+
protected stayPosition?: Vector3;
|
|
25
|
+
protected firstName?: string;
|
|
26
|
+
protected lastName?: string;
|
|
27
|
+
|
|
28
|
+
constructor()
|
|
29
|
+
{
|
|
30
|
+
this.loginParamsJsonFile = path.join(__dirname, '..', '..', 'examples', 'loginParameters.json');
|
|
31
|
+
this.loginParameters = require(this.loginParamsJsonFile);
|
|
32
|
+
this.firstName = this.loginParameters.firstName;
|
|
33
|
+
this.lastName = this.loginParameters.lastName;
|
|
34
|
+
|
|
35
|
+
// If you don't intend to use the object store (i.e you have no interest in inworld objects, textures, etc,
|
|
36
|
+
// using nmv.BotOptionFlags.LiteObjectStore will drastically reduce the footprint and CPU usage.
|
|
37
|
+
//
|
|
38
|
+
// The full object store has a full searchable rtree index, the lite does not.
|
|
39
|
+
//
|
|
40
|
+
// For the minimum footprint, use :
|
|
41
|
+
//
|
|
42
|
+
// const options = nmv.BotOptionFlags.LiteObjectStore | nmv.BotOptionFlags.StoreMyAttachmentsOnly;
|
|
43
|
+
|
|
44
|
+
const options = BotOptionFlags.None;
|
|
45
|
+
|
|
46
|
+
this.bot = new Bot(this.loginParameters, options);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
public async run(): Promise<void>
|
|
50
|
+
{
|
|
51
|
+
const exitHandler = async(options: { exit?: boolean }, err: Error | number | Signals) =>
|
|
52
|
+
{
|
|
53
|
+
if (err && err instanceof Error)
|
|
54
|
+
{
|
|
55
|
+
console.log(err.stack);
|
|
56
|
+
}
|
|
57
|
+
if (this.isConnected)
|
|
58
|
+
{
|
|
59
|
+
console.log('Disconnecting');
|
|
60
|
+
try
|
|
61
|
+
{
|
|
62
|
+
await this.bot.close();
|
|
63
|
+
}
|
|
64
|
+
catch (error)
|
|
65
|
+
{
|
|
66
|
+
console.error('Error when closing client:');
|
|
67
|
+
console.error(error);
|
|
68
|
+
}
|
|
69
|
+
process.exit();
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
if (options.exit)
|
|
73
|
+
{
|
|
74
|
+
process.exit();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
// Do something when app is closing
|
|
81
|
+
process.on('exit', exitHandler.bind(this, {}));
|
|
82
|
+
|
|
83
|
+
// Catches ctrl+c event
|
|
84
|
+
process.on('SIGINT', exitHandler.bind(this, { exit: true }));
|
|
85
|
+
|
|
86
|
+
// Catches "kill pid"
|
|
87
|
+
process.on('SIGUSR1', exitHandler.bind(this, { exit: true }));
|
|
88
|
+
process.on('SIGUSR2', exitHandler.bind(this, { exit: true }));
|
|
89
|
+
|
|
90
|
+
// Catches uncaught exceptions
|
|
91
|
+
process.on('uncaughtException', exitHandler.bind(this, { exit: true }));
|
|
92
|
+
|
|
93
|
+
// This will tell the bot to keep trying to teleport back to the 'stay' location.
|
|
94
|
+
// You can specify a region and position, such as:
|
|
95
|
+
// bot.stayPut(true, 'Izanagi', new nmv.Vector3([128, 128, 21]));
|
|
96
|
+
// Note that the 'stay' location will be updated if you request or accept a lure (a teleport).
|
|
97
|
+
// If no region is specified, it will be set to the region you log in to.
|
|
98
|
+
this.bot.stayPut(true, this.stayRegion, this.stayPosition);
|
|
99
|
+
|
|
100
|
+
await this.login();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
protected async onConnected(): Promise<void>
|
|
104
|
+
{
|
|
105
|
+
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
protected async login(): Promise<void>
|
|
109
|
+
{
|
|
110
|
+
if (this.isConnecting)
|
|
111
|
+
{
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
this.isConnecting = true;
|
|
115
|
+
try
|
|
116
|
+
{
|
|
117
|
+
if (this.reconnectTimer !== undefined)
|
|
118
|
+
{
|
|
119
|
+
clearInterval(this.reconnectTimer);
|
|
120
|
+
}
|
|
121
|
+
this.reconnectTimer = setInterval(this.reconnectCheck.bind(this), 60000);
|
|
122
|
+
|
|
123
|
+
console.log('Logging in..');
|
|
124
|
+
this.loginResponse = await this.bot.login();
|
|
125
|
+
|
|
126
|
+
console.log('Login complete');
|
|
127
|
+
|
|
128
|
+
// Establish circuit with region
|
|
129
|
+
await this.bot.connectToSim();
|
|
130
|
+
|
|
131
|
+
console.log('Waiting for event queue');
|
|
132
|
+
await this.bot.waitForEventQueue();
|
|
133
|
+
|
|
134
|
+
this.isConnected = true;
|
|
135
|
+
}
|
|
136
|
+
finally
|
|
137
|
+
{
|
|
138
|
+
this.isConnecting = false;
|
|
139
|
+
}
|
|
140
|
+
return this.connected();
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
private async reconnectCheck(): Promise<void>
|
|
144
|
+
{
|
|
145
|
+
if (!this.isConnected)
|
|
146
|
+
{
|
|
147
|
+
await this.login();
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
private async connected(): Promise<void>
|
|
152
|
+
{
|
|
153
|
+
this.bot.clientEvents.onDisconnected.subscribe((event) =>
|
|
154
|
+
{
|
|
155
|
+
if (event.requested)
|
|
156
|
+
{
|
|
157
|
+
if (this.reconnectTimer !== undefined)
|
|
158
|
+
{
|
|
159
|
+
clearInterval(this.reconnectTimer);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
this.isConnected = false;
|
|
163
|
+
console.log('Disconnected from simulator: ' + event.message);
|
|
164
|
+
});
|
|
165
|
+
await this.onConnected();
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// @ts-ignore
|
|
169
|
+
private async close(): Promise<void>
|
|
170
|
+
{
|
|
171
|
+
if (this.reconnectTimer !== undefined)
|
|
172
|
+
{
|
|
173
|
+
clearInterval(this.reconnectTimer);
|
|
174
|
+
this.reconnectTimer = undefined;
|
|
175
|
+
}
|
|
176
|
+
return this.bot.close();
|
|
177
|
+
}
|
|
178
|
+
}
|