Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: flat mode view and optimized chunks loading #2572

Open
wants to merge 6 commits into
base: next
Choose a base branch
from
Open

Conversation

r0man1337
Copy link
Contributor

@r0man1337 r0man1337 commented Dec 20, 2024

The client now manages chunk loading more efficiently. Previously, loading was not optimal because each camera movement would reload many entities. Now, entities are only loaded from chunks that were not previously on the screen. A flat mode view has also been added.

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Introduced a flat mode setting that allows users to toggle between rendering modes.
    • Added a checkbox in the settings for enabling/disabling flat mode.
    • New method to retrieve the flat mode setting from local storage.
  • Enhancements

    • Improved camera and scene rendering based on the flat mode configuration.
    • Updated graphics settings management to include dynamic paths for biome models.
    • Enhanced responsiveness of the game world management and rendering.
    • Added a new method to calculate surrounding chunks for improved chunk management.
    • Adjusted GUI placement based on new environment configuration.
  • Bug Fixes

    • Ensured type safety for graphics settings retrieval.
  • Documentation

    • Updated comments and documentation to reflect new features and settings.

Copy link

vercel bot commented Dec 20, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
eternum ❌ Failed (Inspect) Dec 24, 2024 0:16am
eternum-docs ✅ Ready (Inspect) Visit Preview 💬 Add feedback Dec 24, 2024 0:16am
eternum-landing ✅ Ready (Inspect) Visit Preview 💬 Add feedback Dec 24, 2024 0:16am

Copy link
Contributor

coderabbitai bot commented Dec 20, 2024

Walkthrough

This pull request introduces the IS_FLAT_MODE configuration setting across multiple client-side components, enhancing rendering flexibility. The changes primarily focus on camera positioning, scene rendering, and model path selection based on the flat mode. The implementation spans several files within the Three.js rendering ecosystem, introducing conditional logic to support a flat view mode alongside the existing perspective view.

Changes

File Change Summary
client/src/three/GameRenderer.ts Added IS_FLAT_MODE to conditionally set camera far clipping plane.
client/src/three/helpers/GUIManager.ts Updated autoPlace to use env.VITE_PUBLIC_GRAPHICS_DEV.
client/src/three/scenes/HexagonScene.ts Added conditional fog and camera movement based on IS_FLAT_MODE.
client/src/three/scenes/Hexception.tsx Modified maxDistance and rotation calculations using IS_FLAT_MODE.
client/src/three/scenes/Worldmap.ts Added getChunksAround method and updated scene management.
client/src/three/scenes/constants.ts Introduced FLAT_PATH and dynamic model path selection.
client/src/ui/config.tsx Added getFlatMode() function and IS_FLAT_MODE constant.
client/src/ui/modules/settings/Settings.tsx Implemented flat mode toggle in settings UI.

Possibly related PRs

Suggested reviewers

  • aymericdelab
  • edisontim

Poem

🐰 Flat or Tall, Choose Your Call! 🌍
A rabbit's view, now crystal clear,
Perspectives shift without a fear,
Cameras dance, scenes rearrange,
With just one click, the world will change!
Hop into mode, both flat and bright! 🚀


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

mentatbot bot commented Dec 20, 2024

You are out of MentatBot reviews. Your usage will refresh December 23 at 08:00 AM.

Copy link

Failed to generate code suggestions for PR

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (9)
client/src/three/scenes/Worldmap.ts (4)

372-372: **Consider dynamic scaling of maxDistance **
Currently, maxDistance is a fixed value dependent on IS_FLAT_MODE (40 vs. 20). For added flexibility, you could dynamically scale maxDistance based on screen size or device capabilities to improve user experience, especially for edge cases like ultra-wide screens or WebGL performance constraints.


490-505: **Use consistent chunk key parsing and error handling **
The approach of extracting row and column from the chunk key via split is fine, but it might be safer to add basic validation (e.g., ensure that chunkKey is in the expected format). If an unexpected chunkKey value were passed in, parseInt might yield NaN.
You could also factor out a helper function like parseChunkKey(chunkKey) to keep the code standardized across all references to chunk keys.


571-571: **Remove console logs or guard them in production **
Consider removing or conditionally wrapping console.log("cache applied") in a development/debug flag to avoid polluting production logs.


