Skip to content

feat(dungeons): instanced underworld dungeon portal and keystone attunement engine - #201

Open
angelTomo9 wants to merge 1 commit into
Bitcoindefi:mainfrom
angelTomo9:feat-underworld-dungeon-1787864475000
Open

feat(dungeons): instanced underworld dungeon portal and keystone attunement engine#201
angelTomo9 wants to merge 1 commit into
Bitcoindefi:mainfrom
angelTomo9:feat-underworld-dungeon-1787864475000

Conversation

@angelTomo9

Copy link
Copy Markdown

Summary

Implements an instanced underworld dungeon portal and keystone attunement engine for OpenAO MMORPG.

Features

  • Dungeon difficulty tiers (Normal, Heroic, Mythic Keystone)
  • Party member level and attunement key requirements
  • Dynamic instance expiration timers and auto-collapse
  • Boss chamber lockouts and encounter tracking
  • Time-scaled reward chest distribution (Bronze, Silver, Gold, Mythic Cache)
  • Full unit test coverage under Vitest

Comment on lines +138 to +152
if (action === "LOCK_CHAMBER") {
instance.isBossChamberLocked = true;
return { success: true, instanceCompleted: false };
}

if (action === "UNLOCK_CHAMBER") {
instance.isBossChamberLocked = false;
return { success: true, instanceCompleted: false };
}

