430 lines
12 KiB
JavaScript
430 lines
12 KiB
JavaScript
/**
|
|
* TECHNICAL & PERFORMANCE SYSTEM
|
|
* Performance optimization, mod support, replay system, and debug tools
|
|
*/
|
|
class TechnicalPerformanceSystem {
|
|
constructor(scene) {
|
|
this.scene = scene;
|
|
this.enabled = true;
|
|
|
|
// Performance monitoring
|
|
this.fpsHistory = [];
|
|
this.memoryHistory = [];
|
|
this.performanceStats = {
|
|
fps: 60,
|
|
memory: 0,
|
|
drawCalls: 0,
|
|
entities: 0
|
|
};
|
|
|
|
// Entity pooling
|
|
this.entityPools = new Map();
|
|
|
|
// Mod support
|
|
this.loadedMods = new Map();
|
|
this.modAPI = {};
|
|
|
|
// Replay system
|
|
this.isRecording = false;
|
|
this.isPlaying = false;
|
|
this.replayData = [];
|
|
this.currentReplayFrame = 0;
|
|
|
|
// Debug tools
|
|
this.debugMode = false;
|
|
this.debugCommands = new Map();
|
|
|
|
this.init();
|
|
console.log('✅ Technical & Performance System initialized');
|
|
}
|
|
|
|
init() {
|
|
this.setupEntityPools();
|
|
this.setupDebugCommands();
|
|
this.setupModAPI();
|
|
console.log('⚡ Technical & Performance ready');
|
|
}
|
|
|
|
// ========== PERFORMANCE MONITORING ==========
|
|
|
|
updatePerformanceStats() {
|
|
// FPS
|
|
this.performanceStats.fps = Math.round(this.scene.game.loop.actualFps);
|
|
this.fpsHistory.push(this.performanceStats.fps);
|
|
if (this.fpsHistory.length > 60) this.fpsHistory.shift();
|
|
|
|
// Memory (if available)
|
|
if (performance.memory) {
|
|
this.performanceStats.memory = Math.round(performance.memory.usedJSHeapSize / 1048576); // MB
|
|
this.memoryHistory.push(this.performanceStats.memory);
|
|
if (this.memoryHistory.length > 60) this.memoryHistory.shift();
|
|
}
|
|
|
|
// Entity count
|
|
this.performanceStats.entities = this.scene.children.list.length;
|
|
}
|
|
|
|
getPerformanceReport() {
|
|
const avgFps = this.fpsHistory.reduce((a, b) => a + b, 0) / this.fpsHistory.length;
|
|
const avgMemory = this.memoryHistory.reduce((a, b) => a + b, 0) / this.memoryHistory.length;
|
|
|
|
return {
|
|
fps: {
|
|
current: this.performanceStats.fps,
|
|
average: Math.round(avgFps),
|
|
min: Math.min(...this.fpsHistory),
|
|
max: Math.max(...this.fpsHistory)
|
|
},
|
|
memory: {
|
|
current: this.performanceStats.memory,
|
|
average: Math.round(avgMemory)
|
|
},
|
|
entities: this.performanceStats.entities
|
|
};
|
|
}
|
|
|
|
// ========== ENTITY POOLING ==========
|
|
|
|
setupEntityPools() {
|
|
// Create pools for frequently spawned entities
|
|
this.createPool('particle', 100);
|
|
this.createPool('projectile', 50);
|
|
this.createPool('enemy', 30);
|
|
this.createPool('item', 50);
|
|
}
|
|
|
|
createPool(type, size) {
|
|
const pool = {
|
|
available: [],
|
|
active: []
|
|
};
|
|
|
|
for (let i = 0; i < size; i++) {
|
|
pool.available.push(this.createEntity(type));
|
|
}
|
|
|
|
this.entityPools.set(type, pool);
|
|
console.log(`🔄 Created pool for ${type}: ${size} entities`);
|
|
}
|
|
|
|
createEntity(type) {
|
|
// Create entity based on type
|
|
return { type, active: false };
|
|
}
|
|
|
|
getFromPool(type) {
|
|
const pool = this.entityPools.get(type);
|
|
if (!pool || pool.available.length === 0) {
|
|
return this.createEntity(type);
|
|
}
|
|
|
|
const entity = pool.available.pop();
|
|
pool.active.push(entity);
|
|
entity.active = true;
|
|
return entity;
|
|
}
|
|
|
|
returnToPool(type, entity) {
|
|
const pool = this.entityPools.get(type);
|
|
if (!pool) return;
|
|
|
|
const index = pool.active.indexOf(entity);
|
|
if (index > -1) {
|
|
pool.active.splice(index, 1);
|
|
pool.available.push(entity);
|
|
entity.active = false;
|
|
}
|
|
}
|
|
|
|
// ========== CHUNK LOADING ==========
|
|
|
|
loadChunk(chunkX, chunkY) {
|
|
console.log(`📦 Loading chunk (${chunkX}, ${chunkY})`);
|
|
// Load terrain, entities, etc. for chunk
|
|
}
|
|
|
|
unloadChunk(chunkX, chunkY) {
|
|
console.log(`📦 Unloading chunk (${chunkX}, ${chunkY})`);
|
|
// Unload chunk to free memory
|
|
}
|
|
|
|
// ========== MOD SUPPORT ==========
|
|
|
|
setupModAPI() {
|
|
this.modAPI = {
|
|
registerItem: (id, data) => this.registerModItem(id, data),
|
|
registerRecipe: (id, data) => this.registerModRecipe(id, data),
|
|
registerEnemy: (id, data) => this.registerModEnemy(id, data),
|
|
addCommand: (name, callback) => this.addDebugCommand(name, callback)
|
|
};
|
|
}
|
|
|
|
loadMod(modId, modData) {
|
|
if (this.loadedMods.has(modId)) {
|
|
console.log(`❌ Mod already loaded: ${modId}`);
|
|
return false;
|
|
}
|
|
|
|
// Validate mod
|
|
if (!this.validateMod(modData)) {
|
|
console.log(`❌ Invalid mod: ${modId}`);
|
|
return false;
|
|
}
|
|
|
|
// Load mod
|
|
this.loadedMods.set(modId, modData);
|
|
|
|
// Execute mod init
|
|
if (modData.init) {
|
|
modData.init(this.modAPI);
|
|
}
|
|
|
|
console.log(`✅ Mod loaded: ${modId}`);
|
|
return true;
|
|
}
|
|
|
|
validateMod(modData) {
|
|
// Check required fields
|
|
return modData.name && modData.version;
|
|
}
|
|
|
|
registerModItem(id, data) {
|
|
console.log(`📦 Registered mod item: ${id}`);
|
|
}
|
|
|
|
registerModRecipe(id, data) {
|
|
console.log(`🔨 Registered mod recipe: ${id}`);
|
|
}
|
|
|
|
registerModEnemy(id, data) {
|
|
console.log(`👹 Registered mod enemy: ${id}`);
|
|
}
|
|
|
|
detectModConflicts() {
|
|
const conflicts = [];
|
|
// Check for conflicts between mods
|
|
return conflicts;
|
|
}
|
|
|
|
// ========== REPLAY SYSTEM ==========
|
|
|
|
startRecording() {
|
|
this.isRecording = true;
|
|
this.replayData = [];
|
|
console.log('🎬 Recording started');
|
|
}
|
|
|
|
stopRecording() {
|
|
this.isRecording = false;
|
|
console.log('🎬 Recording stopped');
|
|
return this.replayData;
|
|
}
|
|
|
|
recordFrame() {
|
|
if (!this.isRecording) return;
|
|
|
|
const frame = {
|
|
time: Date.now(),
|
|
inputs: this.captureInputs(),
|
|
state: this.captureGameState()
|
|
};
|
|
|
|
this.replayData.push(frame);
|
|
}
|
|
|
|
captureInputs() {
|
|
// Capture keyboard/mouse inputs
|
|
return {
|
|
keys: {},
|
|
mouse: { x: 0, y: 0, buttons: [] }
|
|
};
|
|
}
|
|
|
|
captureGameState() {
|
|
// Capture minimal game state
|
|
return {
|
|
playerPos: { x: 0, y: 0 },
|
|
time: 0
|
|
};
|
|
}
|
|
|
|
playReplay(replayData) {
|
|
this.isPlaying = true;
|
|
this.replayData = replayData;
|
|
this.currentReplayFrame = 0;
|
|
console.log('▶️ Playing replay');
|
|
}
|
|
|
|
stopReplay() {
|
|
this.isPlaying = false;
|
|
this.currentReplayFrame = 0;
|
|
console.log('⏹️ Replay stopped');
|
|
}
|
|
|
|
updateReplay() {
|
|
if (!this.isPlaying) return;
|
|
|
|
if (this.currentReplayFrame >= this.replayData.length) {
|
|
this.stopReplay();
|
|
return;
|
|
}
|
|
|
|
const frame = this.replayData[this.currentReplayFrame];
|
|
this.applyReplayFrame(frame);
|
|
this.currentReplayFrame++;
|
|
}
|
|
|
|
applyReplayFrame(frame) {
|
|
// Apply inputs and state from replay frame
|
|
}
|
|
|
|
saveReplay(filename) {
|
|
const data = JSON.stringify(this.replayData);
|
|
localStorage.setItem(`replay_${filename}`, data);
|
|
console.log(`💾 Replay saved: ${filename}`);
|
|
}
|
|
|
|
loadReplay(filename) {
|
|
const data = localStorage.getItem(`replay_${filename}`);
|
|
if (data) {
|
|
this.replayData = JSON.parse(data);
|
|
console.log(`📂 Replay loaded: ${filename}`);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// ========== DEBUG TOOLS ==========
|
|
|
|
setupDebugCommands() {
|
|
this.addDebugCommand('help', () => this.showDebugHelp());
|
|
this.addDebugCommand('spawn', (entity, x, y) => this.spawnEntity(entity, x, y));
|
|
this.addDebugCommand('tp', (x, y) => this.teleportPlayer(x, y));
|
|
this.addDebugCommand('give', (item, amount) => this.giveItem(item, amount));
|
|
this.addDebugCommand('time', (hours) => this.setTime(hours));
|
|
this.addDebugCommand('weather', (type) => this.setWeather(type));
|
|
this.addDebugCommand('god', () => this.toggleGodMode());
|
|
this.addDebugCommand('noclip', () => this.toggleNoclip());
|
|
this.addDebugCommand('kill', (radius) => this.killEnemies(radius));
|
|
this.addDebugCommand('clear', () => this.clearInventory());
|
|
}
|
|
|
|
addDebugCommand(name, callback) {
|
|
this.debugCommands.set(name, callback);
|
|
}
|
|
|
|
executeCommand(commandString) {
|
|
const parts = commandString.split(' ');
|
|
const command = parts[0];
|
|
const args = parts.slice(1);
|
|
|
|
const callback = this.debugCommands.get(command);
|
|
if (callback) {
|
|
callback(...args);
|
|
} else {
|
|
console.log(`❌ Unknown command: ${command}`);
|
|
}
|
|
}
|
|
|
|
showDebugHelp() {
|
|
console.log('📋 Available commands:');
|
|
for (const [name] of this.debugCommands.entries()) {
|
|
console.log(` - ${name}`);
|
|
}
|
|
}
|
|
|
|
spawnEntity(entity, x, y) {
|
|
console.log(`👾 Spawned ${entity} at (${x}, ${y})`);
|
|
}
|
|
|
|
teleportPlayer(x, y) {
|
|
if (this.scene.player) {
|
|
this.scene.player.setPosition(parseFloat(x), parseFloat(y));
|
|
console.log(`🚀 Teleported to (${x}, ${y})`);
|
|
}
|
|
}
|
|
|
|
giveItem(item, amount) {
|
|
if (this.scene.inventorySystem) {
|
|
this.scene.inventorySystem.addItem(item, parseInt(amount) || 1);
|
|
console.log(`🎁 Gave ${amount || 1}x ${item}`);
|
|
}
|
|
}
|
|
|
|
setTime(hours) {
|
|
if (this.scene.weatherSystem) {
|
|
this.scene.weatherSystem.currentTime = parseFloat(hours);
|
|
console.log(`⏰ Time set to ${hours}:00`);
|
|
}
|
|
}
|
|
|
|
setWeather(type) {
|
|
if (this.scene.weatherSystem) {
|
|
this.scene.weatherSystem.setWeather(type);
|
|
console.log(`🌦️ Weather set to ${type}`);
|
|
}
|
|
}
|
|
|
|
toggleGodMode() {
|
|
console.log('⚡ God mode toggled');
|
|
}
|
|
|
|
toggleNoclip() {
|
|
console.log('👻 Noclip toggled');
|
|
}
|
|
|
|
killEnemies(radius) {
|
|
console.log(`💀 Killed all enemies in ${radius || 'infinite'} radius`);
|
|
}
|
|
|
|
clearInventory() {
|
|
if (this.scene.inventorySystem) {
|
|
this.scene.inventorySystem.clear();
|
|
console.log('🗑️ Inventory cleared');
|
|
}
|
|
}
|
|
|
|
toggleDebugMode() {
|
|
this.debugMode = !this.debugMode;
|
|
console.log(`🐛 Debug mode: ${this.debugMode ? 'ON' : 'OFF'}`);
|
|
}
|
|
|
|
// ========== AUTO-UPDATE ==========
|
|
|
|
checkForUpdates() {
|
|
console.log('🔍 Checking for updates...');
|
|
// Check version against server
|
|
return { available: false, version: '3.0.0' };
|
|
}
|
|
|
|
downloadUpdate(version) {
|
|
console.log(`⬇️ Downloading update ${version}...`);
|
|
}
|
|
|
|
installUpdate() {
|
|
console.log('📦 Installing update...');
|
|
}
|
|
|
|
rollbackUpdate() {
|
|
console.log('⏪ Rolling back update...');
|
|
}
|
|
|
|
// ========== UPDATE ==========
|
|
|
|
update(delta) {
|
|
this.updatePerformanceStats();
|
|
|
|
if (this.isRecording) {
|
|
this.recordFrame();
|
|
}
|
|
|
|
if (this.isPlaying) {
|
|
this.updateReplay();
|
|
}
|
|
}
|
|
|
|
destroy() {
|
|
console.log('⚡ Technical & Performance System destroyed');
|
|
}
|
|
}
|