hytopia-debugging
1
总安装量
1
周安装量
#53347
全站排名
安装命令
npx skills add https://github.com/abstrucked/hytopia-skills --skill hytopia-debugging
Agent 安装分布
opencode
1
claude-code
1
Skill 文档
HYTOPIA Debugging
This skill helps you debug HYTOPIA SDK games effectively.
Documentation: https://dev.hytopia.com/sdk-guides/debugging
When to Use This Skill
Use this skill when the user:
- Wants to see performance metrics (FPS, memory, latency)
- Needs to debug client-side UI issues
- Asks about server-side logging and errors
- Wants to troubleshoot network issues
- Needs to track entity positions
- Asks about error handling best practices
Client Performance Debug Panel
Accessing Debug Info
The HYTOPIA client provides real-time performance metrics:
Keyboard: Press the tilde key (`) – typically top-left of keyboard
Mobile: Tap with 5 fingers simultaneously anywhere on screen
Persistent Debug: Append ?debug to your game URL for debug panel to persist across hot reloads
Debug Panel Shows
- FPS – Frame rate (capped at device refresh rate due to vsync)
- Memory usage – Current memory consumption
- Network latency – Round trip time to server
- Entity position – Position of controlled entity
Client & UI Debugging
Browser Developer Tools
Access via:
- Menu: “View â Developer Tools”
- Right-click: Select “Inspect”
Console Tab
// All console.log() calls from UI code appear here
console.log('Player clicked button');
console.log('UI state:', uiState);
// Errors also appear with stack traces
console.error('Failed to load asset');
Elements Tab
- View current DOM state
- Inspect UI element styles
- Debug layout issues
- Modify styles in real-time for testing
Server-Side Debugging
Terminal Output
Server logs appear in the terminal where you launched the HYTOPIA server:
// Standard logging
console.log('Player joined:', player.username);
console.log('Game state:', gameState);
// Debug specific systems
console.log('[Physics] Collision detected:', entityA.id, entityB.id);
console.log('[AI] Enemy state changed:', enemy.state);
ErrorHandler Class
The SDK provides native error logging with stack traces:
import { ErrorHandler } from 'hytopia';
// Warning - non-critical issues
ErrorHandler.warn('Player inventory nearly full');
// Error - recoverable errors
ErrorHandler.error('Failed to load player data, using defaults');
// Fatal Error - unrecoverable, may crash
ErrorHandler.fatalError('Critical game state corruption detected');
Error Handling Patterns
// Wrap risky operations
function loadPlayerData(player: Player) {
try {
const data = loadFromStorage(player.id);
return data;
} catch (error) {
ErrorHandler.error(`Failed to load data for ${player.username}: ${error}`);
return getDefaultPlayerData();
}
}
// Validate inputs
function handlePlayerAction(player: Player, action: string) {
if (!action) {
ErrorHandler.warn(`Empty action from ${player.username}`);
return;
}
if (!isValidAction(action)) {
ErrorHandler.error(`Invalid action "${action}" from ${player.username}`);
return;
}
processAction(player, action);
}
Debugging Patterns
Debug Logging System
const DEBUG = true; // Set false in production
function debugLog(category: string, message: string, data?: any) {
if (!DEBUG) return;
const timestamp = new Date().toISOString();
if (data) {
console.log(`[${timestamp}] [${category}] ${message}`, data);
} else {
console.log(`[${timestamp}] [${category}] ${message}`);
}
}
// Usage
debugLog('Physics', 'Raycast hit', { entity: entity.id, distance: 5.2 });
debugLog('Network', 'Player sync', { playerCount: world.players.length });
Performance Monitoring
function measurePerformance(name: string, fn: () => void) {
const start = performance.now();
fn();
const duration = performance.now() - start;
if (duration > 16) { // More than one frame at 60fps
console.warn(`[Performance] ${name} took ${duration.toFixed(2)}ms`);
}
}
// Usage
measurePerformance('AI Update', () => {
updateAllEnemies();
});
Entity Debug Visualization
// Log entity states for debugging
function debugEntity(entity: Entity) {
console.log('Entity Debug:', {
id: entity.id,
position: entity.position,
rotation: entity.rotation,
velocity: entity.velocity,
health: entity.getData('health'),
state: entity.getData('state')
});
}
// Periodic state dump
setInterval(() => {
console.log('=== World State ===');
console.log('Players:', world.players.length);
console.log('Entities:', world.entities.length);
world.players.forEach(p => {
console.log(` ${p.username}: ${JSON.stringify(p.position)}`);
});
}, 10000); // Every 10 seconds
Network Debug
// Track network events
world.onPlayerJoin = (player) => {
console.log(`[Network] Player connected: ${player.username} (${player.id})`);
};
world.onPlayerLeave = (player) => {
console.log(`[Network] Player disconnected: ${player.username}`);
};
// Log sync issues
function onSyncError(player: Player, error: string) {
ErrorHandler.error(`[Sync] Player ${player.username}: ${error}`);
}
Best Practices
- Use categories – Prefix logs with system names ([Physics], [AI], [Network])
- Log levels – Use console.log for info, console.warn for warnings, ErrorHandler for errors
- Include context – Always include relevant IDs and state in logs
- Performance check – Watch for operations taking more than 16ms
- Clean up for production – Disable verbose logging in production builds
- Use ?debug URL – Keeps debug panel visible during development
Common Debugging Scenarios
“Why isn’t my entity moving?”
// Check entity state
console.log('Entity position:', entity.position);
console.log('Entity velocity:', entity.velocity);
console.log('Has physics:', entity.hasComponent('physics'));
console.log('Is kinematic:', entity.isKinematic);
“Why is FPS low?”
// Profile expensive operations
console.time('AI Update');
updateAllEnemies();
console.timeEnd('AI Update');
console.time('Physics Tick');
world.physicsStep();
console.timeEnd('Physics Tick');
“Why did player disconnect?”
world.onPlayerLeave = (player) => {
console.log('Player left:', {
username: player.username,
playTime: Date.now() - player.getData('joinTime'),
lastPosition: player.position,
lastAction: player.getData('lastAction')
});
};