mirror of
https://github.com/cliffe/BreakEscape.git
synced 2026-02-20 13:50:46 +00:00
fix: refactor item giving and unlock handling for improved async processing and server synchronization
This commit is contained in:
@@ -99,17 +99,23 @@ export function processGameActionTags(tags, ui) {
|
||||
break;
|
||||
}
|
||||
|
||||
const giveResult = window.NPCGameBridge.giveItem(npcId, itemType);
|
||||
if (giveResult.success) {
|
||||
result.success = true;
|
||||
result.message = `📦 Received: ${giveResult.item.name}`;
|
||||
if (ui) ui.showNotification(result.message, 'success');
|
||||
console.log('✅ Item given successfully:', giveResult);
|
||||
} else {
|
||||
result.message = `⚠️ ${giveResult.error}`;
|
||||
if (ui) ui.showNotification(result.message, 'warning');
|
||||
console.warn('⚠️ Item give failed:', giveResult);
|
||||
}
|
||||
// giveItem is async (awaits addToInventory so server inventory is confirmed).
|
||||
// Use .then() since we can't await inside forEach.
|
||||
// Mark result as success optimistically - the conversation continues
|
||||
// immediately while the inventory sync happens in the background.
|
||||
result.success = true;
|
||||
result.message = `📦 Receiving: ${itemType}`;
|
||||
window.NPCGameBridge.giveItem(npcId, itemType).then(giveResult => {
|
||||
if (giveResult.success) {
|
||||
console.log('✅ Item given and server inventory synced:', giveResult);
|
||||
if (ui) ui.showNotification(`📦 Received: ${giveResult.item.name}`, 'success');
|
||||
} else {
|
||||
console.warn('⚠️ Item give failed:', giveResult);
|
||||
if (ui) ui.showNotification(`⚠️ ${giveResult.error}`, 'warning');
|
||||
}
|
||||
}).catch(error => {
|
||||
console.error('❌ giveItem error:', error);
|
||||
});
|
||||
} else {
|
||||
result.message = '⚠️ give_item requires item type parameter';
|
||||
console.warn(result.message);
|
||||
|
||||
@@ -392,12 +392,20 @@ export function startKeySelectionMinigame(lockable, type, playerKeys, requiredKe
|
||||
requiredKeyId: requiredKeyId,
|
||||
onComplete: (success, result) => {
|
||||
if (success) {
|
||||
console.log('KEY SELECTION SUCCESS');
|
||||
window.gameAlert('Successfully unlocked with the correct key!', 'success', 'Unlock Successful', 4000);
|
||||
// Detect which mode completed the unlock while currentMinigame is still live.
|
||||
// keyMode is true → player used a physical key
|
||||
// keyMode is false → player switched to and completed lockpick mode
|
||||
const keyMode = window.MinigameFramework?.currentMinigame?.keyMode;
|
||||
const unlockMethod = keyMode === false ? 'lockpick' : 'key';
|
||||
console.log(`🔓 KEY SELECTION SUCCESS via method='${unlockMethod}' (keyMode=${keyMode})`);
|
||||
const successMsg = unlockMethod === 'lockpick'
|
||||
? 'Successfully picked the lock!'
|
||||
: 'Successfully unlocked with the correct key!';
|
||||
window.gameAlert(successMsg, 'success', 'Unlock Successful', 4000);
|
||||
// Small delay to ensure minigame cleanup completes before room loading
|
||||
if (unlockTargetCallback) {
|
||||
setTimeout(() => {
|
||||
unlockTargetCallback(lockable, type, lockable.layer);
|
||||
unlockTargetCallback(lockable, type, lockable.layer, unlockMethod);
|
||||
}, 100);
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -171,7 +171,7 @@ export class NPCGameBridge {
|
||||
* @param {string} itemType - Type of item to give (optional - gives first if null)
|
||||
* @returns {Object} Result with success status
|
||||
*/
|
||||
giveItem(npcId, itemType = null) {
|
||||
async giveItem(npcId, itemType = null) {
|
||||
if (!npcId) {
|
||||
const result = { success: false, error: 'No npcId provided' };
|
||||
this._logAction('giveItem', { npcId, itemType }, result);
|
||||
@@ -224,10 +224,18 @@ export class NPCGameBridge {
|
||||
texture: { key: item.type }
|
||||
};
|
||||
|
||||
// Add to player inventory
|
||||
window.addToInventory(tempSprite);
|
||||
// Await addToInventory so server inventory is confirmed before removing from NPC.
|
||||
// This prevents the race condition where validate_unlock is called before the
|
||||
// inventory POST /inventory request completes, causing a spurious 422.
|
||||
const added = await window.addToInventory(tempSprite);
|
||||
|
||||
// Remove from NPC's inventory
|
||||
if (!added) {
|
||||
// addToInventory returns false for duplicates (already in inventory) or server rejection.
|
||||
// Treat already-in-inventory as success; true failures are logged by addToInventory itself.
|
||||
console.warn(`[NPCGameBridge] addToInventory returned false for ${item.type} from ${npcId} - may already be in inventory`);
|
||||
}
|
||||
|
||||
// Remove from NPC's inventory (after server confirms)
|
||||
npc.itemsHeld.splice(itemIndex, 1);
|
||||
|
||||
// Emit event to update Ink variables
|
||||
|
||||
@@ -161,9 +161,12 @@ export function handleUnlock(lockable, type) {
|
||||
if (playerKeys.length > 0) {
|
||||
// Keys take priority - go straight to key selection
|
||||
console.log('KEYS AVAILABLE - STARTING KEY SELECTION');
|
||||
// Wrap unlockTarget to notify server first
|
||||
const unlockWithServerNotification = async (lockable, type, layer) => {
|
||||
const serverResponse = await notifyServerUnlock(lockable, type, 'key');
|
||||
// Wrap unlockTarget to notify server first.
|
||||
// method is passed from the key selection minigame's onComplete:
|
||||
// 'key' → player used a physical key from inventory
|
||||
// 'lockpick' → player switched to and completed pick mode
|
||||
const unlockWithServerNotification = async (lockable, type, layer, method = 'key') => {
|
||||
const serverResponse = await notifyServerUnlock(lockable, type, method);
|
||||
unlockTarget(lockable, type, layer, serverResponse);
|
||||
};
|
||||
startKeySelectionMinigame(lockable, type, playerKeys, requiredKey, unlockWithServerNotification);
|
||||
|
||||
Reference in New Issue
Block a user