UNPKG

advanced-games-library

Version:

Advanced Gaming Library for React Native - Four Complete Games with iOS Compatibility Fixes

603 lines (515 loc) 16 kB
import * as React from 'react'; /** * Advanced Memory Management and Optimization utilities */ export interface MemoryUsageInfo { used: number; total: number; limit: number; percentage: number; timestamp: Date; } export interface OptimizationResult { memoryFreed: number; timeSpent: number; optimizationsApplied: string[]; success: boolean; } export interface PerformanceProfile { gameId: string; playerId?: string; deviceInfo: any; averageFrameTime: number; memoryUsage: MemoryUsageInfo; inputLatency: number; loadTime: number; renderTime: number; batteryImpact: 'low' | 'medium' | 'high'; networkUsage: number; recommendations: string[]; } /** * Advanced Memory Manager with leak detection and optimization */ export class AdvancedMemoryManager { private static instance: AdvancedMemoryManager; private memoryHistory: MemoryUsageInfo[] = []; private memoryThreshold = 85; // Percentage private optimizationTasks: Array<() => Promise<void>> = []; private weakRefs = new Set<any>(); private objectPool = new Map<string, any[]>(); private isOptimizing = false; private constructor() { this.startMemoryMonitoring(); } static getInstance(): AdvancedMemoryManager { if (!AdvancedMemoryManager.instance) { AdvancedMemoryManager.instance = new AdvancedMemoryManager(); } return AdvancedMemoryManager.instance; } /** * Start continuous memory monitoring */ private startMemoryMonitoring(): void { setInterval(() => { this.updateMemoryUsage(); this.checkMemoryLeaks(); this.cleanupWeakRefs(); }, 10000); // Every 10 seconds } /** * Update memory usage information */ private updateMemoryUsage(): void { try { const memInfo = this.getCurrentMemoryUsage(); if (memInfo) { this.memoryHistory.push(memInfo); // Keep only last 50 measurements (about 8 minutes) if (this.memoryHistory.length > 50) { this.memoryHistory.shift(); } // Trigger optimization if memory usage is high if (memInfo.percentage > this.memoryThreshold && !this.isOptimizing) { this.optimizeMemory(); } } } catch (error) { console.warn('Failed to update memory usage:', error); } } /** * Get current memory usage */ private getCurrentMemoryUsage(): MemoryUsageInfo | null { if ('memory' in performance) { const memory = (performance as any).memory; return { used: memory.usedJSHeapSize, total: memory.totalJSHeapSize, limit: memory.jsHeapSizeLimit, percentage: (memory.usedJSHeapSize / memory.jsHeapSizeLimit) * 100, timestamp: new Date() }; } return null; } /** * Detect potential memory leaks */ private checkMemoryLeaks(): void { if (this.memoryHistory.length < 10) return; // Check for consistent memory growth const recent = this.memoryHistory.slice(-10); const growthTrend = this.calculateGrowthTrend(recent); if (growthTrend > 5) { // 5% growth over 10 measurements console.warn('Potential memory leak detected. Growth trend:', growthTrend + '%'); this.optimizeMemory(); } } /** * Calculate memory growth trend */ private calculateGrowthTrend(measurements: MemoryUsageInfo[]): number { if (measurements.length < 2) return 0; const first = measurements[0].percentage; const last = measurements[measurements.length - 1].percentage; return ((last - first) / first) * 100; } /** * Clean up weak references */ private cleanupWeakRefs(): void { const toRemove: any[] = []; this.weakRefs.forEach(ref => { if (ref.deref() === undefined) { toRemove.push(ref); } }); toRemove.forEach(ref => this.weakRefs.delete(ref)); } /** * Register an object for weak reference tracking */ trackObject(obj: any): void { this.weakRefs.add(new (WeakRef as any)(obj)); } /** * Register optimization task */ registerOptimizationTask(task: () => Promise<void>): void { this.optimizationTasks.push(task); } /** * Optimize memory usage */ async optimizeMemory(): Promise<OptimizationResult> { if (this.isOptimizing) { return { memoryFreed: 0, timeSpent: 0, optimizationsApplied: [], success: false }; } this.isOptimizing = true; const startTime = Date.now(); const initialMemory = this.getCurrentMemoryUsage(); const optimizationsApplied: string[] = []; try { // Run optimization tasks for (const task of this.optimizationTasks) { try { await task(); optimizationsApplied.push('custom_task'); } catch (error) { console.warn('Optimization task failed:', error); } } // Clear object pools let poolsCleared = 0; this.objectPool.forEach((pool, key) => { if (pool.length > 10) { // Keep max 10 objects per pool pool.splice(10); poolsCleared++; } }); if (poolsCleared > 0) { optimizationsApplied.push('object_pool_cleanup'); } // Force garbage collection if available if ('gc' in global && typeof (global as any).gc === 'function') { (global as any).gc(); optimizationsApplied.push('forced_gc'); } // Clean up weak references this.cleanupWeakRefs(); optimizationsApplied.push('weakref_cleanup'); const finalMemory = this.getCurrentMemoryUsage(); const memoryFreed = initialMemory && finalMemory ? initialMemory.used - finalMemory.used : 0; return { memoryFreed, timeSpent: Date.now() - startTime, optimizationsApplied, success: true }; } finally { this.isOptimizing = false; } } /** * Object pool management */ getFromPool<T>(poolName: string, factory: () => T): T { const pool = this.objectPool.get(poolName) || []; if (pool.length > 0) { return pool.pop() as T; } return factory(); } /** * Return object to pool */ returnToPool(poolName: string, obj: any): void { const pool = this.objectPool.get(poolName) || []; if (pool.length < 20) { // Max pool size // Reset object if it has a reset method if (typeof obj.reset === 'function') { obj.reset(); } pool.push(obj); this.objectPool.set(poolName, pool); } } /** * Get memory usage history */ getMemoryHistory(): MemoryUsageInfo[] { return [...this.memoryHistory]; } /** * Get current memory status */ getCurrentMemoryStatus(): { current: MemoryUsageInfo | null; trend: 'increasing' | 'decreasing' | 'stable'; riskLevel: 'low' | 'medium' | 'high' | 'critical'; } { const current = this.getCurrentMemoryUsage(); const trend = this.getMemoryTrend(); const riskLevel = this.assessMemoryRisk(current); return { current, trend, riskLevel }; } /** * Get memory trend */ private getMemoryTrend(): 'increasing' | 'decreasing' | 'stable' { if (this.memoryHistory.length < 5) return 'stable'; const recent = this.memoryHistory.slice(-5); const growth = this.calculateGrowthTrend(recent); if (growth > 2) return 'increasing'; if (growth < -2) return 'decreasing'; return 'stable'; } /** * Assess memory risk level */ private assessMemoryRisk(memInfo: MemoryUsageInfo | null): 'low' | 'medium' | 'high' | 'critical' { if (!memInfo) return 'low'; if (memInfo.percentage > 95) return 'critical'; if (memInfo.percentage > 85) return 'high'; if (memInfo.percentage > 70) return 'medium'; return 'low'; } } /** * Advanced Performance Profiler */ export class PerformanceProfiler { private static instance: PerformanceProfiler; private profiles = new Map<string, PerformanceProfile>(); private isProfileEnabled = true; static getInstance(): PerformanceProfiler { if (!PerformanceProfiler.instance) { PerformanceProfiler.instance = new PerformanceProfiler(); } return PerformanceProfiler.instance; } /** * Create performance profile for a game session */ async createProfile( gameId: string, playerId?: string ): Promise<PerformanceProfile> { if (!this.isProfileEnabled) { return this.getEmptyProfile(gameId, playerId); } const memoryManager = AdvancedMemoryManager.getInstance(); const memoryStatus = memoryManager.getCurrentMemoryStatus(); const profile: PerformanceProfile = { gameId, playerId, deviceInfo: await this.getDeviceInfo(), averageFrameTime: this.calculateAverageFrameTime(), memoryUsage: memoryStatus.current || this.getEmptyMemoryInfo(), inputLatency: this.calculateAverageInputLatency(), loadTime: this.getGameLoadTime(gameId), renderTime: this.getAverageRenderTime(gameId), batteryImpact: this.estimateBatteryImpact(), networkUsage: this.estimateNetworkUsage(), recommendations: this.generateRecommendations(memoryStatus) }; this.profiles.set(`${gameId}_${playerId || 'anonymous'}`, profile); return profile; } /** * Generate performance recommendations */ private generateRecommendations(memoryStatus: any): string[] { const recommendations: string[] = []; if (memoryStatus.riskLevel === 'high' || memoryStatus.riskLevel === 'critical') { recommendations.push('Consider reducing texture quality'); recommendations.push('Enable memory optimization mode'); } if (memoryStatus.trend === 'increasing') { recommendations.push('Monitor for memory leaks'); recommendations.push('Consider periodic memory cleanup'); } if (this.calculateAverageFrameTime() > 20) { recommendations.push('Reduce visual effects for better performance'); recommendations.push('Lower frame rate target'); } return recommendations; } /** * Get empty performance profile */ private getEmptyProfile(gameId: string, playerId?: string): PerformanceProfile { return { gameId, playerId, deviceInfo: {}, averageFrameTime: 16.67, memoryUsage: this.getEmptyMemoryInfo(), inputLatency: 0, loadTime: 0, renderTime: 0, batteryImpact: 'low', networkUsage: 0, recommendations: [] }; } /** * Get empty memory info */ private getEmptyMemoryInfo(): MemoryUsageInfo { return { used: 0, total: 0, limit: 0, percentage: 0, timestamp: new Date() }; } /** * Get device information */ private async getDeviceInfo(): Promise<any> { // This would be implemented with actual device detection return { platform: 'react-native', model: 'unknown', memory: 'unknown', cpu: 'unknown', gpu: 'unknown' }; } /** * Calculate average frame time */ private calculateAverageFrameTime(): number { // This would integrate with actual frame time measurements return 16.67; // 60 FPS target } /** * Calculate average input latency */ private calculateAverageInputLatency(): number { // This would integrate with actual input latency measurements return 50; // ms } /** * Get game load time */ private getGameLoadTime(gameId: string): number { // This would retrieve from performance monitor return 1000; // ms } /** * Get average render time */ private getAverageRenderTime(gameId: string): number { // This would retrieve from performance monitor return 8; // ms } /** * Estimate battery impact */ private estimateBatteryImpact(): 'low' | 'medium' | 'high' { // This would be based on CPU/GPU usage, frame rate, etc. return 'medium'; } /** * Estimate network usage */ private estimateNetworkUsage(): number { // This would track actual network usage return 0; // bytes } /** * Get profile for game session */ getProfile(gameId: string, playerId?: string): PerformanceProfile | null { return this.profiles.get(`${gameId}_${playerId || 'anonymous'}`) || null; } /** * Enable/disable profiling */ setProfilingEnabled(enabled: boolean): void { this.isProfileEnabled = enabled; } } /** * Memory-aware object factory */ export class MemoryAwareObjectFactory { private static instance: MemoryAwareObjectFactory; private memoryManager: AdvancedMemoryManager; private constructor() { this.memoryManager = AdvancedMemoryManager.getInstance(); } static getInstance(): MemoryAwareObjectFactory { if (!MemoryAwareObjectFactory.instance) { MemoryAwareObjectFactory.instance = new MemoryAwareObjectFactory(); } return MemoryAwareObjectFactory.instance; } /** * Create object with memory tracking */ create<T>(poolName: string, factory: () => T): T { const memoryStatus = this.memoryManager.getCurrentMemoryStatus(); // If memory is critical, try to get from pool first if (memoryStatus.riskLevel === 'critical' || memoryStatus.riskLevel === 'high') { return this.memoryManager.getFromPool(poolName, factory); } const obj = factory(); this.memoryManager.trackObject(obj); return obj; } /** * Dispose object with memory management */ dispose(poolName: string, obj: any): void { // Clean up object if it has a dispose method if (typeof obj.dispose === 'function') { obj.dispose(); } // Return to pool for reuse this.memoryManager.returnToPool(poolName, obj); } } // Export singleton instances export const advancedMemoryManager = AdvancedMemoryManager.getInstance(); export const performanceProfiler = PerformanceProfiler.getInstance(); export const memoryAwareObjectFactory = MemoryAwareObjectFactory.getInstance(); /** * Decorator for memory-aware methods */ export function memoryOptimized(poolName: string) { return function (target: any, propertyName: string, descriptor: PropertyDescriptor) { const method = descriptor.value; descriptor.value = function (...args: any[]) { const memoryStatus = advancedMemoryManager.getCurrentMemoryStatus(); // Skip expensive operations if memory is critical if (memoryStatus.riskLevel === 'critical') { console.warn(`Skipping ${propertyName} due to critical memory usage`); return null; } return method.apply(this, args); }; return descriptor; }; } /** * Memory usage monitor hook for React components */ export function useMemoryMonitor() { const [memoryStatus, setMemoryStatus] = React.useState( advancedMemoryManager.getCurrentMemoryStatus() ); React.useEffect(() => { const interval = setInterval(() => { setMemoryStatus(advancedMemoryManager.getCurrentMemoryStatus()); }, 5000); return () => clearInterval(interval); }, []); return memoryStatus; } declare global { // Polyfill for WeakRef if not available // @ts-ignore var WeakRef: typeof WeakRef | undefined; } if (typeof WeakRef === 'undefined') { // @ts-ignore window.WeakRef = class { private _value: any; constructor(value: any) { this._value = value; } deref() { return this._value; } }; }