Skip to content

Next#104

Merged
Await-0x merged 15 commits intomainfrom
next
Jan 16, 2026
Merged

Next#104
Await-0x merged 15 commits intomainfrom
next

Conversation

@Await-0x
Copy link
Member

@Await-0x Await-0x commented Jan 16, 2026

Summary by CodeRabbit

  • New Features
    • Added Advanced Mode toggle with combat insights panel showing fight probabilities, win rates, damage metrics, and XP/gold rewards
    • Introduced Active Players display tracking real-time survivor count and player statistics
    • Added gear preset system for quick equipment configurations (cloth, hide, metal presets)
    • Implemented AI-powered gear suggestion system for combat optimization
    • Added game filtering by Active and Completed status with watch functionality for spectating completed adventures
    • Introduced exploration analytics displaying lethal chance calculations for ambush and trap encounters

✏️ Tip: You can customize this high-level summary in your review settings.

@vercel
Copy link

vercel bot commented Jan 16, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
loot-survivor-2 Ready Ready Preview, Comment Jan 16, 2026 8:47pm

Request Review

@coderabbitai
Copy link

coderabbitai bot commented Jan 16, 2026

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

This pull request introduces an advanced mode feature across the client, enabling combat simulation with Web Workers, gear preset application, exploration risk analytics, and enhanced UI elements. It adds comprehensive combat outcome calculation (deterministic and Monte Carlo), exploration lethal-chance computations, gear suggestion workflows, and active player tracking. The changes refactor payment flow to use numeric identifiers, rename mobile component pairs (GameSettings* → CustomizeGame*), and conditionally render advanced analytics and controls throughout desktop and mobile overlays.

Changes

