advanced-games-library
Version:
Advanced Gaming Library for React Native - Four Complete Games with iOS Compatibility Fixes
971 lines (838 loc) • 27 kB
text/typescript
/**
* Smart Network Adaptation System - מערכת התאמה חכמה לעומס רשת
* מנטרת את מצב הרשת ומתאימה את איכות המשחק בהתאם
*/
export interface NetworkMetrics {
latency: number; // ms
bandwidth: number; // Mbps
packetLoss: number; // percentage 0-100
jitter: number; // ms
connectionType: 'wifi' | 'cellular' | 'ethernet' | 'unknown';
signalStrength: number; // 0-100
isOnline: boolean;
timestamp: number;
}
export interface AdaptationProfile {
id: string;
name: string;
minLatency: number;
maxLatency: number;
minBandwidth: number;
maxPacketLoss: number;
gameSettings: GameQualitySettings;
uiSettings: UIAdaptationSettings;
syncSettings: SyncAdaptationSettings;
}
export interface GameQualitySettings {
updateRate: number; // Hz
compressionLevel: number; // 0-100
maxParticipants: number;
enablePrediction: boolean;
bufferSize: number; // ms
priorityMode: 'performance' | 'quality' | 'balanced';
fallbackToOffline: boolean;
}
export interface UIAdaptationSettings {
animationQuality: 'high' | 'medium' | 'low' | 'disabled';
effectsEnabled: boolean;
imageCompression: number; // 0-100
fontOptimization: boolean;
lazyLoading: boolean;
preloadingEnabled: boolean;
}
export interface SyncAdaptationSettings {
syncInterval: number; // ms
batchUpdates: boolean;
deltaCompression: boolean;
stateSize: 'full' | 'minimal' | 'compressed';
conflictResolution: 'server' | 'client' | 'consensus';
retryStrategy: RetryStrategy;
}
export interface RetryStrategy {
maxRetries: number;
baseDelay: number; // ms
backoffMultiplier: number;
maxDelay: number; // ms
exponentialBackoff: boolean;
}
export interface NetworkEvent {
type: 'connection_change' | 'quality_change' | 'adaptation_triggered' | 'error';
timestamp: number;
metrics?: NetworkMetrics;
adaptationApplied?: string;
details?: any;
}
export interface PredictiveModel {
patterns: Array<{
timeRange: { start: number; end: number };
expectedMetrics: NetworkMetrics;
confidence: number;
}>;
learningData: Array<{
timestamp: number;
metrics: NetworkMetrics;
context: any;
}>;
accuracy: number;
}
class SmartNetworkAdaptationSystem {
private currentMetrics: NetworkMetrics;
private metricsHistory: NetworkMetrics[] = [];
private adaptationProfiles: Map<string, AdaptationProfile> = new Map();
private activeProfile: AdaptationProfile | null = null;
private eventHistory: NetworkEvent[] = [];
private predictiveModel: PredictiveModel;
private monitoringInterval?: NodeJS.Timeout;
private adaptationCallbacks: Map<string, (profile: AdaptationProfile) => void> = new Map();
private isMonitoring = false;
private adaptationThreshold = 0.3; // Sensitivity for changes
constructor() {
this.currentMetrics = {
latency: 0,
bandwidth: 0,
packetLoss: 0,
jitter: 0,
connectionType: 'unknown',
signalStrength: 0,
isOnline: true,
timestamp: Date.now()
};
this.predictiveModel = {
patterns: [],
learningData: [],
accuracy: 0
};
this.initializeAdaptationProfiles();
this.setupNetworkMonitoring();
console.log('🌐 Smart Network Adaptation System initialized');
}
/**
* אתחול פרופילי התאמה
*/
private initializeAdaptationProfiles(): void {
// High Quality Profile - לרשת מהירה ויציבה
const highQuality: AdaptationProfile = {
id: 'high_quality',
name: 'High Quality',
minLatency: 0,
maxLatency: 50,
minBandwidth: 10,
maxPacketLoss: 1,
gameSettings: {
updateRate: 60,
compressionLevel: 10,
maxParticipants: 8,
enablePrediction: true,
bufferSize: 100,
priorityMode: 'quality',
fallbackToOffline: false
},
uiSettings: {
animationQuality: 'high',
effectsEnabled: true,
imageCompression: 10,
fontOptimization: false,
lazyLoading: false,
preloadingEnabled: true
},
syncSettings: {
syncInterval: 16, // 60 FPS
batchUpdates: false,
deltaCompression: false,
stateSize: 'full',
conflictResolution: 'server',
retryStrategy: {
maxRetries: 5,
baseDelay: 100,
backoffMultiplier: 1.5,
maxDelay: 2000,
exponentialBackoff: true
}
}
};
// Medium Quality Profile - לרשת בינונית
const mediumQuality: AdaptationProfile = {
id: 'medium_quality',
name: 'Medium Quality',
minLatency: 50,
maxLatency: 150,
minBandwidth: 2,
maxPacketLoss: 5,
gameSettings: {
updateRate: 30,
compressionLevel: 30,
maxParticipants: 6,
enablePrediction: true,
bufferSize: 200,
priorityMode: 'balanced',
fallbackToOffline: false
},
uiSettings: {
animationQuality: 'medium',
effectsEnabled: true,
imageCompression: 30,
fontOptimization: true,
lazyLoading: true,
preloadingEnabled: true
},
syncSettings: {
syncInterval: 33, // 30 FPS
batchUpdates: true,
deltaCompression: true,
stateSize: 'compressed',
conflictResolution: 'server',
retryStrategy: {
maxRetries: 3,
baseDelay: 200,
backoffMultiplier: 2,
maxDelay: 3000,
exponentialBackoff: true
}
}
};
// Low Quality Profile - לרשת איטית
const lowQuality: AdaptationProfile = {
id: 'low_quality',
name: 'Low Quality',
minLatency: 150,
maxLatency: 500,
minBandwidth: 0.5,
maxPacketLoss: 15,
gameSettings: {
updateRate: 15,
compressionLevel: 60,
maxParticipants: 4,
enablePrediction: true,
bufferSize: 500,
priorityMode: 'performance',
fallbackToOffline: false
},
uiSettings: {
animationQuality: 'low',
effectsEnabled: false,
imageCompression: 60,
fontOptimization: true,
lazyLoading: true,
preloadingEnabled: false
},
syncSettings: {
syncInterval: 66, // 15 FPS
batchUpdates: true,
deltaCompression: true,
stateSize: 'minimal',
conflictResolution: 'client',
retryStrategy: {
maxRetries: 2,
baseDelay: 500,
backoffMultiplier: 2.5,
maxDelay: 5000,
exponentialBackoff: true
}
}
};
// Offline Profile - למצב לא מקוון
const offline: AdaptationProfile = {
id: 'offline',
name: 'Offline Mode',
minLatency: 500,
maxLatency: Infinity,
minBandwidth: 0,
maxPacketLoss: 100,
gameSettings: {
updateRate: 60,
compressionLevel: 0,
maxParticipants: 1,
enablePrediction: false,
bufferSize: 0,
priorityMode: 'performance',
fallbackToOffline: true
},
uiSettings: {
animationQuality: 'high',
effectsEnabled: true,
imageCompression: 0,
fontOptimization: false,
lazyLoading: false,
preloadingEnabled: false
},
syncSettings: {
syncInterval: 0,
batchUpdates: false,
deltaCompression: false,
stateSize: 'full',
conflictResolution: 'client',
retryStrategy: {
maxRetries: 0,
baseDelay: 0,
backoffMultiplier: 1,
maxDelay: 0,
exponentialBackoff: false
}
}
};
this.adaptationProfiles.set('high_quality', highQuality);
this.adaptationProfiles.set('medium_quality', mediumQuality);
this.adaptationProfiles.set('low_quality', lowQuality);
this.adaptationProfiles.set('offline', offline);
// Set default profile
this.activeProfile = mediumQuality;
}
/**
* הגדרת ניטור רשת
*/
private setupNetworkMonitoring(): void {
if (typeof window !== 'undefined') {
// Monitor online/offline status
window.addEventListener('online', () => {
this.handleConnectionChange(true);
});
window.addEventListener('offline', () => {
this.handleConnectionChange(false);
});
// Monitor connection type changes
if ('connection' in navigator) {
const connection = (navigator as any).connection;
connection.addEventListener('change', () => {
this.updateConnectionInfo();
});
}
}
this.startContinuousMonitoring();
}
/**
* התחלת ניטור רציף
*/
startContinuousMonitoring(): void {
if (this.isMonitoring) return;
this.isMonitoring = true;
this.monitoringInterval = setInterval(() => {
this.measureNetworkMetrics();
}, 2000); // Measure every 2 seconds
console.log('📊 Network monitoring started');
}
/**
* עצירת ניטור
*/
stopMonitoring(): void {
if (this.monitoringInterval) {
clearInterval(this.monitoringInterval);
this.monitoringInterval = undefined;
}
this.isMonitoring = false;
console.log('📊 Network monitoring stopped');
}
/**
* מדידת מדדי רשת
*/
private async measureNetworkMetrics(): Promise<void> {
try {
const startTime = performance.now();
// Measure latency with a lightweight request
const latency = await this.measureLatency();
// Get connection info
const connectionInfo = this.getConnectionInfo();
// Estimate bandwidth (simplified)
const bandwidth = await this.estimateBandwidth();
// Calculate jitter from latency history
const jitter = this.calculateJitter();
const metrics: NetworkMetrics = {
latency,
bandwidth,
packetLoss: 0, // Would need more complex measurement
jitter,
connectionType: connectionInfo.type,
signalStrength: connectionInfo.strength,
isOnline: navigator.onLine,
timestamp: Date.now()
};
this.updateMetrics(metrics);
} catch (error) {
console.warn('Network measurement failed:', error);
// Use fallback metrics
const fallbackMetrics: NetworkMetrics = {
...this.currentMetrics,
isOnline: navigator.onLine,
timestamp: Date.now()
};
this.updateMetrics(fallbackMetrics);
}
}
/**
* מדידת latency
*/
private async measureLatency(): Promise<number> {
const startTime = performance.now();
try {
// Use a lightweight endpoint or create a data URL
const testUrl = 'data:text/plain,ping';
await fetch(testUrl, { method: 'HEAD', cache: 'no-store' });
const endTime = performance.now();
return endTime - startTime;
} catch (error) {
// Fallback to previous latency or default
return this.currentMetrics.latency || 100;
}
}
/**
* הערכת bandwidth
*/
private async estimateBandwidth(): Promise<number> {
if ('connection' in navigator) {
const connection = (navigator as any).connection;
if (connection.downlink) {
return connection.downlink;
}
}
// Fallback estimation based on connection type
const connectionInfo = this.getConnectionInfo();
switch (connectionInfo.type) {
case 'wifi': return 10; // Assume decent WiFi
case 'cellular': return 2; // Conservative cellular estimate
case 'ethernet': return 100; // Assume fast ethernet
default: return 1; // Conservative default
}
}
/**
* חישוב jitter
*/
private calculateJitter(): number {
if (this.metricsHistory.length < 3) return 0;
const recentLatencies = this.metricsHistory
.slice(-5)
.map(m => m.latency);
const diffs = [];
for (let i = 1; i < recentLatencies.length; i++) {
diffs.push(Math.abs(recentLatencies[i] - recentLatencies[i - 1]));
}
return diffs.reduce((sum, diff) => sum + diff, 0) / diffs.length;
}
/**
* קבלת מידע על החיבור
*/
private getConnectionInfo(): { type: NetworkMetrics['connectionType']; strength: number } {
if ('connection' in navigator) {
const connection = (navigator as any).connection;
let type: NetworkMetrics['connectionType'] = 'unknown';
if (connection.type) {
switch (connection.type) {
case 'wifi':
case 'ethernet':
type = connection.type;
break;
case 'cellular':
type = 'cellular';
break;
default:
type = 'unknown';
}
}
// Estimate signal strength based on effective type
let strength = 50; // Default
if (connection.effectiveType) {
switch (connection.effectiveType) {
case '4g': strength = 90; break;
case '3g': strength = 60; break;
case '2g': strength = 30; break;
case 'slow-2g': strength = 10; break;
}
}
return { type, strength };
}
return { type: 'unknown', strength: 50 };
}
/**
* עדכון מדדים
*/
private updateMetrics(metrics: NetworkMetrics): void {
this.currentMetrics = metrics;
this.metricsHistory.push(metrics);
// Keep only last 50 measurements
if (this.metricsHistory.length > 50) {
this.metricsHistory.shift();
}
// Add to learning data
this.predictiveModel.learningData.push({
timestamp: metrics.timestamp,
metrics,
context: this.getCurrentContext()
});
// Check if adaptation is needed
this.checkAdaptationNeeded(metrics);
// Update predictive model
this.updatePredictiveModel();
}
/**
* בדיקה אם נדרשת התאמה
*/
private checkAdaptationNeeded(metrics: NetworkMetrics): void {
if (!this.activeProfile) return;
const currentProfile = this.activeProfile;
const bestProfile = this.findBestProfile(metrics);
if (bestProfile.id !== currentProfile.id) {
const changeSignificance = this.calculateChangeSignificance(metrics, currentProfile);
if (changeSignificance > this.adaptationThreshold) {
this.triggerAdaptation(bestProfile, metrics, changeSignificance);
}
}
}
/**
* חיפוש הפרופיל הטוב ביותר
*/
private findBestProfile(metrics: NetworkMetrics): AdaptationProfile {
if (!metrics.isOnline) {
return this.adaptationProfiles.get('offline')!;
}
// Score each profile based on how well it matches current conditions
let bestProfile = this.adaptationProfiles.get('medium_quality')!;
let bestScore = -Infinity;
for (const profile of this.adaptationProfiles.values()) {
if (profile.id === 'offline') continue; // Skip offline when online
const score = this.scoreProfile(profile, metrics);
if (score > bestScore) {
bestScore = score;
bestProfile = profile;
}
}
return bestProfile;
}
/**
* ניקוד פרופיל לפי מדדים נוכחיים
*/
private scoreProfile(profile: AdaptationProfile, metrics: NetworkMetrics): number {
let score = 0;
// Latency score
if (metrics.latency <= profile.maxLatency) {
score += 100 - (metrics.latency / profile.maxLatency) * 50;
} else {
score -= 50; // Penalty for exceeding latency
}
// Bandwidth score
if (metrics.bandwidth >= profile.minBandwidth) {
score += 50;
} else {
score -= (profile.minBandwidth - metrics.bandwidth) * 10;
}
// Packet loss score
if (metrics.packetLoss <= profile.maxPacketLoss) {
score += 30;
} else {
score -= (metrics.packetLoss - profile.maxPacketLoss) * 5;
}
// Connection type bonus
switch (metrics.connectionType) {
case 'ethernet': score += 20; break;
case 'wifi': score += 15; break;
case 'cellular': score += 5; break;
default: score += 0;
}
return score;
}
/**
* חישוב משמעות השינוי
*/
private calculateChangeSignificance(metrics: NetworkMetrics, currentProfile: AdaptationProfile): number {
let significance = 0;
// Latency change significance
const latencyRatio = metrics.latency / Math.max(currentProfile.maxLatency, 1);
if (latencyRatio > 1.5 || latencyRatio < 0.5) {
significance += 0.4;
}
// Bandwidth change significance
const bandwidthRatio = metrics.bandwidth / Math.max(currentProfile.minBandwidth, 0.1);
if (bandwidthRatio < 0.5 || bandwidthRatio > 2) {
significance += 0.3;
}
// Connection stability
if (metrics.jitter > 50 || metrics.packetLoss > currentProfile.maxPacketLoss) {
significance += 0.3;
}
return significance;
}
/**
* הפעלת התאמה
*/
private triggerAdaptation(newProfile: AdaptationProfile, metrics: NetworkMetrics, significance: number): void {
const previousProfile = this.activeProfile;
this.activeProfile = newProfile;
// Log the adaptation event
const event: NetworkEvent = {
type: 'adaptation_triggered',
timestamp: Date.now(),
metrics,
adaptationApplied: newProfile.id,
details: {
previousProfile: previousProfile?.id,
significance,
reason: this.getAdaptationReason(metrics, newProfile)
}
};
this.eventHistory.push(event);
// Notify callbacks
this.adaptationCallbacks.forEach(callback => {
try {
callback(newProfile);
} catch (error) {
console.error('Adaptation callback error:', error);
}
});
console.log(`🔄 Network adaptation: ${previousProfile?.name} → ${newProfile.name}`);
}
/**
* קבלת סיבת ההתאמה
*/
private getAdaptationReason(metrics: NetworkMetrics, profile: AdaptationProfile): string {
const reasons = [];
if (!metrics.isOnline) {
reasons.push('offline');
}
if (metrics.latency > 300) {
reasons.push('high_latency');
}
if (metrics.bandwidth < 1) {
reasons.push('low_bandwidth');
}
if (metrics.packetLoss > 10) {
reasons.push('high_packet_loss');
}
if (metrics.jitter > 100) {
reasons.push('unstable_connection');
}
return reasons.join(', ') || 'optimization';
}
/**
* טיפול בשינוי חיבור
*/
private handleConnectionChange(isOnline: boolean): void {
const event: NetworkEvent = {
type: 'connection_change',
timestamp: Date.now(),
details: { isOnline }
};
this.eventHistory.push(event);
if (!isOnline) {
// Switch to offline mode immediately
const offlineProfile = this.adaptationProfiles.get('offline')!;
this.triggerAdaptation(offlineProfile, { ...this.currentMetrics, isOnline: false }, 1.0);
} else {
// Re-measure network when coming back online
setTimeout(() => {
this.measureNetworkMetrics();
}, 1000);
}
}
/**
* עדכון מידע חיבור
*/
private updateConnectionInfo(): void {
const connectionInfo = this.getConnectionInfo();
this.currentMetrics = {
...this.currentMetrics,
connectionType: connectionInfo.type,
signalStrength: connectionInfo.strength,
timestamp: Date.now()
};
}
/**
* קבלת קונטקסט נוכחי
*/
private getCurrentContext(): any {
return {
timeOfDay: new Date().getHours(),
dayOfWeek: new Date().getDay(),
userAgent: typeof navigator !== 'undefined' ? navigator.userAgent : 'unknown',
screenSize: typeof window !== 'undefined' ?
{ width: window.screen.width, height: window.screen.height } :
{ width: 0, height: 0 }
};
}
/**
* עדכון מודל חיזוי
*/
private updatePredictiveModel(): void {
// Simplified predictive model update
if (this.predictiveModel.learningData.length < 10) return;
// Analyze patterns in the last 50 data points
const recentData = this.predictiveModel.learningData.slice(-50);
// Group by time of day
const hourlyPatterns: { [hour: number]: NetworkMetrics[] } = {};
recentData.forEach(data => {
const hour = new Date(data.timestamp).getHours();
if (!hourlyPatterns[hour]) {
hourlyPatterns[hour] = [];
}
hourlyPatterns[hour].push(data.metrics);
});
// Create patterns
this.predictiveModel.patterns = [];
Object.entries(hourlyPatterns).forEach(([hour, metrics]) => {
if (metrics.length >= 3) {
const avgMetrics = this.calculateAverageMetrics(metrics);
this.predictiveModel.patterns.push({
timeRange: {
start: parseInt(hour),
end: (parseInt(hour) + 1) % 24
},
expectedMetrics: avgMetrics,
confidence: Math.min(0.9, metrics.length / 10)
});
}
});
// Update accuracy based on recent predictions vs actual
this.updateModelAccuracy();
}
/**
* חישוב ממוצע מדדים
*/
private calculateAverageMetrics(metrics: NetworkMetrics[]): NetworkMetrics {
const avg = metrics.reduce((acc, m) => ({
latency: acc.latency + m.latency,
bandwidth: acc.bandwidth + m.bandwidth,
packetLoss: acc.packetLoss + m.packetLoss,
jitter: acc.jitter + m.jitter,
signalStrength: acc.signalStrength + m.signalStrength
}), { latency: 0, bandwidth: 0, packetLoss: 0, jitter: 0, signalStrength: 0 });
const count = metrics.length;
return {
latency: avg.latency / count,
bandwidth: avg.bandwidth / count,
packetLoss: avg.packetLoss / count,
jitter: avg.jitter / count,
connectionType: metrics[0].connectionType,
signalStrength: avg.signalStrength / count,
isOnline: true,
timestamp: Date.now()
};
}
/**
* עדכון דיוק המודל
*/
private updateModelAccuracy(): void {
// Simplified accuracy calculation
// In practice, this would compare predictions with actual outcomes
this.predictiveModel.accuracy = Math.min(0.95,
0.5 + (this.predictiveModel.learningData.length / 1000) * 0.4
);
}
/**
* רישום callback להתאמה
*/
onAdaptation(id: string, callback: (profile: AdaptationProfile) => void): void {
this.adaptationCallbacks.set(id, callback);
}
/**
* הסרת callback
*/
offAdaptation(id: string): void {
this.adaptationCallbacks.delete(id);
}
/**
* קבלת פרופיל פעיל
*/
getActiveProfile(): AdaptationProfile | null {
return this.activeProfile;
}
/**
* קבלת מדדי רשת נוכחיים
*/
getCurrentMetrics(): NetworkMetrics {
return { ...this.currentMetrics };
}
/**
* קבלת היסטוריית מדדים
*/
getMetricsHistory(limit?: number): NetworkMetrics[] {
const history = [...this.metricsHistory];
return limit ? history.slice(-limit) : history;
}
/**
* קבלת חיזוי למדדי רשת
*/
getPrediction(timeAhead: number = 3600000): NetworkMetrics | null { // 1 hour ahead
const currentHour = new Date().getHours();
const targetTime = new Date(Date.now() + timeAhead);
const targetHour = targetTime.getHours();
const pattern = this.predictiveModel.patterns.find(p =>
p.timeRange.start <= targetHour && targetHour < p.timeRange.end
);
return pattern ? pattern.expectedMetrics : null;
}
/**
* הגדרת רגישות התאמה
*/
setAdaptationThreshold(threshold: number): void {
this.adaptationThreshold = Math.max(0.1, Math.min(1.0, threshold));
}
/**
* כפיית פרופיל ספציפי
*/
forceProfile(profileId: string): boolean {
const profile = this.adaptationProfiles.get(profileId);
if (!profile) return false;
this.activeProfile = profile;
// Notify callbacks
this.adaptationCallbacks.forEach(callback => {
try {
callback(profile);
} catch (error) {
console.error('Forced adaptation callback error:', error);
}
});
console.log(`🔧 Forced network profile: ${profile.name}`);
return true;
}
/**
* קבלת נתונים סטטיסטיים
*/
getNetworkStatistics(): {
averageLatency: number;
averageBandwidth: number;
connectionStability: number;
adaptationCount: number;
mostUsedProfile: string;
modelAccuracy: number;
} {
const recentMetrics = this.metricsHistory.slice(-20);
const avgLatency = recentMetrics.length > 0 ?
recentMetrics.reduce((sum, m) => sum + m.latency, 0) / recentMetrics.length : 0;
const avgBandwidth = recentMetrics.length > 0 ?
recentMetrics.reduce((sum, m) => sum + m.bandwidth, 0) / recentMetrics.length : 0;
// Calculate stability as inverse of jitter variance
const jitters = recentMetrics.map(m => m.jitter);
const avgJitter = jitters.reduce((sum, j) => sum + j, 0) / Math.max(jitters.length, 1);
const jitterVariance = jitters.reduce((sum, j) => sum + Math.pow(j - avgJitter, 2), 0) / Math.max(jitters.length, 1);
const stability = Math.max(0, 1 - (jitterVariance / 1000)); // Normalize
const adaptationEvents = this.eventHistory.filter(e => e.type === 'adaptation_triggered');
// Find most used profile
const profileUsage: { [id: string]: number } = {};
adaptationEvents.forEach(event => {
const profileId = event.adaptationApplied || 'unknown';
profileUsage[profileId] = (profileUsage[profileId] || 0) + 1;
});
const mostUsedProfile = Object.entries(profileUsage)
.sort(([,a], [,b]) => b - a)[0]?.[0] || 'medium_quality';
return {
averageLatency: avgLatency,
averageBandwidth: avgBandwidth,
connectionStability: stability,
adaptationCount: adaptationEvents.length,
mostUsedProfile,
modelAccuracy: this.predictiveModel.accuracy
};
}
/**
* ניקוי משאבים
*/
dispose(): void {
this.stopMonitoring();
if (typeof window !== 'undefined') {
window.removeEventListener('online', (e: Event) => this.handleConnectionChange((e as any).isOnline));
window.removeEventListener('offline', (e: Event) => this.handleConnectionChange((e as any).isOnline));
}
this.adaptationCallbacks.clear();
this.metricsHistory.length = 0;
this.eventHistory.length = 0;
this.predictiveModel.learningData.length = 0;
console.log('🌐 Smart Network Adaptation System disposed');
}
}
export default SmartNetworkAdaptationSystem;