2018-10-07 17:06:54 +01:00
// Here's a more modern example of how to use node-metaverse with async/await.
// Modern node.js required
require ( 'source-map-support' ) . install ( ) ;
2017-11-26 01:14:02 +00:00
const nmv = require ( '../dist/index' ) ;
2017-11-21 15:09:26 +00:00
const loginParameters = new nmv . LoginParameters ( ) ;
const parameters = require ( './loginParameters.json' ) ;
2017-12-15 19:13:45 +00:00
const uuid = require ( 'uuid' ) ;
2017-11-21 15:09:26 +00:00
loginParameters . firstName = parameters . firstName ;
loginParameters . lastName = parameters . lastName ;
loginParameters . password = parameters . password ;
2018-10-09 20:03:28 +01:00
loginParameters . start = parameters . start ;
2017-11-21 15:09:26 +00:00
2017-12-14 02:06:28 +00:00
//const options = nmv.BotOptionFlags.None;
// If you don't intend to use the object store (i.e you have no interest in inworld objects, textures, etc,
2018-10-12 17:31:14 +01:00
// using nmv.BotOptionFlags.LiteObjectStore will drastically reduce the footprint and CPU usage.
2017-12-14 02:06:28 +00:00
//
2018-10-12 17:31:14 +01:00
// The full object store has a full searchable rtree index, the lite does not.
//
// For the minimum footprint, use :
//
// const options = nmv.BotOptionFlags.LiteObjectStore | nmv.BotOptionFlags.StoreMyAttachmentsOnly;
const options = nmv . BotOptionFlags . None ;
2017-12-14 02:06:28 +00:00
const bot = new nmv . Bot ( loginParameters , options ) ;
2017-11-21 15:09:26 +00:00
2018-10-09 20:17:32 +01:00
// This will tell the bot to keep trying to teleport back to the 'stay' location.
// You can specify a region and position, such as:
2018-10-12 14:34:43 +01:00
// bot.stayPut(true, 'Izanagi', new nmv.Vector3([128, 128, 21]));
2018-10-09 20:17:32 +01:00
// Note that the 'stay' location will be updated if you request or accept a lure (a teleport).
// If no region is specified, it will be set to the region you log in to.
bot . stayPut ( true ) ;
2017-12-14 01:29:21 +00:00
let isConnected = false ;
2017-11-26 03:10:54 +00:00
2017-12-14 01:21:18 +00:00
const master = 'd1cd5b71-6209-4595-9bf0-771bf689ce00' ;
2017-12-15 19:13:45 +00:00
let loginResponse = null ;
2018-10-07 17:06:54 +01:00
bot . clientEvents . onLure . subscribe ( async ( lureEvent ) =>
2017-11-21 15:09:26 +00:00
{
2018-10-07 17:06:54 +01:00
try
2017-11-30 04:11:59 +00:00
{
2018-10-07 17:06:54 +01:00
const regionInfo = await bot . clientCommands . grid . getRegionMapInfo ( lureEvent . gridX / 256 , lureEvent . gridY / 256 ) ;
2017-12-14 01:21:18 +00:00
if ( lureEvent . from . toString ( ) === master )
2017-11-30 04:11:59 +00:00
{
2018-04-07 22:19:44 +01:00
console . log ( 'Accepting teleport lure to ' + regionInfo . block . name + ' (' + regionInfo . avatars . length + ' avatar' + ( ( regionInfo . avatars . length === 1 ) ? '' : 's' ) + ' present) from ' + lureEvent . fromName + ' with message: ' + lureEvent . lureMessage ) ;
2018-10-09 20:03:28 +01:00
bot . clientCommands . teleport . acceptTeleport ( lureEvent ) . then ( ( ) => { } ) . catch ( ( err ) => {
console . error ( 'Teleport error:' ) ;
console . error ( err ) ;
} ) ;
2017-12-14 01:21:18 +00:00
}
else
{
2018-04-07 22:19:44 +01:00
console . log ( 'Ignoring teleport lure to ' + regionInfo . block . name + ' (' + regionInfo . avatars . length + ' avatar' + ( ( regionInfo . avatars . length === 1 ) ? '' : 's' ) + ' present) from ' + lureEvent . fromName + ' with message: ' + lureEvent . lureMessage ) ;
2017-12-14 01:21:18 +00:00
}
2018-10-07 17:06:54 +01:00
}
catch ( error )
{
console . error ( "Failed to get region map info:" ) ;
console . error ( error ) ;
}
2017-12-14 01:21:18 +00:00
} ) ;
2017-11-30 04:11:59 +00:00
2017-12-14 01:21:18 +00:00
bot . clientEvents . onInstantMessage . subscribe ( ( IMEvent ) =>
{
if ( IMEvent . source === nmv . ChatSourceType . Agent )
{
if ( ! ( IMEvent . flags & nmv . InstantMessageEventFlags . startTyping || IMEvent . flags & nmv . InstantMessageEventFlags . finishTyping ) )
2017-12-13 19:55:08 +00:00
{
2018-10-07 17:06:54 +01:00
bot . clientCommands . comms . typeInstantMessage ( IMEvent . from , 'Thanks for the message! This account is a scripted agent (bot), so cannot reply to your query. Sorry!' ) . then ( ( ) => { } ) ;
2017-12-14 01:21:18 +00:00
}
}
} ) ;
2017-11-30 04:11:59 +00:00
2017-12-19 19:59:06 +00:00
bot . clientEvents . onFriendRequest . subscribe ( ( event ) =>
{
if ( event . from . toString ( ) === master )
{
console . log ( "Accepting friend request from " + event . fromName ) ;
2018-10-07 17:06:54 +01:00
bot . clientCommands . comms . acceptFriendRequest ( event ) . then ( ( ) => { } ) ;
2017-12-19 19:59:06 +00:00
}
else
{
console . log ( "Rejecting friend request from " + event . fromName ) ;
2018-10-07 17:06:54 +01:00
bot . clientCommands . comms . rejectFriendRequest ( event ) . then ( ( ) => { } ) ;
2017-12-19 19:59:06 +00:00
}
} ) ;
bot . clientEvents . onInventoryOffered . subscribe ( ( event ) =>
{
if ( event . from . toString ( ) === master )
{
console . log ( "Accepting inventory offer from " + event . fromName ) ;
2018-10-07 17:06:54 +01:00
bot . clientCommands . comms . acceptInventoryOffer ( event ) . then ( ( ) => { } ) ;
2017-12-19 19:59:06 +00:00
}
else
{
console . log ( "Rejecting inventory offer from " + event . fromName ) ;
2018-10-07 17:06:54 +01:00
bot . clientCommands . comms . rejectInventoryOffer ( event ) . then ( ( ) => { } ) ;
2017-12-19 19:59:06 +00:00
}
} ) ;
2017-12-14 01:21:18 +00:00
bot . clientEvents . onDisconnected . subscribe ( ( DisconnectEvent ) =>
{
2017-12-14 01:29:21 +00:00
isConnected = false ;
2017-12-14 01:21:18 +00:00
console . log ( "Disconnected from simulator: " + DisconnectEvent . message ) ;
if ( ! DisconnectEvent . requested )
{
setTimeout ( ( ) =>
2017-12-13 19:55:08 +00:00
{
2017-12-14 01:21:18 +00:00
console . log ( "Reconnecting" ) ;
2018-10-07 17:06:54 +01:00
connect ( ) . then ( ( ) => { } ) ;
2017-12-14 01:21:18 +00:00
} , 5000 )
}
} ) ;
2017-12-15 19:13:45 +00:00
let pings = { } ;
2018-10-07 17:06:54 +01:00
bot . clientEvents . onGroupChat . subscribe ( async ( GroupChatEvent ) =>
2017-12-14 18:22:41 +00:00
{
2018-10-07 17:06:54 +01:00
console . log ( "Group chat: " + GroupChatEvent . fromName + ': ' + GroupChatEvent . message ) ;
if ( GroupChatEvent . message === '!ping' )
{
let ping = uuid . v4 ( ) ;
pings [ ping ] = Math . floor ( new Date ( ) . getTime ( ) ) ;
try
{
const memberCount = await bot . clientCommands . comms . sendGroupMessage ( GroupChatEvent . groupID , 'ping ' + ping ) ;
console . log ( 'Group message sent to ' + memberCount + ' members' ) ;
}
catch ( error )
{
console . error ( 'Failed to send group message:' ) ;
console . error ( error ) ;
}
}
else if ( GroupChatEvent . from . toString ( ) === loginResponse . agent . agentID . toString ( ) )
{
if ( GroupChatEvent . message . substr ( 0 , 5 ) === 'ping ' )
{
const pingID = GroupChatEvent . message . substr ( 5 ) ;
if ( pings [ pingID ] )
{
console . log ( "found ping" ) ;
const time = ( new Date ( ) . getTime ( ) ) - pings [ pingID ] ;
delete pings [ pingID ] ;
bot . clientCommands . comms . sendGroupMessage ( GroupChatEvent . groupID , 'Chat lag: ' + time + 'ms' ) . then ( ( ) => { } ) ;
}
else
{
console . log ( "ping not found |" + pingID + "|" ) ;
}
}
}
2017-12-14 18:22:41 +00:00
} ) ;
2018-12-22 12:05:17 +11:00
bot . clientEvents . onGroupNotice . subscribe ( async ( GroupNoticeEvent ) =>
{
2018-12-22 12:13:04 +11:00
// Get group name
const groupProfile = await bot . clientCommands . group . getGroupProfile ( GroupNoticeEvent . groupID ) ;
console . log ( 'Group notice from ' + GroupNoticeEvent . fromName + ' (' + GroupNoticeEvent . from + '), from group ' + groupProfile . Name + ' (' + GroupNoticeEvent . groupID + ')' ) ;
2018-12-22 12:05:17 +11:00
console . log ( 'Subject: ' + GroupNoticeEvent . subject ) ;
console . log ( 'Message: ' + GroupNoticeEvent . message ) ;
} ) ;
2018-10-07 17:06:54 +01:00
bot . clientEvents . onGroupInvite . subscribe ( async ( GroupInviteEvent ) =>
2017-12-14 18:22:41 +00:00
{
console . log ( 'Group invite from ' + GroupInviteEvent . fromName + ': ' + GroupInviteEvent . message ) ;
//Resolve avatar key
2018-10-07 17:06:54 +01:00
try
2017-12-14 18:22:41 +00:00
{
2018-10-12 14:34:43 +01:00
const key = await bot . clientCommands . grid . avatarName2Key ( GroupInviteEvent . fromName ) ;
2017-12-14 18:22:41 +00:00
if ( key . toString ( ) === master )
{
console . log ( 'Accepting' ) ;
2018-10-07 17:06:54 +01:00
bot . clientCommands . group . acceptGroupInvite ( GroupInviteEvent ) . then ( ( ) => { } ) ;
2017-12-14 18:22:41 +00:00
}
else
{
console . log ( 'Unauthorised - rejecting' ) ;
2018-10-07 17:06:54 +01:00
bot . clientCommands . group . rejectGroupInvite ( GroupInviteEvent ) . then ( ( ) => { } ) ;
2017-12-14 18:22:41 +00:00
}
2018-10-07 17:06:54 +01:00
}
catch ( error )
2017-12-14 18:22:41 +00:00
{
2018-10-07 17:06:54 +01:00
console . error ( 'Failed to respond to group invite:' ) ;
console . error ( error ) ;
}
2017-12-14 18:22:41 +00:00
} ) ;
2017-12-19 20:25:42 +00:00
bot . clientEvents . onFriendResponse . subscribe ( ( response ) =>
{
if ( response . accepted )
{
console . log ( response . fromName + ' accepted your friend request' ) ;
}
else
{
console . log ( response . fromName + ' declined your friend request' ) ;
}
} ) ;
2018-10-07 17:06:54 +01:00
async function connect ( )
2017-12-14 01:21:18 +00:00
{
2018-10-07 17:06:54 +01:00
try
2017-12-14 01:21:18 +00:00
{
2018-10-07 17:06:54 +01:00
console . log ( "Logging in.." ) ;
loginResponse = await bot . login ( ) ;
2017-12-14 01:21:18 +00:00
console . log ( "Login complete" ) ;
2017-12-13 19:55:08 +00:00
2017-12-14 01:29:21 +00:00
//Establish circuit with region
2018-10-07 17:06:54 +01:00
await bot . connectToSim ( ) ;
2017-12-15 19:27:12 +00:00
console . log ( "Connected to simulator" ) ;
2017-12-14 01:29:21 +00:00
isConnected = true ;
2017-12-13 19:55:08 +00:00
// Do some stuff
//bot.clientCommands.comms.typeLocalMessage('Never fear, I am here!', 2000);
//bot.clientCommands.group.sendGroupNotice('503e8ef6-e119-ff5e-2524-24f290dd3867', 'Test', 'testy testy test');
2017-12-15 21:28:45 +00:00
// Group invite example
// Just omit the role parameter for "everyone" role
//
// bot.clientCommands.group.sendGroupInvite("c6424e05-6e2c-fb03-220b-ca7904d11e04", "d1cd5b71-6209-4595-9bf0-771bf689ce00");
// Advanced group invite example
//
// Retrieve group roles
const userToInvite = new nmv . UUID ( "d1cd5b71-6209-4595-9bf0-771bf689ce00" ) ;
2017-12-19 23:43:00 +00:00
const groupID = new nmv . UUID ( "c6424e05-6e2c-fb03-220b-ca7904d11e04" ) ;
2017-12-15 21:28:45 +00:00
2018-10-07 17:06:54 +01:00
// If you want to wait here for the request to be acknowledged, you can add "await"
2018-10-12 14:34:43 +01:00
bot . clientCommands . friends . sendFriendRequest ( master , 'Be friends with me?' ) . then ( ( ) => { } ) ;
2018-10-07 17:06:54 +01:00
const folders = bot . clientCommands . inventory . getInventoryRoot ( ) . getChildFolders ( ) ;
folders . forEach ( ( folder ) =>
2017-12-15 21:28:45 +00:00
{
2018-10-07 17:06:54 +01:00
console . log ( 'Top level folder: ' + folder . name ) ;
folder . populate ( ) . then ( ( ) => { } ) ;
} ) ;
const roles = await bot . clientCommands . group . getGroupRoles ( groupID ) ;
roles . forEach ( async ( role ) =>
{
if ( role . Name === 'Officers' )
2017-12-15 21:28:45 +00:00
{
2018-10-07 17:06:54 +01:00
// IMPORTANT: IN PRODUCTION, IT IS HIGHLY RECOMMENDED TO CACHE THIS LIST.
//
try
2017-12-15 21:28:45 +00:00
{
2018-10-07 17:06:54 +01:00
const members = await bot . clientCommands . group . getMemberList ( groupID ) ;
let found = true ;
members . forEach ( ( member ) =>
2017-12-15 21:28:45 +00:00
{
2018-10-07 17:06:54 +01:00
if ( member . AgentID . toString ( ) === userToInvite . toString ( ) )
2017-12-15 21:28:45 +00:00
{
2018-10-07 17:06:54 +01:00
found = true ;
2017-12-15 21:28:45 +00:00
}
} ) ;
2018-10-07 17:06:54 +01:00
if ( found )
{
console . log ( "User already in group, skipping invite" ) ;
}
else
{
bot . clientCommands . group . sendGroupInvite ( groupID , userToInvite , role . RoleID ) . then ( ( ) => { } ) ;
}
}
catch ( error )
{
console . error ( 'Error retrieving member list for group invite' ) ;
2017-12-15 21:28:45 +00:00
}
2018-10-07 17:06:54 +01:00
}
2017-12-15 21:28:45 +00:00
} ) ;
2018-10-07 17:06:54 +01:00
await bot . waitForEventQueue ( ) ;
try
2017-12-16 06:42:41 +00:00
{
2018-10-12 14:34:43 +01:00
// Get map location of Casper Warden (should (hopefully)! fail if you don't have map rights on me..
const regionLocation = await bot . clientCommands . friends . getFriendMapLocation ( 'd1cd5b71-6209-4595-9bf0-771bf689ce00' ) ;
console . log ( 'Casper is in ' + regionLocation . regionName + ' at <' + regionLocation . localX + ', ' + regionLocation . localY + '> and there are ' + regionLocation . avatars . length + ' other avatars there too! You stalker!' ) ;
2018-10-07 17:06:54 +01:00
}
catch ( error )
2017-12-19 23:43:00 +00:00
{
2018-10-19 16:43:15 +01:00
console . log ( 'Map location request failed. You probably do not have map rights on Casper, or he is offline.' ) ;
2018-10-07 17:06:54 +01:00
}
2018-10-12 14:34:43 +01:00
2018-10-19 16:43:15 +01:00
// By default, camera view distance is set to 1, to minimise memory and bandwidth consumption.
// This algorithm will slowly drag the camera up into the sky, scanning for objects.
let height = 64 ;
let lastObjects = 0 ;
bot . clientCommands . agent . setCamera (
new nmv . Vector3 ( [ 128 , 128 , height ] ) ,
new nmv . Vector3 ( [ 128 , 128 , 0 ] ) ,
2018-10-20 14:32:33 +01:00
256 ,
2018-10-19 16:43:15 +01:00
new nmv . Vector3 ( [ - 1.0 , 0 , 0 ] ) ,
new nmv . Vector3 ( [ 0.0 , 1.0 , 0 ] ) ) ;
2020-01-05 19:05:52 +00:00
// Get group member list
try
{
const memberList = await bot . clientCommands . group . getMemberList ( 'f0466f71-abf4-1559-db93-50352d13ae74' ) ;
}
catch ( error )
{
// Probably access denied
console . error ( error ) ;
}
// Get group ban list
try
{
const banList = await bot . clientCommands . group . getBanList ( 'f0466f71-abf4-1559-db93-50352d13ae74' ) ;
}
catch ( error )
{
// Probably access denied
console . error ( error ) ;
}
// Moderate group member
try
{
const groupKey = '4b35083d-b51a-a148-c400-6f1038a5589e' ;
const avatarKey = '4300b952-d20e-4aa5-b3d6-d2e4d675880d' ;
// Note this will start a new group chat session if one does not already exist
await bot . clientCommands . comms . moderateGroupChat ( groupKey , avatarKey , true , true ) ;
// Now, the group mute stuff is often pretty useless because an avatar can just leave the session and re-join.
// Let's enforce it a little better.
const groupChatSubscriber = bot . clientEvents . onGroupChatAgentListUpdate . subscribe ( ( event ) =>
{
if ( event . groupID . toString ( ) === groupKey && event . agentID . toString ( ) === avatarKey && event . entered )
{
bot . clientCommands . comms . moderateGroupChat ( groupKey , avatarKey , true , true ) . then ( ( ) =>
{
console . log ( 'Re-enforced mute on ' + avatarKey ) ;
} ) . catch ( ( err ) =>
{
console . error ( err ) ;
} ) ;
}
} ) ;
// Send a group message
await bot . clientCommands . comms . sendGroupMessage ( groupKey , 'Test' ) ;
}
catch ( error )
{
console . error ( error ) ;
}
2018-10-12 17:31:14 +01:00
2018-10-12 14:34:43 +01:00
//await bot.clientCommands.friends.grantFriendRights('d1cd5b71-6209-4595-9bf0-771bf689ce00', nmv.RightsFlags.CanModifyObjects | nmv.RightsFlags.CanSeeOnline | nmv.RightsFlags.CanSeeOnMap );
2019-12-31 02:23:30 +00:00
const parcelInMiddle = await bot . clientCommands . region . getParcelAt ( 128 , 128 ) ;
console . log ( 'Parcel at 128x128 is ' + parcelInMiddle . Name ) ;
const parcels = await bot . clientCommands . region . getParcels ( ) ;
console . log ( 'Parcels on region:' ) ;
console . log ( '========================' ) ;
for ( const p of parcels )
{
console . log ( p . Name ) ;
}
console . log ( '========================' ) ;
2018-10-07 17:06:54 +01:00
}
catch ( error )
2017-12-13 19:55:08 +00:00
{
2017-12-14 01:29:21 +00:00
isConnected = false ;
2017-12-13 19:55:08 +00:00
console . log ( "Error:" ) ;
console . error ( error ) ;
setTimeout ( ( ) =>
{
2018-10-07 17:06:54 +01:00
connect ( ) . then ( ( ) => { } ) ;
2017-12-13 19:55:08 +00:00
} , 5000 )
2018-10-07 17:06:54 +01:00
}
2017-12-13 19:55:08 +00:00
}
2017-11-21 15:09:26 +00:00
2018-10-07 17:06:54 +01:00
try
{
connect ( ) . then ( ( ) => { } ) ;
}
catch ( error )
{
console . error ( 'Connection failure: ' ) ;
console . log ( error ) ;
}
2017-12-14 01:29:21 +00:00
2018-10-07 17:06:54 +01:00
async function exitHandler ( options , err )
2017-12-14 01:29:21 +00:00
{
2017-12-14 18:22:41 +00:00
if ( err )
{
console . log ( err . stack ) ;
}
2017-12-14 01:29:21 +00:00
if ( isConnected )
{
console . log ( "Disconnecting" ) ;
2018-10-07 17:06:54 +01:00
try
2017-12-14 01:29:21 +00:00
{
2018-10-07 17:06:54 +01:00
await bot . close ( ) ;
}
catch ( error )
{
console . error ( 'Error when closing client:' ) ;
console . error ( error ) ;
}
process . exit ( ) ;
2017-12-14 01:29:21 +00:00
return ;
}
if ( options . exit )
{
process . exit ( ) ;
}
}
//do something when app is closing
process . on ( 'exit' , exitHandler . bind ( null , { } ) ) ;
//catches ctrl+c event
process . on ( 'SIGINT' , exitHandler . bind ( null , { exit : true } ) ) ;
2018-10-07 17:06:54 +01:00
// catches "kill pid"
2017-12-14 01:29:21 +00:00
process . on ( 'SIGUSR1' , exitHandler . bind ( null , { exit : true } ) ) ;
process . on ( 'SIGUSR2' , exitHandler . bind ( null , { exit : true } ) ) ;
//catches uncaught exceptions
2018-12-22 12:05:17 +11:00
process . on ( 'uncaughtException' , exitHandler . bind ( null , { exit : true } ) ) ;