Cohort / File(s) Summary
Component Renames
client/src/App.tsx, client/src/mobile/components/CustomizeGame.tsx, client/src/mobile/components/CustomizeGameList.tsx
Renamed GameSettings/GameSettingsList to CustomizeGame/CustomizeGameList; updated import paths and function declarations.
Payment & Context
client/src/components/PaymentOptionsModal.tsx, client/src/contexts/controller.tsx
Payment modal footer now calls openBuyTicket on click with updated text; openBuyTicket passes numeric 3 instead of string identifier to openStarterPack.
Advanced Mode State
client/src/stores/uiStore.ts
Added advancedMode boolean and setAdvancedMode setter to UI store; persists via zustand/persist.
Desktop Settings Integration
client/src/desktop/components/Settings.tsx, client/src/desktop/overlays/Settings.tsx
Added Switch component and "Enable Advanced Mode" section bound to advancedMode/setAdvancedMode in both settings locations.
Desktop Advanced Combat
client/src/desktop/overlays/Combat.tsx
Integrated useCombatSimulation hook and added auto-last-hit combat loop, fight probability insights panel with damage/XP/gold metrics, Net HP projection, and potion coverage calculations; conditional rendering for advanced mode. Lines: +704/-27.
Desktop Advanced Stats & Gear
client/src/desktop/components/AdventurerStats.tsx
Integrated UI store and gear-suggestion workflow (handleSuggestGear); added renderAdvancedStatsView with stat increment/decrement controls and per-stat totals; extended equipment damage indicators for advanced mode. Lines: +180/-9.
Desktop Gear Presets & Inventory
client/src/desktop/overlays/Inventory.tsx
Added useGearPresets hook and preset UI (CLOTH, HIDE, METAL buttons); integrated crit damage indicators in advanced mode for both equipped and bag items; CharacterEquipment signature extended with disabledEquip prop. Lines: +164/-16.
Desktop Exploration Analytics
client/src/desktop/overlays/Explore.tsx
Integrated useExplorationWorker hook to compute lethal chances; conditionally renders lethal-chance panel (Ambush, Trap) in advanced mode. Lines: +65/-8.
Desktop Market & Insights
client/src/desktop/overlays/Market.tsx
Added tabbed UI (Market/Explore/Events) in advanced mode; integrated exploration insights (damage distributions, slot analytics); event log rendering with icon/metadata branching; item stat bonus indicators. Lines: +891/-194.
Desktop Tips & Beast
client/src/desktop/overlays/Tips.tsx, client/src/desktop/overlays/Beast.tsx
Tips overlay hidden when advancedMode is true; Beast component renders crit chance conditionally based on advancedMode.
Desktop Game Lists & Navigation
client/src/desktop/components/AdventurersList.tsx, client/src/desktop/pages/GamePage.tsx
AdventurersList adds tab-based filtering (Active/Completed) with watch button for completed games; GamePage removes setCurrentNetworkConfig from connector hook.
Desktop Active Players
client/src/desktop/overlays/ActivePlayers.tsx, client/src/desktop/overlays/MainMenu.tsx
New ActivePlayers overlay component fetches and displays live active players with level/health; mounted in MainMenu. Lines: +248/-0 (overlay) + 3 (MainMenu).
Desktop Watch & Events
client/src/desktop/pages/WatchPage.tsx
Integrated live event subscription via useDojoSDK; processes real-time events with setEventQueue and cleanup on unmount; conditional streaming path for in-progress games.
Mobile Advanced Screens
client/src/mobile/containers/BeastScreen.tsx, client/src/mobile/containers/ExploreScreen.tsx, client/src/mobile/containers/SettingsScreen.tsx
BeastScreen now accepts setIsBattling prop; integrated gear suggestion and combat simulation; ExploreScreen becomes proped (isExploring, setIsExploring) with lethal-chance rendering; SettingsScreen adds Advanced Mode toggle and game-setting controls. Lines: BeastScreen +729/-137, ExploreScreen +80/-4, SettingsScreen +87/-3.
Mobile Game Lists & Navigation
client/src/mobile/components/GameTokensList.tsx, client/src/mobile/components/BottomNav.tsx, client/src/mobile/pages/GamePage.tsx
GameTokensList adds tabs (Active/Completed) with watch flow and TheatersIcon; BottomNav extended with isExploring/isBattling props to disable actions during activity; GamePage manages exploration/battle state flags. Lines: GameTokensList +181/-112, BottomNav +44/-23, GamePage +22/-4.
Mobile Active Players & Header
client/src/mobile/components/ActivePlayers.tsx, client/src/mobile/components/Header.tsx, client/src/mobile/containers/MarketScreen.tsx
New ActivePlayers component (mobile) displays survivor count with expandable list; mounted in Header; MarketScreen adds item stat bonus display based on seed. Lines: ActivePlayers +227, Header +4/-2, MarketScreen +17/-1.
Mobile Event Handling & Menu
client/src/mobile/pages/WatchPage.tsx, client/src/mobile/contexts/GameDirector.tsx, client/src/mobile/components/HeaderMenu.tsx
WatchPage integrates live event subscription; GameDirector reads fastBattle/skipFirstBattle flags and adjusts event delay/starting sequence; HeaderMenu adds Game Settings modal with volume/advanced-mode/battle-speed controls. Lines: WatchPage +56/-4, GameDirector +35/-3, HeaderMenu +283/-122.
Combat Simulation Core
client/src/utils/combatSimulationCore.ts, client/src/utils/combatSimulation.ts, client/src/hooks/useCombatSimulation.ts, client/src/workers/combatSimulationWorker.ts
New comprehensive combat simulation module with deterministic and Monte Carlo strategies; worker orchestration with fallback; debounced hook wrapper with memoized stats and simulation-state hashing. Lines: Core +765, Wrapper +221, Hook +224, Worker +55.
Exploration Analytics
client/src/utils/exploration.ts, client/src/hooks/useExplorationWorker.ts, client/src/workers/explorationWorker.ts
New exploration module computing lethal chances, damage distributions, and encounter probabilities; Monte Carlo worker with deterministic RNG; hook manages worker lifecycle and input batching. Lines: Module +1255, Hook +126, Worker +554.
Gear Presets & Suggestions
client/src/utils/gearPresets.ts, client/src/utils/gearSuggestion.ts, client/src/utils/gearSuggestionShared.ts, client/src/hooks/useGearPresets.ts, client/src/workers/gearSuggestionWorker.ts
New gear preset system (cloth/hide/metal presets) and asynchronous gear suggestion engine with greedy pre-screening and combinatorial search; shared utilities and worker for parallel evaluation. Lines: Presets +161, Suggestion +377, Shared +351, Hook +105, Worker +21.
Game State & Utilities
client/src/stores/gameStore.ts, client/src/dojo/useGameTokens.ts, client/src/utils/events.ts, client/src/utils/queries.ts
gameStore adds equipGearPreset and applyGearSuggestion methods; useGameTokens exposes getActivePlayersCount and getPlayerNames helpers; events.ts adds processRawGameEvent converter; queries.ts updates to HistoricalToriiQueryBuilder.

Sequence Diagrams

sequenceDiagram
    participant Client as Client Code
    participant Hook as useCombatSimulation Hook
    participant Worker as Combat Worker
    participant Fallback as Inline Fallback
    participant Core as Combat Core

    Client->>Hook: useCombatSimulation(adventurer, beast, bag)
    Hook->>Hook: Compute state hash
    alt Hash unchanged
        Hook->>Client: Return cached result
    else Hash changed
        Hook->>Hook: Debounce (100ms)
        Hook->>Worker: postMessage({adventurer, beast, options})
        alt Worker available & responsive
            Worker->>Core: calculateCombatResult()
            Core-->>Worker: result
            Worker-->>Hook: postMessage(result)
            Hook->>Client: Return simulationResult
        else Worker error or timeout
            Hook->>Fallback: runSimulationInline()
            alt No stack overflow
                Fallback->>Core: calculateCombatResult()
                Core-->>Fallback: result
                Fallback-->>Hook: result
                Hook->>Client: Return simulationResult
            else Stack overflow
                Hook->>Client: Return defaultSimulationResult
            end
        end
    end
