diff --git a/src/components/game/WebGPUGameCanvas.tsx b/src/components/game/WebGPUGameCanvas.tsx index 189f08e0..85aae2fd 100644 --- a/src/components/game/WebGPUGameCanvas.tsx +++ b/src/components/game/WebGPUGameCanvas.tsx @@ -203,7 +203,7 @@ export function WebGPUGameCanvas() { }); // Input handling hook - const { selectionState, handleMouseDown, handleMouseMove, handleMouseUp, handleContextMenu } = useGameInput({ + const { selectionState } = useGameInput({ containerRef, cameraRef: refs.camera, gameRef, @@ -646,10 +646,6 @@ export function WebGPUGameCanvas() {
{/* Loading screen */} {isLoading && ( diff --git a/src/components/game/hooks/useGameInput.ts b/src/components/game/hooks/useGameInput.ts index 74d7394b..73c9402f 100644 --- a/src/components/game/hooks/useGameInput.ts +++ b/src/components/game/hooks/useGameInput.ts @@ -49,14 +49,6 @@ export interface UseGameInputProps { export interface UseGameInputReturn { selectionState: SelectionState; - /** @deprecated Use InputManager.getInstance() directly */ - handleMouseDown: (e: React.MouseEvent) => void; - /** @deprecated Use InputManager.getInstance() directly */ - handleMouseMove: (e: React.MouseEvent) => void; - /** @deprecated Use InputManager.getInstance() directly */ - handleMouseUp: (e: React.MouseEvent) => void; - /** @deprecated Use InputManager.getInstance() directly */ - handleContextMenu: (e: React.MouseEvent) => void; } // Default selection state for SSR or before initialization @@ -185,39 +177,7 @@ export function useGameInput({ () => defaultSelectionState // Server snapshot ); - // ============================================================================= - // LEGACY EVENT HANDLERS (for backwards compatibility) - // ============================================================================= - - // These are kept for backwards compatibility but are no longer needed - // since InputManager handles events directly on the container - const handleMouseDown = useCallback((e: React.MouseEvent) => { - // Events are now handled by InputManager - // This handler is kept for backwards compatibility - }, []); - - const handleMouseMove = useCallback((e: React.MouseEvent) => { - // Events are now handled by InputManager - }, []); - - const handleMouseUp = useCallback((e: React.MouseEvent) => { - // Events are now handled by InputManager - }, []); - - const handleContextMenu = useCallback((e: React.MouseEvent) => { - e.preventDefault(); - // Events are now handled by InputManager - }, []); - - // ============================================================================= - // RETURN - // ============================================================================= - return { selectionState, - handleMouseDown, - handleMouseMove, - handleMouseUp, - handleContextMenu, }; } diff --git a/src/data/maps/MapTypes.ts b/src/data/maps/MapTypes.ts index 60cfc960..df4b8e40 100644 --- a/src/data/maps/MapTypes.ts +++ b/src/data/maps/MapTypes.ts @@ -74,28 +74,16 @@ export const TERRAIN_FEATURE_CONFIG: Record = { - 0: 60, // Low ground - 1: 140, // Mid ground - 2: 220, // High ground - }; - return mapping[level]; -} +/** Standard elevation values for gameplay zones */ +export const ELEVATION_LOW = 60; +export const ELEVATION_MID = 140; +export const ELEVATION_HIGH = 220; /** * Convert 0-255 elevation to gameplay zone (low/mid/high) @@ -249,22 +237,17 @@ export function createTerrainGrid( width: number, height: number, defaultTerrain: TerrainType = 'ground', - defaultElevation: ElevationLevel | Elevation = 1, + defaultElevation: Elevation = ELEVATION_MID, defaultFeature: TerrainFeature = 'none' ): MapCell[][] { const grid: MapCell[][] = []; - // Convert legacy elevation if needed - const elevation256 = typeof defaultElevation === 'number' && defaultElevation <= 2 - ? legacyElevationTo256(defaultElevation as ElevationLevel) - : defaultElevation as Elevation; - for (let y = 0; y < height; y++) { grid[y] = []; for (let x = 0; x < width; x++) { grid[y][x] = { terrain: defaultTerrain, - elevation: elevation256, + elevation: defaultElevation, feature: defaultFeature, textureId: Math.floor(Math.random() * 4), // Random texture variation }; @@ -452,14 +435,9 @@ export function fillTerrainRect( width: number, height: number, terrain: TerrainType, - elevation?: ElevationLevel | Elevation, + elevation?: Elevation, feature?: TerrainFeature ): void { - // Convert legacy elevation if provided - const elevation256 = elevation !== undefined - ? (elevation <= 2 ? legacyElevationTo256(elevation as ElevationLevel) : elevation) - : undefined; - for (let dy = 0; dy < height; dy++) { for (let dx = 0; dx < width; dx++) { const px = Math.floor(x + dx); @@ -472,8 +450,8 @@ export function fillTerrainRect( } grid[py][px].terrain = terrain; - if (elevation256 !== undefined) { - grid[py][px].elevation = elevation256; + if (elevation !== undefined) { + grid[py][px].elevation = elevation; } if (feature !== undefined) { grid[py][px].feature = feature; @@ -491,14 +469,9 @@ export function fillTerrainCircle( centerY: number, radius: number, terrain: TerrainType, - elevation?: ElevationLevel | Elevation, + elevation?: Elevation, feature?: TerrainFeature ): void { - // Convert legacy elevation if provided - const elevation256 = elevation !== undefined - ? (elevation <= 2 ? legacyElevationTo256(elevation as ElevationLevel) : elevation) - : undefined; - for (let y = -radius; y <= radius; y++) { for (let x = -radius; x <= radius; x++) { if (x * x + y * y <= radius * radius) { @@ -512,8 +485,8 @@ export function fillTerrainCircle( } grid[py][px].terrain = terrain; - if (elevation256 !== undefined) { - grid[py][px].elevation = elevation256; + if (elevation !== undefined) { + grid[py][px].elevation = elevation; } if (feature !== undefined) { grid[py][px].feature = feature; @@ -577,7 +550,7 @@ export function createRampInTerrain( * @param centerX - Center X of the platform * @param centerY - Center Y of the platform * @param radius - Radius of the buildable area - * @param elevation - Elevation level (0, 1, or 2) + * @param elevation - Elevation value (0-255, use ELEVATION_LOW/MID/HIGH constants) * @param cliffWidth - Width of the cliff ring around the platform (default 3) */ export function createRaisedPlatform( @@ -585,10 +558,9 @@ export function createRaisedPlatform( centerX: number, centerY: number, radius: number, - elevation: ElevationLevel, + elevation: Elevation, cliffWidth: number = 3 ): void { - const elevation256 = legacyElevationTo256(elevation); const outerRadius = radius + cliffWidth; for (let dy = -outerRadius; dy <= outerRadius; dy++) { @@ -607,7 +579,7 @@ export function createRaisedPlatform( // Inner buildable area grid[py][px] = { terrain: 'ground', - elevation: elevation256, + elevation: elevation, feature: 'none', textureId: Math.floor(Math.random() * 4), }; @@ -616,7 +588,7 @@ export function createRaisedPlatform( if (!isRampOrNearRamp(grid, px, py, cliffWidth + 1)) { grid[py][px] = { terrain: 'unwalkable', - elevation: elevation256, + elevation: elevation, feature: 'cliff', textureId: Math.floor(Math.random() * 4), }; @@ -630,6 +602,7 @@ export function createRaisedPlatform( /** * Create a raised rectangular platform with cliff edges. * Useful for bases that need non-circular shapes. + * @param elevation - Elevation value (0-255, use ELEVATION_LOW/MID/HIGH constants) */ export function createRaisedRect( grid: MapCell[][], @@ -637,10 +610,9 @@ export function createRaisedRect( y: number, width: number, height: number, - elevation: ElevationLevel, + elevation: Elevation, cliffWidth: number = 3 ): void { - const elevation256 = legacyElevationTo256(elevation); // Create outer cliff ring first for (let dy = -cliffWidth; dy < height + cliffWidth; dy++) { @@ -661,7 +633,7 @@ export function createRaisedRect( // Inner buildable area grid[py][px] = { terrain: 'ground', - elevation: elevation256, + elevation: elevation, feature: 'none', textureId: Math.floor(Math.random() * 4), }; @@ -669,7 +641,7 @@ export function createRaisedRect( // Cliff edge - buffer must be >= cliff width to ensure gap for ramps grid[py][px] = { terrain: 'unwalkable', - elevation: elevation256, + elevation: elevation, feature: 'cliff', textureId: Math.floor(Math.random() * 4), }; diff --git a/src/rendering/EnvironmentManager.ts b/src/rendering/EnvironmentManager.ts index 8c974c65..968264c8 100644 --- a/src/rendering/EnvironmentManager.ts +++ b/src/rendering/EnvironmentManager.ts @@ -44,7 +44,7 @@ export class EnvironmentManager { private waterMesh: WaterMesh | null = null; private mapBorderFog: TSLMapBorderFog | null = null; private particles: EnvironmentParticles | null = null; - private legacyDecorations: MapDecorations | null = null; + private mapDecorations: MapDecorations | null = null; // AAA decoration light manager - pools 50 lights for hundreds of emissive decorations private decorationLightManager: DecorationLightManager | null = null; // Centralized emissive decoration manager with animation and light attachment @@ -269,8 +269,8 @@ export class EnvironmentManager { } // MapDecorations handles watch towers and destructibles (non-instanced objects) - this.legacyDecorations = new MapDecorations(this.mapData, this.terrain, this.scene, this.decorationLightManager); - this.scene.add(this.legacyDecorations.group); + this.mapDecorations = new MapDecorations(this.mapData, this.terrain, this.scene, this.decorationLightManager); + this.scene.add(this.mapDecorations.group); } /** @@ -296,8 +296,8 @@ export class EnvironmentManager { } // Update emissive decoration pulsing animation - if (this.legacyDecorations) { - this.legacyDecorations.update(deltaTime); + if (this.mapDecorations) { + this.mapDecorations.update(deltaTime); } // Update emissive decoration manager (crystal pulsing, etc.) @@ -781,7 +781,7 @@ export class EnvironmentManager { if (this.waterMesh) this.scene.remove(this.waterMesh.group); if (this.mapBorderFog) this.scene.remove(this.mapBorderFog.mesh); if (this.particles) this.scene.remove(this.particles.points); - if (this.legacyDecorations) this.scene.remove(this.legacyDecorations.group); + if (this.mapDecorations) this.scene.remove(this.mapDecorations.group); // STEP 2: Now safe to dispose resources (no longer being rendered) this.trees?.dispose(); @@ -794,7 +794,7 @@ export class EnvironmentManager { this.waterMesh?.dispose(); this.mapBorderFog?.dispose(); this.particles?.dispose(); - this.legacyDecorations?.dispose(); + this.mapDecorations?.dispose(); this.decorationLightManager?.dispose(); this.emissiveDecorationManager?.dispose(); this.emissiveLightPool?.dispose(); diff --git a/src/rendering/Terrain.ts b/src/rendering/Terrain.ts index 868985b2..955b0e08 100644 --- a/src/rendering/Terrain.ts +++ b/src/rendering/Terrain.ts @@ -1,5 +1,5 @@ import * as THREE from 'three'; -import { MapData, MapCell, TerrainType, ElevationLevel, Elevation, TerrainFeature, TERRAIN_FEATURE_CONFIG } from '@/data/maps'; +import { MapData, MapCell, TerrainType, Elevation, TerrainFeature, TERRAIN_FEATURE_CONFIG } from '@/data/maps'; import { BiomeConfig, BIOMES, blendBiomeColors, BiomeType } from './Biomes'; import { TSLTerrainMaterial } from './tsl/TerrainMaterial'; import AssetManager from '@/assets/AssetManager'; diff --git a/src/utils/math.ts b/src/utils/math.ts index 1d72a670..5082d03e 100644 --- a/src/utils/math.ts +++ b/src/utils/math.ts @@ -48,28 +48,6 @@ export function angle(x1: number, y1: number, x2: number, y2: number): number { return Math.atan2(y2 - y1, x2 - x1); } -/** - * @internal NON-DETERMINISTIC - DO NOT USE IN GAMEPLAY CODE - * Uses Math.random() which breaks multiplayer sync. For gameplay randomness, - * use SeededRandom instead. This function exists only for non-gameplay uses - * like UI effects or debugging. - * @deprecated Use SeededRandom.nextRange() for deterministic gameplay - */ -export function randomRange(min: number, max: number): number { - return min + Math.random() * (max - min); -} - -/** - * @internal NON-DETERMINISTIC - DO NOT USE IN GAMEPLAY CODE - * Uses Math.random() which breaks multiplayer sync. For gameplay randomness, - * use SeededRandom instead. This function exists only for non-gameplay uses - * like UI effects or debugging. - * @deprecated Use SeededRandom.nextInt() for deterministic gameplay - */ -export function randomInt(min: number, max: number): number { - return Math.floor(randomRange(min, max + 1)); -} - // Seeded random for deterministic gameplay export class SeededRandom { private seed: number; diff --git a/tests/utils/math.test.ts b/tests/utils/math.test.ts index 411cf038..a2c6f56c 100644 --- a/tests/utils/math.test.ts +++ b/tests/utils/math.test.ts @@ -8,8 +8,6 @@ import { distanceXY, normalize, angle, - randomRange, - randomInt, SeededRandom, } from '@/utils/math'; @@ -47,16 +45,6 @@ describe('math utilities', () => { expect(angle(0, 0, 0, 1)).toBe(Math.PI / 2); }); - it('uses Math.random for non-deterministic helpers', () => { - const originalRandom = Math.random; - Math.random = () => 0.5; - - expect(randomRange(0, 10)).toBe(5); - expect(randomInt(0, 9)).toBe(5); - - Math.random = originalRandom; - }); - it('generates deterministic sequences with SeededRandom', () => { const rngA = new SeededRandom(42); const rngB = new SeededRandom(42);