602-606: **Potential concurrency improvement for chunk fetching **
You are populating tile entities for the current chunk and the surrounding chunks, which is good for smooth user experience. However, you might consider running these in parallel using Promise.all to reduce total wait time, if the server and client can handle multiple requests at once.

client/src/three/helpers/GUIManager.ts (1)

6-6: **Use triple equals to avoid unintended type coercion **
“env.VITE_PUBLIC_GRAPHICS_DEV == true” can be changed to “env.VITE_PUBLIC_GRAPHICS_DEV === true” for stricter comparison.

- autoPlace: env.VITE_PUBLIC_GRAPHICS_DEV == true && !IS_MOBILE,
+ autoPlace: env.VITE_PUBLIC_GRAPHICS_DEV === true && !IS_MOBILE,
client/src/ui/config.tsx (1)

43-44: **Consider a more explicit fallback behavior **
Currently, missing localStorage yields GraphicsSettings.HIGH by default. If this is intended, no problems; otherwise, consider prompting for user preference or defaulting to a more conservative setting like LOW on unknown devices.

client/src/three/scenes/constants.ts (1)

80-82: **Flexible path handling for flat vs. base mode **
Directly setting BASE_PATH or FLAT_PATH is concise. For multi-theme or multi-mode scenarios, consider an object keyed by mode type, so new mode expansions remain readable:

- const MODELS_PATH = IS_FLAT_MODE ? FLAT_PATH : BASE_PATH;
+ const PATHS = {
+   flat: FLAT_PATH,
+   base: BASE_PATH,
+ };
+ const MODELS_PATH = IS_FLAT_MODE ? PATHS.flat : PATHS.base;
client/src/ui/modules/settings/Settings.tsx (1)

89-98: Consider optimizing the flat mode toggle implementation.

The implementation forces a full page reload when toggling flat mode. While this ensures all components reflect the change, it might impact user experience.

Consider implementing a more granular update mechanism:

  1. Use React context or state management to propagate the change
  2. Update only the affected components
  3. Avoid full page reload
 const toggleFlatMode = () => {
   setIsFlatMode((prev) => {
     const newFlatMode = !prev;
     localStorage.setItem("FLAT_MODE", newFlatMode.toString());
-    window.location.reload(); // Reload the page to apply changes
+    // Dispatch an event or update state to notify affected components
+    window.dispatchEvent(new CustomEvent('flatModeChanged', { detail: newFlatMode }));
     return newFlatMode;
   });
 };
client/src/three/scenes/Hexception.tsx (1)

275-275: Consider extracting magic numbers into named constants

The maxDistance values should be defined as named constants for better maintainability and clarity.

+const FLAT_MODE_MAX_DISTANCE = 36;
+const DEFAULT_MAX_DISTANCE = 18;
-    this.controls.maxDistance = IS_FLAT_MODE ? 36 : 18;
+    this.controls.maxDistance = IS_FLAT_MODE ? FLAT_MODE_MAX_DISTANCE : DEFAULT_MAX_DISTANCE;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 60fe5bd and de8660b.

📒 Files selected for processing (8)
  • client/src/three/GameRenderer.ts (2 hunks)
  • client/src/three/helpers/GUIManager.ts (1 hunks)
  • client/src/three/scenes/HexagonScene.ts (4 hunks)
  • client/src/three/scenes/Hexception.tsx (4 hunks)
  • client/src/three/scenes/Worldmap.ts (8 hunks)
  • client/src/three/scenes/constants.ts (2 hunks)
  • client/src/ui/config.tsx (2 hunks)
  • client/src/ui/modules/settings/Settings.tsx (4 hunks)
🔇 Additional comments (14)
client/src/three/scenes/Worldmap.ts (3)

9-9: **Good addition of config imports **
Importing IS_FLAT_MODE allows for conditional scene logic for flat mode rendering. This is a clear and organized use of the configuration constants.


431-438: **Conditional rotation logic is concise **
The code neatly toggles random rotations for non-flat mode while resetting rotation in flat mode. This cleanly separates the two modes.
Consider adding a small comment to explain that the random rotation highlights biome variety or terrain variation. This can help future maintainers understand the purpose of the rotation logic.


689-693: **Validate chunk key parsing to avoid NaN errors **
Similar to the earlier comment about chunk keys, make sure chunkKey is always in a valid format ("row,col"). If it isn’t, parseInt might return NaN and cause range computations to malfunction.
Would you like a script to confirm all chunkKey references match the "number,number" pattern across the codebase?