Loading
sequenceDiagram
    participant UI as Desktop Combat UI
    participant Sim as useCombatSimulation
    participant State as Game State
    participant Display as Combat Insights Panel

    UI->>Sim: Initialize with adventurer, beast, bag
    Sim->>Sim: Run simulation (worker or inline)
    Sim-->>UI: simulationResult { winRate, OTK, damageDistribution, rounds, xp, gold }
    UI->>UI: Calculate Net HP (potions - damage)
    UI->>Display: Render Fight/Flee/Gamble probabilities
    Display->>Display: Highlight winning outcome
    alt User clicks Fight
        UI->>State: dispatch attack
        State-->>UI: New state + events
    else User clicks Auto Last-Hit
        UI->>UI: Enter auto-loop until final round
        UI->>UI: Continue attack sequence
    end
Loading
sequenceDiagram
    participant Client as Client Code
    participant Hook as useExplorationWorker Hook
    participant Worker as Exploration Worker
    participant RNG as Deterministic RNG

    Client->>Hook: useExplorationWorker(adventurer, gameSettings)
    Hook->>Hook: Compute input hash
    alt Input unchanged
        Hook->>Client: Return cached (ambushLethalChance, trapLethalChance)
    else Input changed
        Hook->>Hook: Debounce (50ms)
        Hook->>Worker: postMessage({adventurer, gameSettings})
        Worker->>RNG: Initialize seed from adventurer state
        Worker->>Worker: Monte Carlo sampling (slots: armor slots + neck)
        loop For each slot
            Worker->>Worker: Simulate beast/obstacle damage with specials
            Worker->>Worker: Aggregate lethal outcomes
        end
        Worker-->>Hook: postMessage({ambushLethalChance, trapLethalChance})
        Hook->>Client: Update result state
        Client->>Client: Render lethal-chance panel in advanced mode
    end
Loading
sequenceDiagram
    participant UI as Desktop Inventory UI
    participant Hook as useGearPresets Hook
    participant Preset as Preset Engine
    participant Store as Game Store

    UI->>Hook: useGearPresets(adventurer, bag, enabled=true)
    Hook->>Hook: Compute inventory hash
    alt Inventory unchanged
        Hook->>UI: Return cached presets
    else Inventory changed
        Hook->>Preset: applyGearPreset(adventurer, bag, 'cloth')
        Preset->>Preset: Aggregate items by slot
        Preset->>Preset: Select best by level/power per slot
        Preset-->>Hook: { adventurer, bag, hasChanges: true }
        Hook->>Preset: applyGearPreset(adventurer, bag, 'hide')
        Preset-->>Hook: result
        Hook->>Preset: applyGearPreset(adventurer, bag, 'metal')
        Preset-->>Hook: result
        Hook->>UI: Return { presets: { cloth, hide, metal }, ... }
    end
    UI->>UI: Render 3 preset buttons in advanced mode
    alt User clicks CLOTH preset
        UI->>Store: equipGearPreset('cloth')
        Store->>Store: Apply preset + update bag
        Store-->>UI: New adventurer state
        UI->>UI: Re-render with updated gear
    end
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

  • Next #71: Modifies client/src/stores/uiStore.ts to add UI state flags (skipIntroOutro, skipAllAnimations) with persistence—directly parallels the advancedMode addition in this PR.
  • Next #72: Updates client/src/desktop/components/AdventurerStats.tsx and game store to modify stat selection flow—foundational work for the gear suggestion integration in this PR.
  • Obstacle Icons & Leaderboard #65: Adds a Leaderboard overlay mounted in MainMenu, mirroring the pattern used to add ActivePlayers overlay in this PR.

Poem

🐰 Hopping through combat with workers in flight,
Gear presets shimmer, advanced mode shines bright,
Monte Carlo dances with exploration's embrace,
Active players gather in cyberspace—
A warrior's toolkit, refined and precise,
Adventure awaits when you roll the dice!

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@claude
Copy link

claude bot commented Jan 16, 2026

Claude finished @Await-0x's task —— View job


Pull Request Review

I've completed my review of this large PR (48 files, 8594 additions). Here's my comprehensive analysis:

