mirror of
https://github.com/DeNNiiInc/Connect-5.git
synced 2026-04-17 22:46:00 +00:00
FEATURE: Migrate username storage from localStorage to IndexedDB
- Created storage.js wrapper with IndexedDB support - Automatic fallback to localStorage if IndexedDB unavailable - Updated all username storage calls to use async API - Better performance and more storage capacity - Improved PWA compatibility Benefits: - 50MB+ storage vs 5-10MB localStorage - Async API doesn't block main thread - Better for future features (game history, stats, etc.)
This commit is contained in:
@@ -182,6 +182,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script src="storage.js"></script>
|
||||||
<script src="multiplayer.js"></script>
|
<script src="multiplayer.js"></script>
|
||||||
<script src="game.js"></script>
|
<script src="game.js"></script>
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class MultiplayerClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Show username modal immediately if not saved
|
// Show username modal immediately if not saved
|
||||||
const savedUsername = localStorage.getItem('connect5_username');
|
const savedUsername = await window.gameStorage.getItem('connect5_username');
|
||||||
if (!savedUsername) {
|
if (!savedUsername) {
|
||||||
this.showUsernameModal();
|
this.showUsernameModal();
|
||||||
} else {
|
} else {
|
||||||
@@ -92,13 +92,13 @@ class MultiplayerClient {
|
|||||||
}
|
}
|
||||||
}, 5000);
|
}, 5000);
|
||||||
|
|
||||||
tempSocket.on('connect', () => {
|
tempSocket.on('connect', async () => {
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
this.socket = tempSocket;
|
this.socket = tempSocket;
|
||||||
console.log('✅ Socket connected, listeners ready');
|
console.log('✅ Socket connected, listeners ready');
|
||||||
|
|
||||||
// Now that listeners are set up, handle auto-registration
|
// Now that listeners are set up, handle auto-registration
|
||||||
const savedUsername = localStorage.getItem('connect5_username') || this.username;
|
const savedUsername = await window.gameStorage.getItem('connect5_username') || this.username;
|
||||||
if (savedUsername) {
|
if (savedUsername) {
|
||||||
console.log('Auto-registering with saved username:', savedUsername);
|
console.log('Auto-registering with saved username:', savedUsername);
|
||||||
this.registerPlayer(savedUsername);
|
this.registerPlayer(savedUsername);
|
||||||
@@ -191,9 +191,9 @@ class MultiplayerClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Register player
|
// Register player
|
||||||
registerPlayer(username) {
|
async registerPlayer(username) {
|
||||||
this.username = username;
|
this.username = username;
|
||||||
localStorage.setItem('connect5_username', username);
|
await window.gameStorage.setItem('connect5_username', username);
|
||||||
|
|
||||||
// Hide username modal immediately for better UX
|
// Hide username modal immediately for better UX
|
||||||
const modal = document.getElementById('usernameModal');
|
const modal = document.getElementById('usernameModal');
|
||||||
@@ -220,14 +220,12 @@ class MultiplayerClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle registration response
|
// Handle registration response
|
||||||
handleRegistration(data) {
|
async handleRegistration(data) {
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
this.playerId = data.player.id;
|
this.playerId = data.player.id;
|
||||||
this.username = data.player.username;
|
this.username = data.player.username;
|
||||||
|
await window.gameStorage.setItem('connect5_username', this.username);
|
||||||
// Save username to localStorage for auto-login
|
console.log('Username saved to IndexedDB');
|
||||||
localStorage.setItem('connect5_username', this.username);
|
|
||||||
console.log('Username saved to localStorage');
|
|
||||||
|
|
||||||
// Hide username modal (if visible)
|
// Hide username modal (if visible)
|
||||||
const modal = document.getElementById('usernameModal');
|
const modal = document.getElementById('usernameModal');
|
||||||
|
|||||||
140
storage.js
Normal file
140
storage.js
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
// IndexedDB wrapper for Connect-5 game data storage
|
||||||
|
class GameStorage {
|
||||||
|
constructor() {
|
||||||
|
this.dbName = 'Connect5DB';
|
||||||
|
this.dbVersion = 1;
|
||||||
|
this.storeName = 'gameData';
|
||||||
|
this.db = null;
|
||||||
|
this.isIndexedDBSupported = this.checkIndexedDBSupport();
|
||||||
|
}
|
||||||
|
|
||||||
|
checkIndexedDBSupport() {
|
||||||
|
return 'indexedDB' in window;
|
||||||
|
}
|
||||||
|
|
||||||
|
async init() {
|
||||||
|
if (!this.isIndexedDBSupported) {
|
||||||
|
console.warn('IndexedDB not supported, falling back to localStorage');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const request = indexedDB.open(this.dbName, this.dbVersion);
|
||||||
|
|
||||||
|
request.onerror = () => {
|
||||||
|
console.error('IndexedDB failed to open:', request.error);
|
||||||
|
reject(request.error);
|
||||||
|
};
|
||||||
|
|
||||||
|
request.onsuccess = () => {
|
||||||
|
this.db = request.result;
|
||||||
|
console.log('✅ IndexedDB initialized successfully');
|
||||||
|
resolve(this.db);
|
||||||
|
};
|
||||||
|
|
||||||
|
request.onupgradeneeded = (event) => {
|
||||||
|
const db = event.target.result;
|
||||||
|
|
||||||
|
// Create object store if it doesn't exist
|
||||||
|
if (!db.objectStoreNames.contains(this.storeName)) {
|
||||||
|
db.createObjectStore(this.storeName, { keyPath: 'key' });
|
||||||
|
console.log('📦 Created IndexedDB object store');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async setItem(key, value) {
|
||||||
|
// Fallback to localStorage if IndexedDB not supported
|
||||||
|
if (!this.isIndexedDBSupported || !this.db) {
|
||||||
|
localStorage.setItem(key, value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const transaction = this.db.transaction([this.storeName], 'readwrite');
|
||||||
|
const store = transaction.objectStore(this.storeName);
|
||||||
|
const request = store.put({ key, value });
|
||||||
|
|
||||||
|
request.onsuccess = () => resolve();
|
||||||
|
request.onerror = () => {
|
||||||
|
console.error('IndexedDB setItem failed, falling back to localStorage');
|
||||||
|
localStorage.setItem(key, value);
|
||||||
|
reject(request.error);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async getItem(key) {
|
||||||
|
// Fallback to localStorage if IndexedDB not supported
|
||||||
|
if (!this.isIndexedDBSupported || !this.db) {
|
||||||
|
return localStorage.getItem(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const transaction = this.db.transaction([this.storeName], 'readonly');
|
||||||
|
const store = transaction.objectStore(this.storeName);
|
||||||
|
const request = store.get(key);
|
||||||
|
|
||||||
|
request.onsuccess = () => {
|
||||||
|
const result = request.result;
|
||||||
|
resolve(result ? result.value : null);
|
||||||
|
};
|
||||||
|
|
||||||
|
request.onerror = () => {
|
||||||
|
console.error('IndexedDB getItem failed, falling back to localStorage');
|
||||||
|
resolve(localStorage.getItem(key));
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async removeItem(key) {
|
||||||
|
// Fallback to localStorage if IndexedDB not supported
|
||||||
|
if (!this.isIndexedDBSupported || !this.db) {
|
||||||
|
localStorage.removeItem(key);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const transaction = this.db.transaction([this.storeName], 'readwrite');
|
||||||
|
const store = transaction.objectStore(this.storeName);
|
||||||
|
const request = store.delete(key);
|
||||||
|
|
||||||
|
request.onsuccess = () => resolve();
|
||||||
|
request.onerror = () => {
|
||||||
|
console.error('IndexedDB removeItem failed, falling back to localStorage');
|
||||||
|
localStorage.removeItem(key);
|
||||||
|
reject(request.error);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async clear() {
|
||||||
|
// Fallback to localStorage if IndexedDB not supported
|
||||||
|
if (!this.isIndexedDBSupported || !this.db) {
|
||||||
|
localStorage.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const transaction = this.db.transaction([this.storeName], 'readwrite');
|
||||||
|
const store = transaction.objectStore(this.storeName);
|
||||||
|
const request = store.clear();
|
||||||
|
|
||||||
|
request.onsuccess = () => resolve();
|
||||||
|
request.onerror = () => {
|
||||||
|
console.error('IndexedDB clear failed, falling back to localStorage');
|
||||||
|
localStorage.clear();
|
||||||
|
reject(request.error);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create global instance
|
||||||
|
window.gameStorage = new GameStorage();
|
||||||
|
|
||||||
|
// Initialize on page load
|
||||||
|
window.gameStorage.init().catch(err => {
|
||||||
|
console.warn('Failed to initialize IndexedDB, using localStorage fallback:', err);
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user