client/src/ui/config.tsx (3)

9-9: **Enum trailing comma is acceptable **
No errors or concerns here. The trailing comma in the enum can improve diffs and is standard in many code styles.


46-48: **Function getFlatMode is straightforward **
This boolean retrieval approach is clear and easy to maintain. Just ensure you store "true"/"false" consistently in localStorage for Flat Mode.


52-52: **Exposing IS_FLAT_MODE is helpful for global usage **

client/src/three/scenes/constants.ts (3)

2-2: **Clear addition of IS_FLAT_MODE import **
Bringing in IS_FLAT_MODE for conditional resource path logic is well structured for code readability.


83-101: **BiomeFilenames enum is well-structured **
Having a single source of truth for biome file names improves maintainability and reduces potential typos in string paths.


104-120: **All references default to Grassland or TemperateDeciduousForest **
You are routing multiple biome types to the same file. If this is intentional (placeholder) it’s fine. Otherwise, confirm with a designer or map artist that reusing the same models is correct, as you might lose biome-specific variations.

client/src/three/GameRenderer.ts (1)

90-90: Verify the impact of increased far clipping plane.

Increasing the far clipping plane from 30 to 50 in flat mode could affect:

  1. Rendering performance due to larger view frustum
  2. Z-fighting artifacts for distant objects
✅ Verification successful

Let me gather more information about the rendering setup and camera usage.


The increased far clipping plane in flat mode is safe to use.

The codebase analysis reveals that the change is well-considered within the rendering architecture:

  1. The renderer uses PCFSoftShadowMap and has proper depth buffer handling
  2. No z-fighting issues are reported in the codebase
  3. Flat mode already has specific optimizations:
    • Disabled fog effects in flat mode
    • Adjusted camera controls (maxDistance: 40 vs 20)
    • Simplified rotation handling
  4. The far plane increase (30 to 50) aligns with flat mode's extended viewing range (maxDistance: 40)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for potential z-fighting issues in flat mode
# Look for depth-related configurations or comments in the codebase

# Search for depth buffer configurations
rg -A 2 'depthTest|depthWrite|renderOrder'

# Search for z-fighting related comments
rg -i 'z-fighting|z fighting|depth buffer'

Length of output: 1382


Script:

#!/bin/bash
# Search for camera-related configurations and render settings
rg -A 3 'PerspectiveCamera|OrthographicCamera'

# Search for any flat mode related configurations
rg -A 3 'IS_FLAT_MODE'

# Look for renderer configurations
rg -A 3 'renderer\.set|antialias|logarithmicDepthBuffer'

Length of output: 12723

client/src/three/scenes/HexagonScene.ts (1)

70-72: LGTM: Fog configuration is well-considered.

The conditional fog application makes sense:

  • Disabled in flat mode for clearer visibility
  • Only enabled in high graphics mode for performance
client/src/three/scenes/Hexception.tsx (3)

8-8: LGTM: Import of flat mode configuration

The import follows proper naming conventions for configuration constants.


544-544: LGTM: Z-fighting prevention

Setting pillars slightly below the surface (-0.01) helps prevent z-fighting artifacts.


675-684: LGTM: Flat mode implementation

The implementation correctly handles both position and rotation adjustments for flat mode:

  • Forces y-position to 0 in flat mode
  • Removes rotation in flat mode for consistent appearance

Let's verify that flat mode is consistently implemented across other scene components:

✅ Verification successful

Flat mode implementation is consistently handled across scenes

The verification confirms that flat mode is consistently implemented:

  • In Hexception.tsx and Worldmap.ts, both position.y and rotation.y are properly handled for flat mode
  • Other scenes (HexagonScene.ts) correctly handle flat mode positioning
  • Global constants and camera settings are properly adjusted for flat mode
  • No inconsistencies found in the implementation
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for other potential places where flat mode should be considered
rg -l "position\.y|rotation\.y" | while read -r file; do
  echo "=== $file ==="
  rg "position\.y|rotation\.y" "$file"
done

# Verify IS_FLAT_MODE usage consistency
ast-grep --pattern 'IS_FLAT_MODE ? $_ : $_'

Length of output: 12590

Comment on lines +321 to +332

const newPosition = IS_FLAT_MODE
? new THREE.Vector3(newTarget.x, pos.y, newTarget.z)
: new THREE.Vector3(pos.x + deltaX, pos.y, pos.z + deltaZ);

