yahyatesting-0
v1.0.10
Published
Enterprise WebSocket infrastructure for Highrise featuring spatial intelligence systems, memory-optimized architecture, and production-grade reliability for scalable application development
Maintainers
Readme
Highrise Bot SDK - Unofficial WebSocket SDK for Highrise Bot Development
Highrise Bot SDK (highrise-core) is a production-ready TypeScript/JavaScript SDK for creating advanced bots and automation tools for the Highrise social platform. Built with WebSocket connectivity, spatial intelligence, and memory-optimized architecture, this SDK provides enterprise-grade reliability for scalable bot development.
📖 Table of Contents
🚀 Features
Core Capabilities
- Real-time WebSocket Connection - Stable connection with auto-reconnect
- Complete Bot API Coverage - All official Highrise bot endpoints implemented
- Advanced Caching System - Efficient user position tracking and spatial queries and more upcoming
- Comprehensive Event Handling - All major Highrise events supported
- Web API Integration - Access to user, room, item, post, grab data
Performance Highlights
- 86%+ Memory Reduction in position tracking using binary encoding
- Sub-millisecond spatial queries for user location
- Automatic resource cleanup and connection management
- Object pooling for reduced garbage collection
- 98% Memory leak free
📦 Installation
npm install highrise-core🎯 Quick Start
Basic Bot Setup
const { Highrise } = require('highrise-core');
// Create bot instance
const bot = new Highrise(
['ChatEvent', 'UserJoinedEvent', 'UserMovedEvent'], // Events to listen for
{
LoggerOptions: {
showTimestamp: true,
showMethodName: true,
colors: true
},
autoReconnect: true,
reconnectDelay: 5000
}
);
// Event handlers
bot.on('Ready', (metadata) => {
console.log(`Bot connected to room: ${metadata.room.room_name}`);
});
bot.on('Chat', async (user, message) => {
if (message === '!hello') {
await bot.message.send(`Hello ${user.username}! 👋`);
}
});
bot.on('UserJoined', async (user) => {
await bot.message.send(`Welcome to the room, ${user.username}! 🎉`);
});
// Connect to Highrise
bot.login('your_64_character_bot_token', 'your_24_character_room_id');🔧 Core Features
Movement & Positioning
// Make the bot walk to coordinates
await bot.player.walk(10, 0, 5, 'FrontRight');
// Teleport users
await bot.player.teleport('user_id', 15, 0, 10, 'BackLeft');
// Make the bot sit on furniture
await bot.player.sit('entity_id', 0);Advanced Spatial Queries
// Get players in a 8x8 square area
const playersInArea = bot.cache.position.getPlayersInSquare(
{ x: 10, y: 0, z: 10 },
8
);
// Find closest player
const closestPlayer = bot.cache.position.getClosestPlayer({ x: 0, z: 0 });
// Get players within 5 units radius (sorted by distance)
const nearbyPlayers = bot.cache.position.getPlayersInCircle(
{ x: 10, z: 10 },
5
);
// Check if specific user is in area
const isInVIP = bot.cache.position.isPlayerInRectangle('user_id',
{
c1: { x: 20, z: 20 }, // Top-right
c2: { x: 25, z: 20 }, // Top-left
c3: { x: 25, z: 25 }, // bottom-right
c4: { x: 20, z: 25 } // bottom-left
}
);Communication
// Room messages
await bot.message.send("Hello everyone!");
// Private whispers
await bot.whisper.send("user_id", "This is a private message!");
// Direct messages
await bot.direct.send("conversation_id", "Direct message content");
// Send room invites via DM
await bot.direct.invite("conversation_id", { room_id: "target_room_id" });
// Send world invites via DM
await bot.direct.invite("conversation_id", { world_id: "target_world_id" });Moderation
// Basic moderation
await bot.player.moderation.kick("user_id");
await bot.player.moderation.mute("user_id", 5 * 60 * 1000); // 5 minutes (default)
await bot.player.moderation.ban("user_id", 60 * 60 * 1000); // 1 hour (default)
// Room privilege management
await bot.room.moderator.add("user_id");
await bot.room.designer.add("user_id");Economy & Items
// Check wallet
const wallet = await bot.inventory.wallet.get();
console.log(`Gold: ${wallet.gold}, Boosts: ${wallet.boost_tokens}`);
// Send tips
await bot.player.tip("user_id", 100); // 100 gold bars (default: 1)
// Buy bot items
await bot.inventory.item.buy("item_id");
// Set bot outfit
await bot.inventory.set([
{
type: 'clothing',
amount: 1,
id: 'shirt-n_cooltshirt',
account_bound: false,
active_palette: null
}
]);
// set outfit back to default
await bot.inventory.set();🌐 Web API Integration
// User information
const user = await bot.webapi.user.get("username_or_id");
console.log(`${user.username} - ${user.followers} followers`);
// Room information
const room = await bot.webapi.room.get("room_id");
console.log(`${room.name} - ${room.connectedUsers} users online`);
// Item catalog
const items = await bot.webapi.item.search({ query: "dragon", limit: 10 });
items.items.forEach(item => {
console.log(`${item.name} - ${item.pricing.gems} gems`);
});
// Posts and social
const posts = await bot.webapi.post.getByAuthor("user_id");📊 Performance Metrics
The SDK is optimized for high-performance scenarios:
- Movement Cache: Tracks 1000+ users with ~5KB memory usage
- Spatial Queries: Process 10,000+ positions in <1ms
- WebSocket: Handles 100+ events per second efficiently
- Memory: 80-95% reduction in position storage through binary encoding
📊 Metrics & Monitoring
Access real-time bot performance metrics with bot.getMetrics().
Get Metrics Object
const metrics = bot.getMetrics();
console.log(metrics);
// Returns:
{
uptime: '2h 15m',
connected: true,
room: "Unfairly's room",
messages: 1500,
events: 300,
errors: 2,
cache: {
users: 45,
memory: '5.2 KB',
active: 12,
changes: 28
},
pendingReq: {
fireForget: 3,
reqRes: 1
}
}Display Metrics:
// Simple display
const m = bot.getMetrics();
console.log(`📊 Bot Metrics:`);
console.log(`├─ Room: ${m.room}`);
console.log(`├─ Uptime: ${m.uptime}`);
console.log(`├─ Status: ${m.connected ? '✅ Connected' : '❌ Disconnected'}`);
console.log(`├─ Messages: ${m.messages}`);
console.log(`├─ Events: ${m.events}`);
console.log(`├─ Errors: ${m.errors}`);
console.log(`├─ Cache: ${m.cache.users} users (${m.cache.active} active)`);
console.log(`└─ Memory: ${m.cache.memory} used`);
// Auto-update every 30s
setInterval(() => {
const metrics = bot.getMetrics();
console.log(`[${new Date().toLocaleTimeString()}] ${metrics.room} - ${metrics.uptime} - ${metrics.messages} msgs`);
}, 30000);🔄 Await System
The await system allows your bot to wait for specific events with powerful filtering capabilities with unique user tracking to prevent spam and ensure fairness.
🎯 Basic Usage
Wait for a Single Chat Message
// Wait for any user to type !start
const results = await bot.await.chat(
(user, message) => message === '!start',
30000, // 30 second timeout
1, // Collect 1 match
false // Allow multiple from same user (default)
);
if (results.length > 0) {
const [[user, message]] = results;
await bot.message.send(`Game started by ${user.username}! 🎮`);
}Wait for a Whisper
// Wait for first help request from each user
const helpRequests = await bot.await.whisper(
(user, message) => message.includes('help'),
15000,
10, // Collect up to 10 requests
true // Only one per user
);
if (helpRequests.length > 0) {
const [[user, message]] = helpRequests;
await bot.whisper.send(user.id, "I'm here to help! What do you need?");
}Wait for a Direct Message
// Wait for unique confirmations
const confirmations = await bot.await.direct(
(user, message, conversation) => message === '!confirm',
60000,
5, // Up to 5 confirmations
true // One confirmation per user
);
if (confirmations.length > 0) {
const [[user, message, conversation]] = confirmations;
await bot.direct.send(conversation.id, "Order confirmed! ✅");
}Wait for a Tip
// Wait for first-time donors only
const tips = await bot.await.tip(
(sender, receiver, currency) => receiver.id === bot.info.user.id,
120000,
20, // Up to 20 donors
true // Only count each user's first tip
);
if (tips.length > 0) {
const [[sender, receiver, currency]] = tips;
await bot.message.send(`Thank you ${sender.username} for your first donation! 💰`);
}Wait for Player Movement
// Wait for first-time visitors to area
const entrants = await bot.await.movement(
(user, position, anchor) =>
position.x >= 10 && position.x <= 15 &&
position.z >= 10 && position.z <= 15,
60000,
30, // Up to 30 unique visitors
true // Only track first visit per user
);
if (entrants.length > 0) {
const [[user, position, anchor]] = entrants;
await bot.message.send(`Welcome to the dance floor, ${user.username}! First time here? 💃`);
}🚀 Advanced Usage
Chat - Fair Voting System
// One vote per user (no cheating!)
await bot.message.send("Vote for your favorite: !pizza, !burger, or !sushi");
const votes = await bot.await.chat(
(user, message) => ['!pizza', '!burger', '!sushi'].includes(message),
45000, // 45 seconds
100, // Collect up to 100 votes
true // One vote per user - prevents spamming!
);
// Process results - each user counted only once
const voteCount = {
pizza: votes.filter(([user, message]) => message === '!pizza').length,
burger: votes.filter(([user, message]) => message === '!burger').length,
sushi: votes.filter(([user, message]) => message === '!sushi').length
};
const winner = Object.keys(voteCount).reduce((a, b) => voteCount[a] > voteCount[b] ? a : b);
await bot.message.send(`The winner is ${winner} with ${voteCount[winner]} unique votes! 🏆`);Whisper - Fair Moderation Applications
// One application per user
await bot.message.send("Whisper me '!mod' to apply for moderator");
const modApplications = await bot.await.whisper(
(user, message) => message === '!mod',
120000, // 2 minutes
50, // Up to 50 applications
true // Prevent users from applying multiple times
);
// Process each unique applicant
for (const [user, message] of modApplications) {
const isEligible = await checkUserEligibility(user.id);
if (isEligible) {
await bot.whisper.send(user.id, "You've been approved as moderator! 🛡️");
await bot.room.moderator.add(user.id);
} else {
await bot.whisper.send(user.id, "Sorry, you don't meet the requirements yet.");
}
}Direct - Unique Support Tickets
// One support ticket per user
const supportTickets = await bot.await.direct(
(user, message, conversation) =>
message.includes('help') || message.includes('support') || message.includes('issue'),
300000, // 5 minutes
20, // Handle 20 unique tickets
true // One ticket per user - prevents spam
);
// Create tickets for each unique user
for (const [user, message, conversation] of supportTickets) {
const ticketId = createSupportTicket(user.id, message);
await bot.direct.send(conversation.id,
`Support ticket #${ticketId} created! We'll assist you shortly. ⏱️`
);
// Assign to available support agent
assignTicketToAgent(ticketId, conversation.id);
}Tip - Unique Donor Fundraiser
// Track unique donors only
await bot.message.send("🎗️ Fundraiser started! First donation from each user counts!");
const uniqueDonors = await bot.await.tip(
(sender, receiver, currency) =>
receiver.id === bot.info.user.id && currency.amount >= 50,
600000, // 10 minutes
200, // Track up to 200 unique donors
true // Only count first donation from each user
);
// Calculate and announce totals
let totalRaised = 0;
uniqueDonors.forEach(([sender, receiver, currency]) => {
totalRaised += currency.amount;
// Acknowledge unique donors
if (currency.amount >= 500) {
bot.message.send(`🎉 HUGE thanks to ${sender.username} for first-time donation!`);
}
});
await bot.message.send(
`🏁 Fundraiser complete! ${uniqueDonors.length} unique donors raised ${totalRaised} gold! Thank you all!`
);Movement - First-Time Achievement System
// Award achievements for first-time discoveries
const treasureSpots = [
{ x: 5, z: 5, name: "Ancient Ruins", reward: 100 },
{ x: 15, z: 20, name: "Crystal Cave", reward: 150 },
{ x: 25, z: 10, name: "Dragon's Lair", reward: 200 }
];
await bot.message.send("🔍 Treasure hunt! Find hidden spots for one-time rewards!");
const firstDiscoveries = await bot.await.movement(
(user, position, anchor) => {
return treasureSpots.some(spot =>
Math.abs(position.x - spot.x) < 2 &&
Math.abs(position.z - spot.z) < 2
);
},
300000, // 5 minutes
50, // Up to 50 unique discoverers
true // Only first discovery per user per spot
);
// Award first-time discoverers
for (const [user, position, anchor] of firstDiscoveries) {
const treasure = treasureSpots.find(spot =>
Math.abs(position.x - spot.x) < 2 &&
Math.abs(position.z - spot.z) < 2
);
await bot.message.send(
`🏆 ${user.username} discovered ${treasure.name} for the first time! +${treasure.reward} gold!`
);
await bot.player.tip(user.id, treasure.reward);
// Keep spot available for other users
}🎮 Complex Scenarios
Multi-Stage Registration (Unique Users)
// Complete registration - one per user
await bot.message.send("Type !register to start (one registration per user)");
const starters = await bot.await.chat(
(user, message) => message === '!register',
30000,
100, // Up to 100 registrations
true // One registration per user
);
if (starters.length > 0) {
for (const [user, message] of starters) {
// Each unique user gets personalized registration
await bot.whisper.send(user.id, "What username should we use for your account?");
const usernameResponse = await bot.await.whisper(
(u, msg) => u.id === user.id && msg.length >= 3,
60000,
1,
false // Allow multiple responses from same user
);
if (usernameResponse.length > 0) {
const [[u, preferredUsername]] = usernameResponse;
// Complete registration for this unique user
await completeRegistration(user.id, preferredUsername);
await bot.whisper.send(user.id, "Registration complete! Welcome! 🎉");
}
}
}Real-time Event Coordination (Unique Participants)
// Coordinate unique users for an event
await bot.message.send("🎪 Event starting! Stand in circle AND type !ready");
const [circleUsers, readyUsers] = await Promise.all([
// Wait for unique users in circle
bot.await.movement(
(user, position, anchor) =>
position.x >= 8 && position.x <= 12 &&
position.z >= 8 && position.z <= 12,
60000,
50,
true // Unique users only
),
// Wait for unique users typing ready
bot.await.chat(
(user, message) => message === '!ready',
60000,
50,
true // One ready per user
)
]);
// Find unique users who did both
const uniqueParticipants = circleUsers.filter(([user1]) =>
readyUsers.some(([user2]) => user2.id === user1.id)
);
await bot.message.send(
`${uniqueParticipants.length} unique players are ready! Starting event... 🚀`
);Advanced Movement Tracking (Unique Patterns)
// Track unique users with movement patterns
const movementPatterns = await bot.await.movement(
(user, position, anchor) => {
const previousData = bot.cache.position.get(user.id);
if (!previousData) return false;
const prevPos = previousData.position;
const distance = Math.sqrt(
Math.pow(position.x - prevPos.x, 2) +
Math.pow(position.z - prevPos.z, 2)
);
// Detect first teleport from each user
const isFirstTeleport = distance > 20;
// Detect first sitting/standing transition per user
const wasSitting = previousData.anchor !== null;
const isSitting = anchor !== null;
const firstPostureChange = wasSitting !== isSitting;
return isFirstTeleport || firstPostureChange;
},
120000,
30, // Track 30 unique users
true // Only track first occurrence per user
);
// Analyze unique movement patterns
movementPatterns.forEach(([user, position, anchor]) => {
if (anchor) {
bot.utils.logger.info('Movement', `${user.username} sat down for first time`);
} else {
bot.utils.logger.info('Movement', `${user.username} stood up for first time`);
}
});💡 Pro Tips
1. Always Use Unique Users for Fairness
// Fair system - one entry per user
const entries = await bot.await.chat(
filter,
timeout,
max,
true // Critical for contests, voting, rewards
);2. Combine Unique & Non-Unique Await
// Collect first response from each user, then allow follow-ups
const firstResponses = await bot.await.chat(filter1, 30000, 10, true);
const followUpResponses = await bot.await.chat(filter2, 30000, 20, false);3. Smart Timeouts for Unique Collections
// Longer timeout when waiting for many unique users
const responses = await bot.await.direct(
filter,
120000, // 2 minutes for 20 unique users
20,
true
);4. Handle Unique Collections Gracefully
try {
const uniqueResponses = await bot.await.whisper(
(user, message) => message === '!join',
60000,
50,
true // Unique users only
);
if (uniqueResponses.length > 0) {
await bot.message.send(`${uniqueResponses.length} unique users joined!`);
} else {
await bot.message.send("No new users joined. 😔");
}
} catch (error) {
bot.utils.logger.error('Await', 'Unique await failed', error);
}5. Track User Participation
// Keep track of which users have participated
const participatedUsers = new Set();
bot.on('Chat', async (user, message) => {
if (message === '!play' && !participatedUsers.has(user.id)) {
participatedUsers.add(user.id);
await bot.message.send(`${user.username} joined for the first time!`);
}
});The enhanced await system with uniqueUsers parameter transforms your bot from simple event collection into a fair, spam-resistant system perfect for games, contests, voting, and any scenario where you need to track user participation uniquely!
🔌 Event System
Available Events
bot.on('Ready', (metadata) => {
// Bot connected and ready
});
bot.on('Chat', (user, message) => {
// Room message received
});
bot.on('Whisper', (user, message) => {
// Private whisper received
});
bot.on('Movement', (user, position, anchor) => {
// User moved
});
bot.on('UserJoined', (user, position) => {
// User entered the room
});
bot.on('UserLeft', (user) => {
// User left the room
});
bot.on('Direct', (user, message, conversation) => {
// Direct message received
});
bot.on('Tip', (sender, receiver, currency) => {
// Tip received or sent
});
bot.on('Moderation', (moderator, target, action) => {
// Moderation action occurred
});⚙️ Configuration
Bot Options
const bot = new Highrise(events, {
LoggerOptions: {
showTimestamp: true, // Show timestamps in logs
showMethodName: true, // Show method names in logs
colors: true // Color-coded log output
},
autoReconnect: true, // Auto-reconnect on disconnect
reconnectDelay: 5000 // Delay between reconnect attempts (ms)
});Sender Configuration
// Configure request timeouts and retries
bot.configureSenders({
defaultTimeout: 10000, // 10 second timeout
maxRetries: 3, // Maximum retry attempts
retryDelay: 100 // Delay between retries (ms)
});🛠️ Advanced Usage
Custom Event Handlers
// Register custom event processing
bot.on('Movement', async (user, position) => {
const isInVIP = bot.cache.position.isPlayerInRectangle(user.id,
{
c1: { x: 20, z: 20 }, // Top-right
c2: { x: 25, z: 20 }, // Top-left
c3: { x: 25, z: 25 }, // bottom-right
c4: { x: 20, z: 25 } // bottom-left
}
);
// Custom movement logic
if (isInVIP) {
await bot.whisper.send(user.id, "You're in the VIP area! 🎉");
}
});Rate Limiting
// Implement custom rate limiting
class RateLimitedBot {
constructor(bot) {
this.bot = bot;
this.lastMessage = 0;
}
async sendMessage(message) {
const now = Date.now();
if (now - this.lastMessage < 1000) {
await bot.utils.sleep(1000 - (now - this.lastMessage));
}
this.lastMessage = Date.now();
return this.bot.message.send(message);
}
}📈 Real-World Example
Welcome Bot
const { Highrise } = require('highrise-core');
const bot = new Highrise(['ChatEvent', 'UserJoinedEvent', 'UserMovedEvent']);
// Track new users
const newUsers = new Set();
bot.on('Ready', () => {
console.log('Welcome bot is online!');
});
bot.on('UserJoined', async (user) => {
newUsers.add(user.id);
if (newUsers.has(user.id)) {
await bot.message.send(`Welcome ${user.username}! Enjoy your stay! 🏠`);
newUsers.delete(user.id);
}
});
bot.on('UserLeft', (user) => {
newUsers.delete(user.id);
});
bot.on('Chat', async (user, message) => {
// Remove from new users if they chat
newUsers.delete(user.id);
// Simple commands
if (message === '!help') {
await bot.message.send('Available commands: !help, !info, !position');
}
if (message === '!position') {
const position = await bot.room.users.position(user.id);
await bot.whisper.send(user.id, `Your position: ${position.x}, ${position.y}, ${position.z}`);
}
});
bot.login('your_bot_token', 'your_room_id');🔍 Key Benefits
- Reliable: Automatic reconnection and error recovery
- Fast: Optimized caching and efficient data structures and event emition
- Comprehensive: Full Highrise API coverage
- Developer-Friendly: Intuitive API with full TypeScript support
- Production-Ready: Built-in monitoring and performance tracking
📚 Documentation
For complete API documentation, check the TypeScript definitions in index.d.ts or visit our documentation site (will be available soon).
🐛 Issues and Support
Found a bug or need help? Please send a message to me in discord @oqs0_ with:
- sdk version
- Error logs
- Steps to reproduce
📄 License
MIT License - Copyright (c) 2025 Yahya Ahmed
Ready to build? Start with the Quick Start section and check the examples for common use cases!