Review Checklist

  • Read repository guidelines (CLAUDE.md)
  • Review store changes and state management
  • Review new hooks and utility functions
  • Review worker implementations
  • Review UI component changes (mobile/desktop)
  • Check for security vulnerabilities
  • Assess performance implications
  • Evaluate code quality and best practices
  • Check test coverage
  • Provide comprehensive feedback

🎯 Overall Assessment

This is a substantial feature addition that introduces combat simulation, gear optimization, and exploration enhancements. The code quality is generally good, but there are several important concerns that should be addressed.

🔴 Critical Issues

1. Zero Test Coverage

  • Issue: No test files found for any of the new functionality
  • Impact: High - Complex combat simulation logic, worker implementations, and state management changes are completely untested
  • Recommendation: Add unit tests for:
    • combatSimulationCore.ts - Complex probability calculations
    • exploration.ts - Monte Carlo simulations
    • useCombatSimulation.ts - Hook logic and state management
    • Workers - Message handling and error scenarios

2. Worker Security Concerns

File: client/src/workers/combatSimulationWorker.ts:41-55

  • Issue: Uncontrolled execution of imported calculation functions in worker context
  • Security Risk: Workers run in isolated contexts but still need input validation
  • Recommendation: Add input validation for adventurer/beast data before processing

🟠 High Priority Issues

3. Performance Concerns

File: client/src/utils/combatSimulationCore.ts:6-7

export const MAX_DETERMINISTIC_STATE_VISITS = 80_000;
export const DEFAULT_MONTE_CARLO_SAMPLES = 10_000;
  • Issue: Very high computational limits could cause UI freezing
  • Impact: Poor user experience, especially on lower-end devices
  • Recommendation: Consider progressive rendering or reduced initial limits

File: client/src/hooks/useCombatSimulation.ts:106-145

  • Issue: Heavy dependency array in useMemo could trigger excessive recalculations
  • Recommendation: Break down dependencies or use more granular memoization

4. Memory Management Issues

File: client/src/utils/combatSimulationCore.ts:57-62

interface StateOutcome {
  damageDealtDistribution: Map<number, number>;
  damageTakenDistribution: Map<number, number>;
  roundsDistribution: Map<number, number>;
}
  • Issue: Large Maps created without clear cleanup strategy
  • Impact: Potential memory leaks in long-running sessions
  • Recommendation: Implement Map size limits or periodic cleanup

5. State Management Complexity

File: client/src/stores/gameStore.ts:148-183

  • Issue: Complex equipItem function does too many things (equipment, stats, bag management)
  • Impact: Hard to test, debug, and maintain
  • Recommendation: Split into smaller, focused functions

🟡 Medium Priority Issues

6. Error Handling Gaps

File: client/src/hooks/useCombatSimulation.ts:171-178

} catch (error) {
  console.error('[CombatSimulation] Error:', error);
}
  • Issue: Errors are logged but not exposed to UI for user feedback
  • Recommendation: Add error state to hook return value

7. Magic Numbers and Constants

File: client/src/utils/exploration.ts:14-24

  • Issue: Multiple hardcoded values without clear documentation
  • Recommendation: Move to constants file with explanatory comments

8. Type Safety Improvements

File: client/src/mobile/containers/BeastScreen.tsx:32-75

  • Issue: Non-null assertions (!) used without proper null checks
  • Example: beast!.baseName, adventurer!.health
  • Recommendation: Add proper null guards or use optional chaining

🟢 Positive Aspects

1. Excellent Performance Optimization

  • Smart debouncing in useCombatSimulation hook
  • Intelligent state hashing to prevent unnecessary recalculations
  • Web Workers for CPU-intensive tasks

2. Clean Architecture

  • Good separation of concerns between hooks, utilities, and components
  • Consistent use of Zustand for state management
  • Well-structured worker implementation

3. TypeScript Usage

  • Good interface definitions for complex data structures
  • Proper type exports and imports

📋 Specific Recommendations

  1. Add comprehensive tests - This should be the immediate priority
  2. Implement input validation in workers and critical calculation functions
  3. Add error boundaries around simulation components
  4. Profile performance on lower-end devices with the current computational limits
  5. Add user feedback for long-running operations
  6. Document the simulation algorithms - especially the Monte Carlo implementations
  7. Consider progressive enhancement - start with simpler calculations and upgrade to complex ones

🔍 Code Quality

  • Maintainability: Good - Well-organized structure
  • Readability: Good - Clear naming and organization
  • Performance: Concerning - High computational complexity needs monitoring
  • Security: Moderate - Input validation needed in workers

📈 Risk Assessment

  • Low Risk: UI components, store structure
  • Medium Risk: State management complexity
  • High Risk: Untested simulation logic, performance impact
  • Critical Risk: Zero test coverage for complex functionality

Recommendation: Address critical test coverage and performance issues before merging to main.


@claude
Copy link

claude bot commented Jan 16, 2026