if (duration) {
this.cameraAnimate(new THREE.Vector3(pos.x + deltaX, pos.y, pos.z + deltaZ), newTarget, duration);
this.cameraAnimate(newPosition, newTarget, duration);
} else {
target.set(newTarget.x, newTarget.y, newTarget.z);
pos.set(pos.x + deltaX, pos.y, pos.z + deltaZ);
target.copy(newTarget);
pos.copy(newPosition);
}

Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Refactor duplicate camera movement logic.

The camera position calculation logic is duplicated between moveCameraToXYZ and moveCameraToColRow.

Extract the common logic into a shared method:

+private calculateNewCameraPosition(newTarget: THREE.Vector3, currentPosition: THREE.Vector3, currentTarget: THREE.Vector3): THREE.Vector3 {
+  if (IS_FLAT_MODE) {
+    return new THREE.Vector3(newTarget.x, currentPosition.y, newTarget.z);
+  }
+  const deltaX = newTarget.x - currentTarget.x;
+  const deltaZ = newTarget.z - currentTarget.z;
+  return new THREE.Vector3(currentPosition.x + deltaX, currentPosition.y, currentPosition.z + deltaZ);
+}

 public moveCameraToXYZ(x: number, y: number, z: number, duration: number = 2) {
   const newTarget = new THREE.Vector3(x, y, z);
   const target = this.controls.target;
   const pos = this.controls.object.position;
-  const deltaX = newTarget.x - target.x;
-  const deltaZ = newTarget.z - target.z;
-  const newPosition = IS_FLAT_MODE
-    ? new THREE.Vector3(newTarget.x, pos.y, newTarget.z)
-    : new THREE.Vector3(pos.x + deltaX, pos.y, pos.z + deltaZ);
+  const newPosition = this.calculateNewCameraPosition(newTarget, pos, target);
   // ... rest of the method
 }

 public moveCameraToColRow(col: number, row: number, duration: number = 2) {
   const { x, y, z } = getWorldPositionForHex({ col, row });
   const newTarget = new THREE.Vector3(x, y, z);
   const target = this.controls.target;
   const pos = this.controls.object.position;
-  const deltaX = newTarget.x - target.x;
-  const deltaZ = newTarget.z - target.z;
-  const newPosition = IS_FLAT_MODE
-    ? new THREE.Vector3(newTarget.x, pos.y, newTarget.z)
-    : new THREE.Vector3(pos.x + deltaX, pos.y, pos.z + deltaZ);
+  const newPosition = this.calculateNewCameraPosition(newTarget, pos, target);
   // ... rest of the method
 }

Also applies to: 347-357

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
client/src/three/scenes/constants.ts (1)

83-101: Add JSDoc documentation for the BiomeFilenames enum

While the enum is well-structured, adding documentation would improve maintainability and help other developers understand the purpose and usage of these filenames.

Add documentation like this:

+/**
+ * Enum containing the filenames for different biome 3D models.
+ * These files are expected to exist in both the base and flat model directories.
+ */
export enum BiomeFilenames {
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between de8660b and 9db4d4e.

📒 Files selected for processing (1)
  • client/src/three/scenes/constants.ts (2 hunks)
🔇 Additional comments (4)
client/src/three/scenes/constants.ts (4)

81-81: LGTM! Clean implementation of path selection logic

The ternary operator provides a clear and concise way to switch between flat and base paths based on the mode.


2-2: Verify the existence of flat models directory

The code references a new directory for flat mode models. Let's ensure this directory exists and contains the required models.

Also applies to: 80-80

✅ Verification successful

✓ Flat mode models directory and files are properly set up

The directory client/public/models/biomes-flat-opt/ exists and contains all the necessary biome model files (.glb). The models follow the same naming convention as the regular biome models, ensuring consistency across different view modes.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if the flat models directory exists and contains the expected models
fd . "public/models/biomes-flat-opt" --type f -e glb

Length of output: 169


Script:

#!/bin/bash
# Let's check if the directory exists in any location within the repository
fd "biomes-flat-opt" --type d

# Also check for any .glb files in the repository to understand model organization
fd . --type f -e glb

Length of output: 6478


103-120: Verify path construction consistency

Let's ensure the path construction pattern is consistent across the codebase.

✅ Verification successful

Let me gather more information about the path constants to understand the full context.


Based on the gathered information, I can now provide the final response:

Path construction is consistent with codebase patterns

The path construction in the biome models follows the established pattern in the codebase. The MODELS_PATH constant is properly defined and conditionally set based on IS_FLAT_MODE, choosing between FLAT_PATH and BASE_PATH. This is consistent with other model path constructions in the file, where paths are either concatenated using the same pattern or directly specified with string literals.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for other instances of path construction for models
rg "models/.+\.glb" --type ts

# Check for potential path joining issues
rg "MODELS_PATH.*\+" --type ts

Length of output: 5676


Script:

#!/bin/bash
# Check the definition of MODELS_PATH and other path constants
ast-grep --pattern 'const $_ = $_' client/src/three/scenes/constants.ts

# Check if there are any path utilities being used
rg "path\." --type ts

Length of output: 3397


103-120: Document why Outline uses BASE_PATH instead of MODELS_PATH

The Outline biome specifically uses BASE_PATH while all other biomes use MODELS_PATH. This special case should be documented to explain the reasoning.

Add a comment explaining the special case:

export const biomeModelPaths: Record<BiomeType | "Outline", string> = {
  // ... other biomes ...
+ // Outline uses BASE_PATH as it's shared between flat and regular modes
  Outline: BASE_PATH + BiomeFilenames.Outline,
  // ... remaining biomes ...
};
✅ Verification successful

Let me check the usage of Outline in these files to understand why it uses BASE_PATH.


Now I can generate the final response based on the evidence found. The code shows that:

  1. MODELS_PATH switches between FLAT_PATH and BASE_PATH based on IS_FLAT_MODE
  2. Outline is used as a special visual element with unique properties (transparent, different render order)
  3. Outline is consistently treated differently from other biomes (e.g., shadow handling)

Add a comment explaining why Outline uses BASE_PATH

The Outline model should always use BASE_PATH instead of MODELS_PATH because it's a shared visual element that remains the same regardless of flat/regular mode, as evidenced by its special rendering properties in the codebase.

export const biomeModelPaths: Record<BiomeType | "Outline", string> = {
  // ... other biomes ...
+ // Outline uses BASE_PATH directly as it's a shared visual element that doesn't change between flat/regular modes
  Outline: BASE_PATH + BiomeFilenames.Outline,
  // ... remaining biomes ...
};
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for any other special cases of outline handling
rg -l "Outline" --type ts

Length of output: 224


Script:

#!/bin/bash
# Check how Outline is used in the codebase
rg "Outline" --type ts -C 3

# Also check what BASE_PATH and MODELS_PATH are defined as
rg "BASE_PATH|MODELS_PATH" --type ts -C 2

Length of output: 7277

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (3)
client/src/three/scenes/Worldmap.ts (3)

490-505: Consider optimizing chunk calculation logic

The chunk calculation could be improved for better performance and reliability:

  1. Add chunk size validation
  2. Use Set instead of Array to avoid duplicate checks
  3. Optimize the nested loops
 getChunksAround(chunkKey: string) {
   const startRow = parseInt(chunkKey.split(",")[0]);
   const startCol = parseInt(chunkKey.split(",")[1]);
-  const chunks: string[] = [];
+  const chunks = new Set<string>();
+  if (this.chunkSize <= 0) {
+    throw new Error("Invalid chunk size");
+  }
   for (let i = -this.renderChunkSize.width / 2; i <= this.renderChunkSize.width / 2; i += this.chunkSize) {
     for (let j = -this.renderChunkSize.width / 2; j <= this.renderChunkSize.height / 2; j += this.chunkSize) {
       const { x, y, z } = getWorldPositionForHex({ row: startRow + i, col: startCol + j });
       const { chunkX, chunkZ } = this.worldToChunkCoordinates(x, z);
       const _chunkKey = `${chunkZ * this.chunkSize},${chunkX * this.chunkSize}`;
-      if (!chunks.includes(_chunkKey)) {
-        chunks.push(_chunkKey);
-      }
+      chunks.add(_chunkKey);
     }
   }
-  return chunks;
+  return Array.from(chunks);
 }

649-654: Consider extracting magic number to a constant

The y-position adjustment of 0.1 in flat mode should be defined as a named constant for better maintainability.

+const FLAT_MODE_Y_OFFSET = 0.1;
 if (!IS_FLAT_MODE) {
   dummy.rotation.y = randomRotation;
 } else {
-  dummy.position.y += 0.1;
+  dummy.position.y += FLAT_MODE_Y_OFFSET;
   dummy.rotation.y = 0;
 }

571-571: Remove or replace debug console.logs

Consider removing the debug console.log statements or replacing them with proper logging using a logging framework.

-console.log("cache applied");
+// TODO: Replace with proper logging
+logger.debug("Cache applied for chunk computation");

-console.log("chunkKey", chunkKey);
+logger.debug("Computing tile entities for chunk", { chunkKey });

Also applies to: 604-605

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9db4d4e and b0a9e30.

📒 Files selected for processing (1)
  • client/src/three/scenes/Worldmap.ts (8 hunks)
🔇 Additional comments (2)
client/src/three/scenes/Worldmap.ts (2)

372-372: LGTM: Camera distance adjustment for flat mode

The conditional adjustment of maxDistance based on the view mode is appropriate, allowing for better visibility in flat mode.


431-438: LGTM: Proper rotation handling for flat mode

The conditional rotation logic appropriately handles both modes:

