fixes
This commit is contained in:
127
party/index.ts
127
party/index.ts
@@ -89,74 +89,102 @@ export default class GameServer implements Party.Server {
|
||||
async onMessage(message: string, sender: Party.Connection) {
|
||||
const data = JSON.parse(message) as Message;
|
||||
|
||||
let currentUserId: string;
|
||||
let currentUserName: string;
|
||||
let isAuthenticated = false;
|
||||
|
||||
// Verify the Clerk token for authenticated messages
|
||||
if ('token' in data && data.token) {
|
||||
try {
|
||||
const sessionClaims = await verifyToken(data.token, {
|
||||
jwtKey: this.party.env.CLERK_JWT_KEY as string,
|
||||
});
|
||||
const authenticatedUserId = sessionClaims.sub;
|
||||
currentUserId = sessionClaims.sub;
|
||||
isAuthenticated = true;
|
||||
|
||||
// Ensure the userId from the client matches the authenticated userId
|
||||
if (authenticatedUserId !== data.userId) {
|
||||
console.warn(`User ID mismatch: Client sent ${data.userId}, but token is for ${authenticatedUserId}`);
|
||||
if (currentUserId !== data.userId) {
|
||||
console.warn(`User ID mismatch: Client sent ${data.userId}, but token is for ${currentUserId}`);
|
||||
sender.close(); // Close connection for potential tampering
|
||||
return;
|
||||
}
|
||||
|
||||
// Update user info on the server with authenticated data
|
||||
if (!this.gameState.users[authenticatedUserId]) {
|
||||
this.gameState.users[authenticatedUserId] = {
|
||||
name: data.userName, // Use the name provided by the client, which comes from Clerk
|
||||
clicks: 0,
|
||||
lastSeen: Date.now(),
|
||||
bonusMultiplier: 1 // Initialize bonus multiplier
|
||||
};
|
||||
}
|
||||
this.gameState.users[authenticatedUserId].lastSeen = Date.now();
|
||||
this.gameState.users[authenticatedUserId].name = data.userName; // Update name in case it changed
|
||||
// Ensure bonusMultiplier is initialized if it somehow wasn't
|
||||
if (this.gameState.users[authenticatedUserId].bonusMultiplier === undefined) {
|
||||
this.gameState.users[authenticatedUserId].bonusMultiplier = 1;
|
||||
}
|
||||
|
||||
switch (data.type) {
|
||||
case 'user-join':
|
||||
// User join is handled by the token verification and user state update above
|
||||
break;
|
||||
case 'click':
|
||||
this.handleClick(data, authenticatedUserId);
|
||||
break;
|
||||
case 'purchase-upgrade':
|
||||
this.handlePurchaseUpgrade(data, authenticatedUserId);
|
||||
break;
|
||||
case 'apply-multiplier-bonus': // Handle new message type
|
||||
this.handleApplyMultiplierBonus(data, authenticatedUserId);
|
||||
break;
|
||||
}
|
||||
currentUserName = data.userName; // Use name from client, which comes from Clerk
|
||||
} catch (error) {
|
||||
console.error('Clerk token verification failed:', error);
|
||||
sender.close(); // Close connection if token is invalid
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// For messages without a token (e.g., initial connection before token is sent, or unauthenticated actions)
|
||||
// For this game, we only allow authenticated actions.
|
||||
console.warn('Received unauthenticated message, closing connection.');
|
||||
sender.close();
|
||||
return;
|
||||
// Handle unauthenticated messages (guest users)
|
||||
currentUserId = data.userId;
|
||||
currentUserName = data.userName;
|
||||
isAuthenticated = false;
|
||||
|
||||
// Only allow 'user-join' for unauthenticated users.
|
||||
// Other actions like 'click', 'purchase-upgrade', 'apply-multiplier-bonus' are ignored.
|
||||
if (data.type !== 'user-join') {
|
||||
console.warn(`Received unauthenticated message of type '${data.type}' from ${currentUserId}. Action ignored.`);
|
||||
this.broadcast(); // Still broadcast game state to keep guests updated
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Only update user info in gameState for authenticated users
|
||||
if (isAuthenticated) {
|
||||
if (!this.gameState.users[currentUserId]) {
|
||||
this.gameState.users[currentUserId] = {
|
||||
name: currentUserName,
|
||||
clicks: 0,
|
||||
lastSeen: Date.now(),
|
||||
bonusMultiplier: 1 // Initialize bonus multiplier
|
||||
};
|
||||
}
|
||||
this.gameState.users[currentUserId].lastSeen = Date.now();
|
||||
this.gameState.users[currentUserId].name = currentUserName; // Update name in case it changed
|
||||
// Ensure bonusMultiplier is initialized if it somehow wasn't
|
||||
if (this.gameState.users[currentUserId].bonusMultiplier === undefined) {
|
||||
this.gameState.users[currentUserId].bonusMultiplier = 1;
|
||||
}
|
||||
}
|
||||
|
||||
switch (data.type) {
|
||||
case 'user-join':
|
||||
// For authenticated users, user join is handled by the user state update above.
|
||||
// For guest users, no action is needed here as they are not added to gameState.users.
|
||||
break;
|
||||
case 'click':
|
||||
if (isAuthenticated) {
|
||||
this.handleClick(data, currentUserId);
|
||||
} else {
|
||||
console.warn(`Unauthenticated click from ${currentUserId} ignored.`);
|
||||
}
|
||||
break;
|
||||
case 'purchase-upgrade':
|
||||
if (isAuthenticated) {
|
||||
this.handlePurchaseUpgrade(data, currentUserId);
|
||||
} else {
|
||||
console.warn(`Unauthenticated purchase-upgrade from ${currentUserId} ignored.`);
|
||||
}
|
||||
break;
|
||||
case 'apply-multiplier-bonus':
|
||||
if (isAuthenticated) {
|
||||
this.handleApplyMultiplierBonus(data, currentUserId);
|
||||
} else {
|
||||
console.warn(`Unauthenticated apply-multiplier-bonus from ${currentUserId} ignored.`);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
this.broadcast();
|
||||
}
|
||||
|
||||
// handleUserJoin is now largely integrated into onMessage's token verification
|
||||
// Keeping it for now, but it might become redundant or simplified.
|
||||
handleUserJoin(data: UserJoinMessage) {
|
||||
// This function is now mostly handled by the onMessage token verification logic
|
||||
// It ensures the user exists in gameState.users and updates lastSeen/name.
|
||||
// No explicit action needed here beyond what onMessage does.
|
||||
}
|
||||
// handleUserJoin is now fully integrated into onMessage and can be removed or simplified.
|
||||
// Removing it as its logic is now directly in onMessage.
|
||||
// handleUserJoin(data: UserJoinMessage) {
|
||||
// // This function is now mostly handled by the onMessage token verification logic
|
||||
// // It ensures the user exists in gameState.users and updates lastSeen/name.
|
||||
// // No explicit action needed here beyond what onMessage does.
|
||||
// }
|
||||
|
||||
handleClick(data: ClickMessage, authenticatedUserId: string) {
|
||||
// Apply global click multiplier and user-specific bonus multiplier
|
||||
@@ -197,10 +225,9 @@ export default class GameServer implements Party.Server {
|
||||
|
||||
if (!upgrade || !currentUpgrade) return;
|
||||
|
||||
const userClicks = this.gameState.users[authenticatedUserId]?.clicks || 0;
|
||||
|
||||
if (userClicks >= currentUpgrade.cost) {
|
||||
this.gameState.users[authenticatedUserId].clicks -= currentUpgrade.cost;
|
||||
// Check affordability against totalClicks
|
||||
if (this.gameState.totalClicks >= currentUpgrade.cost) {
|
||||
this.gameState.totalClicks -= currentUpgrade.cost; // Deduct from totalClicks
|
||||
currentUpgrade.owned += 1;
|
||||
currentUpgrade.cost = Math.floor(upgrade.baseCost * Math.pow(upgrade.multiplier, currentUpgrade.owned));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user