advanced-games-library
Version:
Advanced Gaming Library for React Native - Four Complete Games with iOS Compatibility Fixes
603 lines (515 loc) • 16 kB
text/typescript
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; }
};
}