  • Flat mode: Consistent 0-degree rotation for a clean, map-like appearance
  • Normal mode: Randomized rotation for visual variety

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b0a9e30 and dba2548.

📒 Files selected for processing (1)
  • client/src/three/scenes/Worldmap.ts (8 hunks)
🔇 Additional comments (3)
client/src/three/scenes/Worldmap.ts (3)

9-9: LGTM: Appropriate camera distance adjustment for flat mode

The doubled maxDistance (40 vs 20) in flat mode is a good adjustment to maintain proper visibility of the map from a top-down perspective.

Also applies to: 372-372


431-438: LGTM: Proper visual adjustments for flat mode

The changes appropriately handle hex visualization in flat mode:

  1. Zero rotation ensures consistent orientation
  2. Small Y-axis offset (+0.1) prevents Z-fighting issues

Also applies to: 651-656


603-608: Remove or implement commented chunk loading code

The commented code for loading surrounding chunks suggests an incomplete implementation. Either implement the surrounding chunk loading or remove the commented code if it's not needed.

Would you like me to help implement the surrounding chunk loading feature?

Comment on lines +692 to +696
private async computeTileEntities(chunkKey: string) {
const startCol = parseInt(chunkKey.split(",")[1]) + FELT_CENTER;
const startRow = parseInt(chunkKey.split(",")[0]) + FELT_CENTER;

const adjustedX = cameraPosition.x + (this.chunkSize * HEX_SIZE * Math.sqrt(3)) / 2;
const adjustedZ = cameraPosition.z + (this.chunkSize * HEX_SIZE * 1.5) / 3;

// Parse current chunk coordinates
const { chunkX, chunkZ } = this.worldToChunkCoordinates(adjustedX, adjustedZ);

const startCol = chunkX * this.chunkSize + FELT_CENTER;
const startRow = chunkZ * this.chunkSize + FELT_CENTER;
//const range = this.chunkSize / 2;
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Clean up debug code and optimize range calculation

  1. Remove debug console.log statements before production deployment
  2. The commented range calculation (const range = this.chunkSize / 2) suggests a potential optimization opportunity compared to the current implementation using renderChunkSize.width / 2

Apply these changes:

-    //const range = this.chunkSize / 2;
-
-    const { width } = this.renderChunkSize;
-    const range = width / 2;
-
-    // Skip if we've already fetched this chunk
-    if (this.fetchedChunks.has(chunkKey)) {
-      console.log("Already fetched");
-      return;
-    }
-
-    // Add to fetched chunks before the query to prevent concurrent duplicate requests
-    this.fetchedChunks.add(chunkKey);
-    console.log(startCol, startRow, range);
+    const range = this.chunkSize / 2;
+
+    if (this.fetchedChunks.has(chunkKey)) {
+      return;
+    }
+
+    this.fetchedChunks.add(chunkKey);

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +490 to +505
getChunksAround(chunkKey: string) {
const startRow = parseInt(chunkKey.split(",")[0]);
const startCol = parseInt(chunkKey.split(",")[1]);
const chunks: string[] = [];
for (let i = -this.renderChunkSize.width / 2; i <= this.renderChunkSize.width / 2; i += this.chunkSize) {
for (let j = -this.renderChunkSize.width / 2; j <= this.renderChunkSize.height / 2; j += this.chunkSize) {
const { x, y, z } = getWorldPositionForHex({ row: startRow + i, col: startCol + j });
const { chunkX, chunkZ } = this.worldToChunkCoordinates(x, z);
const _chunkKey = `${chunkZ * this.chunkSize},${chunkX * this.chunkSize}`;
if (!chunks.includes(_chunkKey)) {
chunks.push(_chunkKey);
}
}
}
return chunks;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix incorrect dimension in chunk calculation loop

There's a bug in the inner loop condition where it uses width instead of height, which could lead to incorrect chunk calculations.

Apply this fix:

-      for (let j = -this.renderChunkSize.width / 2; j <= this.renderChunkSize.height / 2; j += this.chunkSize) {
+      for (let j = -this.renderChunkSize.height / 2; j <= this.renderChunkSize.height / 2; j += this.chunkSize) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
getChunksAround(chunkKey: string) {
const startRow = parseInt(chunkKey.split(",")[0]);
const startCol = parseInt(chunkKey.split(",")[1]);
const chunks: string[] = [];
for (let i = -this.renderChunkSize.width / 2; i <= this.renderChunkSize.width / 2; i += this.chunkSize) {
for (let j = -this.renderChunkSize.width / 2; j <= this.renderChunkSize.height / 2; j += this.chunkSize) {
const { x, y, z } = getWorldPositionForHex({ row: startRow + i, col: startCol + j });
const { chunkX, chunkZ } = this.worldToChunkCoordinates(x, z);
const _chunkKey = `${chunkZ * this.chunkSize},${chunkX * this.chunkSize}`;
if (!chunks.includes(_chunkKey)) {
chunks.push(_chunkKey);
}
}
}
return chunks;
}
getChunksAround(chunkKey: string) {
const startRow = parseInt(chunkKey.split(",")[0]);
const startCol = parseInt(chunkKey.split(",")[1]);
const chunks: string[] = [];
for (let i = -this.renderChunkSize.width / 2; i <= this.renderChunkSize.width / 2; i += this.chunkSize) {
for (let j = -this.renderChunkSize.height / 2; j <= this.renderChunkSize.height / 2; j += this.chunkSize) {
const { x, y, z } = getWorldPositionForHex({ row: startRow + i, col: startCol + j });
const { chunkX, chunkZ } = this.worldToChunkCoordinates(x, z);
const _chunkKey = `${chunkZ * this.chunkSize},${chunkX * this.chunkSize}`;
if (!chunks.includes(_chunkKey)) {
chunks.push(_chunkKey);
}
}
}
return chunks;
}

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
client/src/three/scenes/Worldmap.ts (1)

572-572: Remove debug logging

Debug console.log statements should be removed before merging to production.

-      console.log("cache applied");
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dba2548 and 61a9e43.

📒 Files selected for processing (1)
  • client/src/three/scenes/Worldmap.ts (8 hunks)
🔇 Additional comments (4)
client/src/three/scenes/Worldmap.ts (4)

372-372: LGTM: Camera distance adjustment for flat mode

The different maximum distances for flat mode (40) and regular mode (20) are appropriate for their respective viewing perspectives.


431-439: LGTM: Appropriate rotation handling for flat mode

The code correctly handles rotations:

  • Regular mode: Uses seeded random rotations for visual variety
  • Flat mode: Zeroes rotation and slightly elevates position for better visibility

496-496: Fix incorrect dimension in chunk calculation loop

The inner loop condition incorrectly uses width instead of height.


604-609: Clarify the commented chunk computation implementation

The commented code for computing surrounding chunks suggests an unfinished implementation. This could be important for the chunk loading optimization mentioned in the PR objectives.

Please clarify if this implementation should be:

  1. Uncommented and completed
  2. Removed if no longer needed
✅ Verification successful

Let me gather more information about the chunk computation implementation and its usage in the codebase.


Based on the search results, I can now generate the final response as I have enough context about the chunk computation implementation.

Keep the chunk computation code commented out

The commented code for computing surrounding chunks should remain commented out because:

  1. The current implementation already handles chunk computation efficiently through updateVisibleChunks() which calculates and loads chunks based on camera position
  2. The getChunksAround() method's implementation shows it would process a much larger area (renderChunkSize.width x renderChunkSize.height) which could impact performance
  3. The existing chunk loading system includes proper chunk caching (fetchedChunks), matrix caching, and optimized updates for armies and structures
🏁 Scripts executed

The following scripts were executed for the analysis:

Error: No shell scripts found


Script:

#!/bin/bash
# Search for chunk-related computations and methods
ast-grep --pattern 'computeTileEntities($_) {
  $$$
}'

# Search for getChunksAround implementation
ast-grep --pattern 'getChunksAround($_) {
  $$$
}'

# Search for other chunk-related methods
rg "chunk" client/src/three/scenes/Worldmap.ts -A 5

Length of output: 6706

@r0man1337 r0man1337 changed the title [WIP] feat: flat mode view and optimized chunks loading feat: flat mode view and optimized chunks loading Dec 24, 2024
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (3)
client/src/ui/modules/settings/Settings.tsx (3)

76-96: Add error handling for localStorage operations

While the guild whitelist implementation is clean, consider adding try-catch blocks around localStorage operations to handle potential errors (e.g., when storage is full or disabled).

  const [selectedGuilds, setSelectedGuilds] = useState<string[]>(() => {
-   const savedGuilds = localStorage.getItem("WHITELIST");
-   return savedGuilds ? savedGuilds.split(",") : [];
+   try {
+     const savedGuilds = localStorage.getItem("WHITELIST");
+     return savedGuilds ? savedGuilds.split(",") : [];
+   } catch (error) {
+     console.error("Failed to load guild whitelist:", error);
+     return [];
+   }
  });

  const handleGuildSelect = (guildId: string) => {
    setSelectedGuilds((prev) => {
      const newGuilds = prev.includes(guildId) ? prev.filter((id) => id !== guildId) : [...prev, guildId];
-     localStorage.setItem("WHITELIST", newGuilds.join(","));
+     try {
+       localStorage.setItem("WHITELIST", newGuilds.join(","));
+       toast(prev.includes(guildId) ? "Guild removed from whitelist!" : "Guild added to whitelist!");
+     } catch (error) {
+       console.error("Failed to save guild whitelist:", error);
+       toast.error("Failed to save guild selection");
+     }
      return newGuilds;
    });
  };

98-107: Enhance UX during flat mode toggle

The page reload approach works but might be jarring for users. Consider these improvements:

  1. Show a loading overlay during the reload
  2. Save any unsaved user state before reload
  3. Add a confirmation dialog for better user experience
  const toggleFlatMode = () => {
+   if (!confirm("Changing view mode will reload the page. Continue?")) {
+     return;
+   }
    setIsFlatMode((prev) => {
      const newFlatMode = !prev;
-     localStorage.setItem("FLAT_MODE", newFlatMode.toString());
-     window.location.reload();
+     try {
+       localStorage.setItem("FLAT_MODE", newFlatMode.toString());
+       setBlankOverlay(true); // Show loading overlay
+       window.location.reload();
+     } catch (error) {
+       console.error("Failed to save flat mode setting:", error);
+       toast.error("Failed to change view mode");
+     }
      return newFlatMode;
    });
  };

170-194: Consider pagination for guild list

The guild whitelist UI implementation looks clean, but consider adding pagination or virtualization if the list of guilds grows large. This would improve performance and prevent potential UI issues with a large number of guilds.

Consider using a virtualized list component like react-window or react-virtualized for better performance with large lists:

import { FixedSizeList } from 'react-window';

const GuildList = ({ guilds, selectedGuilds, onSelect }) => {
  const Row = ({ index, style }) => (
    <Button
      style={style}
      size="xs"
      key={guilds[index].entityId}
      variant={selectedGuilds.includes(guilds[index].entityId.toString()) ? "success" : "outline"}
      onClick={() => onSelect(guilds[index].entityId.toString())}
    >
      {guilds[index].name}
    </Button>
  );

  return (
    <FixedSizeList
      height={200}
      itemCount={guilds.length}
      itemSize={35}
      width="100%"
    >
      {Row}
    </FixedSizeList>
  );
};
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 61a9e43 and 2e2d05a.

📒 Files selected for processing (1)
  • client/src/ui/modules/settings/Settings.tsx (3 hunks)
🔇 Additional comments (1)
client/src/ui/modules/settings/Settings.tsx (1)

15-15: LGTM: Clean import addition

The import of IS_FLAT_MODE is properly organized alongside existing graphics settings imports.

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