Claude finished @Await-0x's task —— View job


PR Review Analysis

Reviewing this large PR with 8,596 additions across 48 files. I'll analyze the code quality, potential issues, and provide comprehensive feedback.

Todo List:

  • Review new worker implementations for performance and security
  • Analyze new utility functions and hooks
  • Check component changes for potential bugs
  • Evaluate store modifications
  • Assess overall architecture and patterns
  • Provide final recommendations

🔍 Comprehensive Review Findings

Strengths

Architecture & Performance

  • Excellent worker pattern implementation for CPU-intensive calculations
  • Smart memoization and debouncing in hooks to prevent unnecessary recalculations
  • Deterministic simulation approach with Monte Carlo fallbacks
  • Comprehensive state management with proper separation of concerns

Code Quality

  • Well-structured utilities with clear separation between simulation logic and UI
  • Good error handling patterns throughout workers and async operations
  • Consistent typing and interfaces across the codebase
  • Proper resource cleanup in React hooks and workers

⚠️ Security & Performance Concerns

1. RNG Predictability Risk (explorationWorker.ts:242-252)

const createDeterministicRng = (seedValue: number) => {
  let state = (Math.floor(seedValue) >>> 0) || 0x6d2b79f5;

Risk: While deterministic for reproducibility, the seed generation could be predictable if based on game state.
Recommendation: Consider using cryptographically secure entropy sources for initial seeds in production.

2. Stack Overflow Protection (combatSimulationCore.ts:338-602)

if (rounds >= MAX_ROUNDS_PER_FIGHT) {
  return { winProbability: 0, lethalProbability: 1, ... };
}

Issue: Good protection exists, but complex combat scenarios could still hit call stack limits.
Recommendation: Consider iterative approaches for deeply recursive scenarios.

3. Memory Management (useCombatSimulation.ts:180-216)

debounceTimerRef.current = setTimeout(() => {
  runSimulation(adventurer, beast, initialBeastStrike, simId, adventurer.action_count);
}, debounceMs);

Issue: Rapid component unmounting could leave promises running.
Recommendation: Add Promise.race with abort signals for better cleanup.

4. Worker Race Conditions (useExplorationWorker.ts:104-107)

if (pendingRef.current) {
  return; // Skip if already calculating
}

Issue: Small race condition window between flag setting and worker start.
Recommendation: Use atomic operations or worker queue management.

🎯 Component Quality Issues

5. Missing Error Boundaries (Multiple Components)

Large components like BeastScreen.tsx and Combat.tsx lack error boundaries for worker failures.
Recommendation: Add error boundaries around worker-dependent components.

6. Prop Drilling (HeaderMenu.tsx, Inventory.tsx)

Complex prop chains in mobile components suggest need for better state organization.
Recommendation: Consider additional context providers for deeply nested state.

📊 Test Coverage Gap

Critical Finding: No test files found in the codebase.

# No test scripts in package.json
# No *.test.* or *.spec.* files found

Recommendations for Testing:

  1. Unit tests for pure functions in /utils/
  2. Integration tests for worker communication
  3. Simulation validation tests for combat calculations
  4. Component tests for complex UI interactions

🔧 Store & State Management

7. Store Mutation Risk (gameStore.ts:148-183)

equipItem: (data: Item) => {
  let itemSlot = ItemUtils.getItemSlot(data.id).toLowerCase() as keyof Adventurer['equipment'];
  set((state) => {
    // Complex nested mutations

Issue: Complex object mutations could lead to state consistency issues.
Recommendation: Use Immer integration or immutable update patterns.

🏗️ Architecture Recommendations

8. Worker Pool Management

Current implementation creates workers on-demand. Consider a worker pool for better resource management:

// Recommended pattern
class WorkerPool {
  private workers: Worker[] = [];
  private queue: Task[] = [];
  
  async execute<T>(task: Task): Promise<T> {
    // Reuse existing workers when possible
  }
}

9. Type Safety Improvements

Several utility functions use any types that could be more specific:

// In BeastScreen.tsx:38
onItemClick: (item: any) => void  // Should be (item: Item) => void

10. Performance Monitoring

Consider adding performance monitoring for:

  • Worker execution times
  • Component render counts
  • Memory usage patterns

🎯 Final Recommendations

Priority 1 (Critical)

  1. Add test coverage - Start with unit tests for core utilities
  2. Implement error boundaries around worker-dependent components
  3. Address race conditions in worker management

Priority 2 (High)

  1. Improve RNG security for production use
  2. Add performance monitoring for complex calculations
  3. Strengthen type safety throughout the codebase

Priority 3 (Medium)

  1. Optimize state mutations in stores
  2. Reduce prop drilling in complex components
  3. Add worker pool management for better resource utilization

Approval Recommendation

Despite the identified issues, this PR introduces significant value with its sophisticated game calculation system and well-architected worker patterns. The issues are largely enhancement opportunities rather than blocking problems.

Recommendation: APPROVE with follow-up tasks to address the testing and security concerns in subsequent PRs.

The new features (combat simulation, exploration analysis, gear suggestions) are well-implemented and provide substantial gameplay improvements. The code demonstrates strong architectural thinking and attention to performance optimization.

@gemini-code-assist
Copy link

Summary of Changes

Hello @Await-0x, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly upgrades the game's analytical and strategic capabilities by introducing an 'Advanced Mode'. This mode provides players with in-depth combat and exploration data, intelligent gear recommendations, and live game monitoring. The changes involve extensive refactoring and the integration of Web Workers to maintain high performance while delivering complex calculations and detailed feedback.

Highlights

  • Advanced Mode Introduction: Introduced a new 'Advanced Mode' toggle in settings for both desktop and mobile clients, unlocking enhanced features and detailed insights across various game screens.
  • Combat Simulation & Gear Suggestion: Implemented a sophisticated combat simulation system, utilizing Web Workers for performance, to provide detailed fight probabilities, victory outcomes, and optimal gear suggestions in 'Advanced Mode'.
  • Exploration Insights: Added 'Ambush Lethal Chance' and 'Trap Lethal Chance' calculations to the exploration screen in 'Advanced Mode', powered by a Web Worker for Monte Carlo simulations.
  • Live Game Spectating: Enhanced the 'Watch Page' and 'Adventurers List' to support live event subscriptions for active games, allowing real-time spectating of ongoing adventures.
  • UI/UX Enhancements: Refactored several UI components, including renaming game settings, adding tabs for active/completed games, displaying critical damage indicators on items, and integrating an 'Active Players' overlay.
  • Performance Optimization: Leveraged Web Workers for computationally intensive tasks like combat and exploration simulations, ensuring a smoother and more responsive user experience.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@Await-0x Await-0x merged commit baa9819 into main Jan 16, 2026
6 checks passed
Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a significant new "Advanced Mode" to the application, adding a rich set of features for power users. Key additions include detailed combat simulations, exploration risk analysis, automatic gear suggestions, and live spectating of active games. To handle the increased computational load, several features have been implemented using Web Workers, which is a great approach for maintaining UI responsiveness.

The review identifies several areas for improvement, primarily related to code duplication between desktop and mobile components, and some opportunities to enhance code quality by removing magic numbers and improving type safety. There are also a couple of high-severity issues related to an inefficient data query and a hardcoded table name that should be addressed to ensure performance and maintainability.

Overall, this is a substantial and impressive feature addition. The suggestions provided aim to refine the implementation, improve code reuse, and ensure the long-term health of the codebase.

Comment on lines +175 to +232
useEffect(() => {
if (!advancedMode || !autoLastHitActive || !untilLastHit) {
return;
}

if (!adventurer || !beast) {
setAutoLastHitActive(false);
setLastHitActionCount(null);
setAttackInProgress(false);
return;
}

if (!simulationResult.hasOutcome) {
return;
}

if (isFinalRound) {
setAutoLastHitActive(false);
setLastHitActionCount(null);
setAttackInProgress(false);
return;
}

if (lastHitActionCount !== null && adventurer.action_count <= lastHitActionCount) {
return;
}

if (simulationActionCount === null || simulationActionCount !== adventurer.action_count) {
return;
}

setLastHitActionCount(adventurer.action_count);

const continueAttacking = async () => {
try {
setAttackInProgress(true);
setCombatLog(attackMessage);
await executeGameAction({ type: 'attack', untilDeath: false });
} catch (error) {
console.error('Failed to continue last-hit attack', error);
setAutoLastHitActive(false);
setLastHitActionCount(null);
setAttackInProgress(false);
}
};

void continueAttacking();
}, [
advancedMode,
autoLastHitActive,
untilLastHit,
simulationResult.hasOutcome,
simulationResult.maxRounds,
isFinalRound,
executeGameAction,
adventurer?.action_count,
beast?.id,
]);

Choose a reason for hiding this comment

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

high

The 'auto last hit' logic in this useEffect is duplicated from the desktop CombatOverlay. This complex logic should be extracted into a shared custom hook to avoid duplication and make both components simpler and more maintainable.

Comment on lines 7 to 12
const gameEventsQuery = (gameId: number) => {
return new GameQueryBuilder()
.withClause(
new ClauseBuilder().keys(
[
`${currentNetworkConfig.namespace}-GameEvent`,
],
[addAddressPadding(`0x${gameId.toString(16)}`)]
).build()
)
.withEntityModels([
`${currentNetworkConfig.namespace}-GameEvent`,
])
return new HistoricalToriiQueryBuilder()
.addEntityModel(`${currentNetworkConfig.namespace}-GameEvent`)
.withLimit(1)
.includeHashedKeys();
};

Choose a reason for hiding this comment

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

high

The query for game events has been changed to use HistoricalToriiQueryBuilder, but it no longer filters by gameId on the server side. The new query will fetch all GameEvent entities, and the filtering is done on the client. This is inefficient and can cause performance issues, especially with many active games, as it subscribes to a much larger set of events than necessary. The previous implementation using ClauseBuilder with keys was more efficient as it filtered events at the source (Torii).


let url = `${SQL_ENDPOINT}/sql?query=
SELECT id, player_name
FROM "relayer_0_0_1-TokenPlayerNameUpdate"

Choose a reason for hiding this comment

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

high

The table name "relayer_0_0_1-TokenPlayerNameUpdate" is hardcoded. This is brittle and might break if the relayer version or namespace changes. It would be better to construct this table name dynamically, possibly using the namespace from the network configuration, to make it more robust.

Comment on lines +253 to +316
useEffect(() => {
if (!advancedMode) {
setSimulationResult(defaultSimulationResult);
setSimulationActionCount(null);
return;
}

let cancelled = false;

if (!adventurer || !beast) {
setSimulationResult(defaultSimulationResult);
setSimulationActionCount(null);
return () => {
cancelled = true;
};
}

const runSimulation = async () => {
const result = await simulateCombatOutcomes(adventurer, beast, {
initialBeastStrike: hasNewItemsEquipped,
});

if (!cancelled) {
setSimulationResult(result);
setSimulationActionCount(adventurer.action_count);
}
};

void runSimulation();

return () => {
cancelled = true;
};
}, [
advancedMode,
adventurer?.health,
adventurer?.xp,
adventurer?.item_specials_seed,
adventurer?.stats.strength,
adventurer?.stats.luck,
adventurer?.equipment.weapon.id,
adventurer?.equipment.weapon.xp,
adventurer?.equipment.chest.id,
adventurer?.equipment.chest.xp,
adventurer?.equipment.head.id,
adventurer?.equipment.head.xp,
adventurer?.equipment.waist.id,
adventurer?.equipment.waist.xp,
adventurer?.equipment.hand.id,
adventurer?.equipment.hand.xp,
adventurer?.equipment.foot.id,
adventurer?.equipment.foot.xp,
adventurer?.equipment.neck.id,
adventurer?.equipment.neck.xp,
adventurer?.equipment.ring.id,
adventurer?.equipment.ring.xp,
adventurer?.beast_health,
beast?.health,
beast?.level,
beast?.tier,
beast?.specialPrefix,
beast?.specialSuffix,
hasNewItemsEquipped,
]);

Choose a reason for hiding this comment

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

high

This useEffect block re-implements the combat simulation logic that is already encapsulated in the useCombatSimulation hook used in the desktop CombatOverlay. To reduce code duplication and improve maintainability, this component should also use the useCombatSimulation hook.

@@ -42,15 +43,14 @@ export default function AdventurersList({ onBack }: AdventurersListProps) {
});
const [gameTokens, setGameTokens] = useState<any[]>([]);

Choose a reason for hiding this comment

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

medium

The state gameTokens is typed as any[], and any is used in several places for the game object. Using any undermines TypeScript's type safety. It would be beneficial to define a specific type for the game token object to improve type safety and code clarity.

For example:

interface GameToken {
  adventurer_id: number;
  dead: boolean;
  expired: boolean;
  available_at: number;
  // ... other properties
}

const [gameTokens, setGameTokens] = useState<GameToken[]>([]);

const dungeon = useDungeon();
const { getActivePlayersCount, getPlayerNames } = useGameTokens();
const [left, setLeft] = useState(getMenuLeftOffset());
const [playersOnline, setPlayersOnline] = useState<any[] | null>(null);

Choose a reason for hiding this comment

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

medium

The state playersOnline is typed as any[] | null, and any is used for player objects throughout the component. This reduces type safety. Defining a specific interface for the player data would make the code more robust and easier to understand.

For example:

interface PlayerData {
  adventurer_id: string;
  details?: {
    adventurer?: {
      health: number;
      xp: number;
    };
  };
  // ... other properties
}

const [playersOnline, setPlayersOnline] = useState<PlayerData[] | null>(null);


openProfile: () => (connector as any)?.controller?.openProfile(),
openBuyTicket: () => (connector as any)?.controller?.openStarterPack("ls2-dungeon-ticket-mainnet"),
openBuyTicket: () => (connector as any)?.controller?.openStarterPack(3),

Choose a reason for hiding this comment

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

medium

Using the magic number 3 for the starter pack ID makes the code harder to understand and maintain. It's better to define this as a named constant (e.g., DUNGEON_TICKET_STARTER_PACK_ID) to improve readability and make future updates easier.

</Typography>
</Box>
{adventurer?.item_specials_seed !== 0 && (() => {
const specials = ItemUtils.getSpecials(item.id, 15, adventurer!.item_specials_seed);

Choose a reason for hiding this comment

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

medium

The magic number 15 is used here for the greatness level to get item specials. This value is defined as SUFFIX_UNLOCK_GREATNESS in client/src/constants/loot.ts. Using the constant (after importing it) would improve readability and maintainability.

Suggested change
const specials = ItemUtils.getSpecials(item.id, 15, adventurer!.item_specials_seed);
const specials = ItemUtils.getSpecials(item.id, SUFFIX_UNLOCK_GREATNESS, adventurer!.item_specials_seed);

Comment on lines +171 to +221
const renderAdvancedStatsView = () => (
<>
<Box sx={styles.statGrid}>
{['strength', 'dexterity', 'vitality', 'intelligence', 'wisdom', 'charisma'].map((stat) => {
const totalStatValue = adventurer?.stats?.[stat as keyof typeof STAT_DESCRIPTIONS]! + selectedStats[stat as keyof typeof STAT_DESCRIPTIONS]!;
const effectText = STAT_HELPER_TEXT(stat, totalStatValue);

return (
<Box sx={styles.statRow} key={stat}>
<Box sx={styles.statInfo}>
<Typography sx={styles.statLabel}>{STAT_TITLE(stat)}</Typography>
{effectText && (
<Typography sx={styles.statEffect}>{effectText}</Typography>
)}
</Box>
<Box sx={styles.statControls}>
{adventurer?.stat_upgrades_available! > 0 && stat !== 'luck' && <Button
variant="contained"
size="small"
onClick={() => handleStatDecrement(stat as keyof typeof STAT_DESCRIPTIONS)}
sx={styles.controlButton}
>
-
</Button>}

<Typography sx={styles.statValue}>
{totalStatValue}
</Typography>

{adventurer?.stat_upgrades_available! > 0 && stat !== 'luck' && <Button
variant="contained"
size="small"
onClick={() => handleStatIncrement(stat as keyof typeof STAT_DESCRIPTIONS)}
disabled={(adventurer!.stats[stat as keyof typeof STAT_DESCRIPTIONS] + selectedStats[stat as keyof typeof STAT_DESCRIPTIONS]) >= (MAX_STAT_VALUE + equippedItemStats[stat as keyof typeof STAT_DESCRIPTIONS])}
sx={styles.controlButton}
>
+
</Button>}
</Box>
</Box>
);
})}
</Box>

<Box sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center', mt: 0.5 }}>
{adventurer?.stat_upgrades_available! > 0 &&
<Typography color="secondary" >{pointsRemaining} remaining</Typography>
}
</Box>
</>
);

Choose a reason for hiding this comment

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

medium

This function renderAdvancedStatsView and other parts of the component use non-null assertions (!) on adventurer. While the parent component might ensure adventurer is not null, it's safer and cleaner to add a guard clause at the beginning of the AdventurerStats component to handle the case where adventurer might be null. This makes the component more robust and self-contained.

For example:

export default function AdventurerStats() {
  const { adventurer, ... } = useGameStore();
  // ... other hooks

  if (!adventurer) {
    return null; // or a loading/placeholder component
  }

  // ... rest of the component logic without non-null assertions
}

Comment on lines +76 to +103
const handleSuggestGear = async () => {
if (!adventurer || !bag || !beast) {
return;
}

setSuggestInProgress(true);
setSuggestMessage(null);

try {
const suggestion = await suggestBestCombatGear(adventurer, bag, beast);

if (!suggestion) {
setSuggestMessage('Best gear already equipped');
setTimeout(() => setSuggestMessage(null), 4000);
return;
}

applyGearSuggestion({ adventurer: suggestion.adventurer, bag: suggestion.bag });
setSuggestMessage('Gear equipped');
setTimeout(() => setSuggestMessage(null), 4000);
} catch (error) {
console.error('Failed to suggest combat gear', error);
setSuggestMessage('Unable to suggest gear');
setTimeout(() => setSuggestMessage(null), 4000);
} finally {
setSuggestInProgress(false);
}
};

Choose a reason for hiding this comment

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

medium

The logic for setting and clearing the suggestion message with a timeout is repeated multiple times. You could extract this into a helper function to reduce duplication and improve readability.

For example:

const showTemporaryMessage = (message: string, duration: number = 4000) => {
  setSuggestMessage(message);
  setTimeout(() => setSuggestMessage(null), duration);
};

Then you can call showTemporaryMessage('Best gear already equipped'); inside your try...catch block.

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