if (action === "DEFEAT_BOSS") {
instance.defeatedBosses = Math.min(instance.totalBosses, instance.defeatedBosses + 1);
instance.isBossChamberLocked = false;

if (instance.defeatedBosses >= instance.totalBosses) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Bug: Boss chamber lockout is never enforced on DEFEAT_BOSS

LOCK_CHAMBER sets isBossChamberLocked = true, but DEFEAT_BOSS never checks that flag and immediately resets it to false, so a locked chamber does nothing to block boss defeats. The advertised 'boss chamber lockout' feature is effectively decorative. Guard DEFEAT_BOSS by returning a failure when instance.isBossChamberLocked is true.

Reject boss defeats while the chamber is locked.:

if (action === "DEFEAT_BOSS") {
    if (instance.isBossChamberLocked) {
        return { success: false, instanceCompleted: false, reason: "Boss chamber is locked." };
    }
    instance.defeatedBosses = Math.min(instance.totalBosses, instance.defeatedBosses + 1);
    instance.isBossChamberLocked = false;
  • Apply fix

Check the box to apply the fix or reply for a change | Was this helpful? React with 👍 / 👎

Comment on lines +85 to +88
const allMembers = [leader, ...party.filter((p) => p.playerId !== leader.playerId)];
if (allMembers.length > dungeon.maxPartySize) {
return { success: false, reason: `Party exceeds maximum capacity of ${dungeon.maxPartySize} players.` };
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Edge Case: Duplicate party members are not deduplicated

openPortal only filters the leader out of the party; duplicate entries with the same playerId among the remaining party members pass through unchanged, inflating partyMembers and the effective party count (and potentially bypassing the maxPartySize check for real distinct players). Deduplicate by playerId before the capacity check.

Deduplicate all members (including leader) by playerId.:

const seen = new Set<string>();
const allMembers = [leader, ...party].filter((p) => {
    if (seen.has(p.playerId)) return false;
    seen.add(p.playerId);
    return true;
});
  • Apply fix

Check the box to apply the fix or reply for a change | Was this helpful? React with 👍 / 👎


const durationMs = dungeon.baseDurationMinutes * 60 * 1000;
const instance: ActiveDungeonInstance = {
instanceId: `inst_${keystone.dungeonId}_${currentEpochMs}`,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Bug: instanceId can collide for portals opened in the same ms

instanceId is built only from keystone.dungeonId and currentEpochMs, so two portals for the same dungeon opened in the same millisecond (or with the same caller-supplied timestamp) generate identical ids, which can corrupt downstream tracking keyed by instance id. Append a random/UUID suffix or a monotonic counter to guarantee uniqueness.

Add a random suffix so concurrent opens don't collide.:

instanceId: `inst_${keystone.dungeonId}_${currentEpochMs}_${Math.random().toString(36).slice(2, 8)}`,
  • Apply fix

Check the box to apply the fix or reply for a change | Was this helpful? React with 👍 / 👎

@gitar-bot

gitar-bot Bot commented Aug 27, 2026

Copy link
Copy Markdown
Code Review ⚠️ Changes requested 0 resolved / 3 findings

Implements instanced underworld dungeon portals with keystone attunement and boss lockout mechanics, but three issues prevent merge: the boss chamber lockout flag is never enforced on DEFEAT_BOSS (making it non-functional), duplicate party members are not deduplicated before the capacity check, and instanceId collisions are possible when portals open in the same millisecond.

⚠️ Bug: Boss chamber lockout is never enforced on DEFEAT_BOSS

📄 api/src/lib/underworldDungeonPortal.ts:138-152

LOCK_CHAMBER sets isBossChamberLocked = true, but DEFEAT_BOSS never checks that flag and immediately resets it to false, so a locked chamber does nothing to block boss defeats. The advertised 'boss chamber lockout' feature is effectively decorative. Guard DEFEAT_BOSS by returning a failure when instance.isBossChamberLocked is true.

Reject boss defeats while the chamber is locked.
if (action === "DEFEAT_BOSS") {
    if (instance.isBossChamberLocked) {
        return { success: false, instanceCompleted: false, reason: "Boss chamber is locked." };
    }
    instance.defeatedBosses = Math.min(instance.totalBosses, instance.defeatedBosses + 1);
    instance.isBossChamberLocked = false;
💡 Edge Case: Duplicate party members are not deduplicated

📄 api/src/lib/underworldDungeonPortal.ts:85-88

openPortal only filters the leader out of the party; duplicate entries with the same playerId among the remaining party members pass through unchanged, inflating partyMembers and the effective party count (and potentially bypassing the maxPartySize check for real distinct players). Deduplicate by playerId before the capacity check.

Deduplicate all members (including leader) by playerId.
const seen = new Set<string>();
const allMembers = [leader, ...party].filter((p) => {
    if (seen.has(p.playerId)) return false;
    seen.add(p.playerId);
    return true;
});
💡 Bug: instanceId can collide for portals opened in the same ms

📄 api/src/lib/underworldDungeonPortal.ts:101

instanceId is built only from keystone.dungeonId and currentEpochMs, so two portals for the same dungeon opened in the same millisecond (or with the same caller-supplied timestamp) generate identical ids, which can corrupt downstream tracking keyed by instance id. Append a random/UUID suffix or a monotonic counter to guarantee uniqueness.

Add a random suffix so concurrent opens don't collide.
instanceId: `inst_${keystone.dungeonId}_${currentEpochMs}_${Math.random().toString(36).slice(2, 8)}`,
🤖 Prompt for agents
Code Review: Implements instanced underworld dungeon portals with keystone attunement and boss lockout mechanics, but three issues prevent merge: the boss chamber lockout flag is never enforced on DEFEAT_BOSS (making it non-functional), duplicate party members are not deduplicated before the capacity check, and instanceId collisions are possible when portals open in the same millisecond.

1. ⚠️ Bug: Boss chamber lockout is never enforced on DEFEAT_BOSS
   Files: api/src/lib/underworldDungeonPortal.ts:138-152

   LOCK_CHAMBER sets `isBossChamberLocked = true`, but DEFEAT_BOSS never checks that flag and immediately resets it to false, so a locked chamber does nothing to block boss defeats. The advertised 'boss chamber lockout' feature is effectively decorative. Guard DEFEAT_BOSS by returning a failure when `instance.isBossChamberLocked` is true.

   Fix (Reject boss defeats while the chamber is locked.):
   if (action === "DEFEAT_BOSS") {
       if (instance.isBossChamberLocked) {
           return { success: false, instanceCompleted: false, reason: "Boss chamber is locked." };
       }
       instance.defeatedBosses = Math.min(instance.totalBosses, instance.defeatedBosses + 1);
       instance.isBossChamberLocked = false;

2. 💡 Edge Case: Duplicate party members are not deduplicated
   Files: api/src/lib/underworldDungeonPortal.ts:85-88

   openPortal only filters the leader out of the party; duplicate entries with the same playerId among the remaining party members pass through unchanged, inflating `partyMembers` and the effective party count (and potentially bypassing the maxPartySize check for real distinct players). Deduplicate by playerId before the capacity check.

   Fix (Deduplicate all members (including leader) by playerId.):
   const seen = new Set<string>();
   const allMembers = [leader, ...party].filter((p) => {
       if (seen.has(p.playerId)) return false;
       seen.add(p.playerId);
       return true;
   });

3. 💡 Bug: instanceId can collide for portals opened in the same ms
   Files: api/src/lib/underworldDungeonPortal.ts:101

   instanceId is built only from keystone.dungeonId and currentEpochMs, so two portals for the same dungeon opened in the same millisecond (or with the same caller-supplied timestamp) generate identical ids, which can corrupt downstream tracking keyed by instance id. Append a random/UUID suffix or a monotonic counter to guarantee uniqueness.

   Fix (Add a random suffix so concurrent opens don't collide.):
   instanceId: `inst_${keystone.dungeonId}_${currentEpochMs}_${Math.random().toString(36).slice(2, 8)}`,

Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Showing less information.

Comment with these commands to change the behavior for this request:

Auto-apply Compact
gitar auto-apply:on         
gitar display:verbose         

Important

Your trial ends in 5 days — upgrade now to keep code review, CI analysis, auto-apply, custom automations, and more.

Was this helpful? React with 👍 / 👎 | Gitar

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant