Skip to content

Commit 25c73c9

Browse files
committed
stable
1 parent 78522e8 commit 25c73c9

12 files changed

Lines changed: 93 additions & 43 deletions

File tree

src/core/lib/ecs/ComponentRegistry.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export interface IComponentDescriptor<TData = unknown> {
1616
id: string;
1717
name: string;
1818
category: ComponentCategory;
19-
schema: z.ZodSchema<TData>;
19+
schema: z.ZodType<TData, any, any>;
2020
bitECSSchema: Record<string, unknown>;
2121
serialize: (eid: EntityId) => TData;
2222
deserialize: (eid: EntityId, data: TData) => void;
@@ -53,7 +53,7 @@ export class ComponentFactory {
5353
id: string;
5454
name: string;
5555
category: ComponentCategory;
56-
schema: z.ZodSchema<TData>;
56+
schema: z.ZodType<TData, any, any>;
5757
fields: Record<string, unknown>; // BitECS field definitions
5858
serialize: (eid: EntityId, bitECSComponent: unknown) => TData;
5959
deserialize: (eid: EntityId, data: TData, bitECSComponent: unknown) => void;
@@ -97,7 +97,7 @@ export class ComponentFactory {
9797
id: string;
9898
name: string;
9999
category: ComponentCategory;
100-
schema: z.ZodSchema<TData>;
100+
schema: z.ZodType<TData, any, any>;
101101
fieldMappings: Record<keyof TData, unknown>; // Maps data fields to BitECS types
102102
onAdd?: (eid: EntityId, data: TData) => void;
103103
onRemove?: (eid: EntityId) => void;

src/core/lib/ecs/components/definitions/MeshRendererComponent.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,19 @@ export const meshRendererComponent = ComponentFactory.create({
137137
component.modelPathHash[eid] = storeString(data.modelPath || '');
138138

139139
// Set material properties with defaults
140-
const material = data.material || {};
140+
const material = data.material || {
141+
shader: 'standard' as const,
142+
materialType: 'solid' as const,
143+
color: '#cccccc',
144+
normalScale: 1,
145+
metalness: 0,
146+
roughness: 0.7,
147+
emissive: '#000000',
148+
emissiveIntensity: 0,
149+
occlusionStrength: 1,
150+
textureOffsetX: 0,
151+
textureOffsetY: 0,
152+
};
141153
component.shader[eid] = material.shader === 'unlit' ? 1 : 0;
142154
component.materialType[eid] = material.materialType === 'texture' ? 1 : 0;
143155
setRgbValues(

src/core/lib/scripting/ScriptExecutor.ts

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -99,19 +99,34 @@ export class ScriptExecutor {
9999
// Parse regular function declarations
100100
while ((match = functionRegex.exec(cleanCode)) !== null) {
101101
const [, functionName, functionBody] = match;
102-
result[functionName as keyof IParsedScript] = functionBody.trim();
102+
const body = functionBody.trim();
103+
if (functionName === 'onStart') result.onStart = body;
104+
if (functionName === 'onUpdate') result.onUpdate = body;
105+
if (functionName === 'onDestroy') result.onDestroy = body;
106+
if (functionName === 'onEnable') result.onEnable = body;
107+
if (functionName === 'onDisable') result.onDisable = body;
103108
}
104109

105110
// Parse arrow function declarations
106111
while ((match = arrowFunctionRegex.exec(cleanCode)) !== null) {
107112
const [, functionName, functionBody] = match;
108-
result[functionName as keyof IParsedScript] = functionBody.trim();
113+
const body = functionBody.trim();
114+
if (functionName === 'onStart') result.onStart = body;
115+
if (functionName === 'onUpdate') result.onUpdate = body;
116+
if (functionName === 'onDestroy') result.onDestroy = body;
117+
if (functionName === 'onEnable') result.onEnable = body;
118+
if (functionName === 'onDisable') result.onDisable = body;
109119
}
110120

111121
// Parse simple arrow function assignments
112122
while ((match = simpleArrowRegex.exec(cleanCode)) !== null) {
113123
const [, functionName, functionBody] = match;
114-
result[functionName as keyof IParsedScript] = functionBody.trim();
124+
const body = functionBody.trim();
125+
if (functionName === 'onStart') result.onStart = body;
126+
if (functionName === 'onUpdate') result.onUpdate = body;
127+
if (functionName === 'onDestroy') result.onDestroy = body;
128+
if (functionName === 'onEnable') result.onEnable = body;
129+
if (functionName === 'onDisable') result.onDisable = body;
115130
}
116131

117132
console.log('[ScriptExecutor] Parsed script functions:', {
@@ -172,7 +187,10 @@ export class ScriptExecutor {
172187
const axis = match[1] as 'x' | 'y' | 'z';
173188
const value = parseFloat(match[2]);
174189
if (!isNaN(value)) {
175-
context.entity.position[axis] = value;
190+
const [px, py, pz] = context.entity.transform.position;
191+
if (axis === 'x') context.entity.transform.setPosition(value, py, pz);
192+
if (axis === 'y') context.entity.transform.setPosition(px, value, pz);
193+
if (axis === 'z') context.entity.transform.setPosition(px, py, value);
176194
}
177195
}
178196
}
@@ -190,12 +208,19 @@ export class ScriptExecutor {
190208
const operator = match[2];
191209
const value = parseFloat(match[3]);
192210
if (!isNaN(value)) {
211+
const [rx, ry, rz] = context.entity.transform.rotation;
193212
if (operator === '=') {
194-
context.entity.rotation[axis] = value;
213+
if (axis === 'x') context.entity.transform.setRotation(value, ry, rz);
214+
if (axis === 'y') context.entity.transform.setRotation(rx, value, rz);
215+
if (axis === 'z') context.entity.transform.setRotation(rx, ry, value);
195216
} else if (operator === '+') {
196-
context.entity.rotation[axis] += value;
217+
if (axis === 'x') context.entity.transform.setRotation(rx + value, ry, rz);
218+
if (axis === 'y') context.entity.transform.setRotation(rx, ry + value, rz);
219+
if (axis === 'z') context.entity.transform.setRotation(rx, ry, rz + value);
197220
} else if (operator === '-') {
198-
context.entity.rotation[axis] -= value;
221+
if (axis === 'x') context.entity.transform.setRotation(rx - value, ry, rz);
222+
if (axis === 'y') context.entity.transform.setRotation(rx, ry - value, rz);
223+
if (axis === 'z') context.entity.transform.setRotation(rx, ry, rz - value);
199224
}
200225
}
201226
}
@@ -214,7 +239,11 @@ export class ScriptExecutor {
214239
const axis = match[1] as 'x' | 'y' | 'z';
215240
const amplitude = parseFloat(match[2]);
216241
if (!isNaN(amplitude)) {
217-
context.entity.position[axis] = Math.sin(context.time.time) * amplitude;
242+
const value = Math.sin(context.time.time) * amplitude;
243+
const [px, py, pz] = context.entity.transform.position;
244+
if (axis === 'x') context.entity.transform.setPosition(value, py, pz);
245+
if (axis === 'y') context.entity.transform.setPosition(px, value, pz);
246+
if (axis === 'z') context.entity.transform.setPosition(px, py, value);
218247
}
219248
}
220249
}
@@ -229,7 +258,11 @@ export class ScriptExecutor {
229258
const axis = match[1] as 'x' | 'y' | 'z';
230259
const multiplier = match[2] ? parseFloat(match[2]) : 1;
231260
if (!isNaN(multiplier)) {
232-
context.entity.rotation[axis] += deltaTime * multiplier;
261+
const [rx, ry, rz] = context.entity.transform.rotation;
262+
const delta = deltaTime * multiplier;
263+
if (axis === 'x') context.entity.transform.setRotation(rx + delta, ry, rz);
264+
if (axis === 'y') context.entity.transform.setRotation(rx, ry + delta, rz);
265+
if (axis === 'z') context.entity.transform.setRotation(rx, ry, rz + delta);
233266
}
234267
}
235268
}

src/core/systems/cameraSystem.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,9 @@ export function cameraSystem(): number {
6868
if (!cameraData) return;
6969

7070
// Check if camera needs update (we'll use a simple flag for now)
71-
const bitECSCamera = componentRegistry.getBitECSComponent('Camera');
71+
const bitECSCamera = componentRegistry.getBitECSComponent('Camera') as
72+
| (Record<string, Record<number, number>> & { needsUpdate?: Record<number, number> })
73+
| undefined;
7274
if (!bitECSCamera?.needsUpdate?.[eid]) {
7375
return;
7476
}
@@ -136,14 +138,18 @@ export function markAllCamerasForUpdate(): number {
136138
}
137139

138140
const entities = query(world);
139-
const bitECSCamera = componentRegistry.getBitECSComponent('Camera');
141+
const bitECSCamera = componentRegistry.getBitECSComponent('Camera') as
142+
| (Record<string, Record<number, number>> & { needsUpdate?: Record<number, number> })
143+
| undefined;
140144

141145
if (!bitECSCamera?.needsUpdate) {
142146
return 0;
143147
}
144148

145149
entities.forEach((eid: number) => {
146-
bitECSCamera.needsUpdate[eid] = 1;
150+
if (bitECSCamera?.needsUpdate) {
151+
bitECSCamera.needsUpdate[eid] = 1;
152+
}
147153
});
148154

149155
return entities.length;

src/core/systems/lightSystem.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,9 @@ export function lightSystem(_deltaTime: number): number {
4242

4343
entities.forEach((eid: number) => {
4444
// Get the BitECS component to check needsUpdate flag
45-
const bitECSLight = componentRegistry.getBitECSComponent('Light');
45+
const bitECSLight = componentRegistry.getBitECSComponent('Light') as
46+
| (Record<string, Record<number, number>> & { needsUpdate?: Record<number, number> })
47+
| undefined;
4648
if (!bitECSLight?.needsUpdate?.[eid]) {
4749
return; // Skip entities that don't need updates
4850
}
@@ -65,7 +67,9 @@ export function lightSystem(_deltaTime: number): number {
6567
// This system just processes the ECS side and resets the needsUpdate flag
6668

6769
// Reset the needsUpdate flag after processing
68-
bitECSLight.needsUpdate[eid] = 0;
70+
if (bitECSLight?.needsUpdate) {
71+
bitECSLight.needsUpdate[eid] = 0;
72+
}
6973
updatedCount++;
7074
});
7175

src/editor/components/inspector/adapters/RigidBodyAdapter.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import React from 'react';
33
import { IComponent, KnownComponentTypes } from '@/core/lib/ecs/IComponent';
44
import { MeshColliderData } from '@/core/lib/ecs/components/definitions/MeshColliderComponent';
55
import { RigidBodyData } from '@/core/lib/ecs/components/definitions/RigidBodyComponent';
6-
import { RigidBodySection } from '@/editor/components/panels/InspectorPanel/RigidBody/RigidBodySection';
6+
import { RigidBodySection, BodyType } from '@/editor/components/panels/InspectorPanel/RigidBody/RigidBodySection';
77

88
interface IRigidBodyAdapterProps {
99
rigidBodyComponent: IComponent<RigidBodyData> | null;
@@ -34,14 +34,14 @@ export const RigidBodyAdapter: React.FC<IRigidBodyAdapterProps> = ({
3434
// Convert ECS data to the format expected by RigidBodySection
3535
const rigidBodyData = {
3636
enabled: data.enabled ?? true,
37-
bodyType: data.bodyType || data.type || 'dynamic',
37+
bodyType: (data.bodyType || data.type || 'dynamic') as BodyType,
3838
mass: data.mass || 1,
3939
gravityScale: data.gravityScale || 1,
4040
canSleep: data.canSleep ?? true,
41-
linearDamping: data.linearDamping || 0,
42-
angularDamping: data.angularDamping || 0,
43-
initialVelocity: data.initialVelocity || [0, 0, 0],
44-
initialAngularVelocity: data.initialAngularVelocity || [0, 0, 0],
41+
linearDamping: 0,
42+
angularDamping: 0,
43+
initialVelocity: [0, 0, 0] as [number, number, number],
44+
initialAngularVelocity: [0, 0, 0] as [number, number, number],
4545
material: {
4646
friction: data.material?.friction || 0.7,
4747
restitution: data.material?.restitution || 0.3,

src/editor/components/panels/InspectorPanel/MeshRenderer/MeshRendererSection.tsx

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,14 @@ export interface IMeshRendererData {
1717
enabled: boolean;
1818
castShadows: boolean;
1919
receiveShadows: boolean;
20-
material: {
21-
shader?: 'standard' | 'unlit';
22-
materialType?: 'solid' | 'texture';
20+
modelPath?: string;
21+
material?: {
22+
shader: 'standard' | 'unlit';
23+
materialType: 'solid' | 'texture';
2324
color: string;
2425
albedoTexture?: string;
2526
normalTexture?: string;
26-
normalScale?: number;
27+
normalScale: number;
2728
metalness: number;
2829
roughness: number;
2930
emissive: string;
@@ -32,9 +33,9 @@ export interface IMeshRendererData {
3233
roughnessTexture?: string;
3334
emissiveTexture?: string;
3435
occlusionTexture?: string;
35-
occlusionStrength?: number;
36-
textureOffsetX?: number;
37-
textureOffsetY?: number;
36+
occlusionStrength: number;
37+
textureOffsetX: number;
38+
textureOffsetY: number;
3839
};
3940
}
4041

src/editor/components/panels/ViewportPanel/EntityRenderer.tsx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
import type { ThreeEvent } from '@react-three/fiber';
22
import React from 'react';
3-
import type { Mesh } from 'three';
43

54
import type { IMeshColliderData } from '@/editor/components/panels/InspectorPanel/MeshCollider/MeshColliderSection';
65
import { useEditorStore } from '@/editor/store/editorStore';
76

87
import { GizmoControls } from './GizmoControls';
9-
import { EntityColliders } from './components/EntityColliders';
108
import { EntityMesh } from './components/EntityMesh';
119
import { EntityOutline } from './components/EntityOutline';
1210
import { useEntityColliders } from './hooks/useEntityColliders';
@@ -36,8 +34,6 @@ export interface IEntityRendererProps {
3634
allEntityIds?: number[];
3735
}
3836

39-
import type { TerrainData } from '@/core/lib/ecs/components/definitions/TerrainComponent';
40-
import { Logger } from '@/core/lib/logger';
4137
export const EntityRenderer: React.FC<IEntityRendererProps> = React.memo(
4238
({
4339
entityId,
@@ -49,7 +45,6 @@ export const EntityRenderer: React.FC<IEntityRendererProps> = React.memo(
4945
setIsTransforming,
5046
allEntityIds = [],
5147
}) => {
52-
const logger = Logger.create('EntityRenderer');
5348
const isPlaying = useEditorStore((s) => s.isPlaying);
5449

5550
// ALL HOOKS MUST BE CALLED BEFORE ANY EARLY RETURNS!
@@ -100,7 +95,7 @@ export const EntityRenderer: React.FC<IEntityRendererProps> = React.memo(
10095
const terrainComponent = React.useMemo(
10196
() => entityComponents.find((c) => c.type === 'Terrain'),
10297
[entityComponents.find((c) => c.type === 'Terrain')],
103-
);
98+
) as { type: string; data: { size: [number, number]; segments: [number, number]; heightScale: number; noiseEnabled: boolean; noiseSeed: number; noiseFrequency: number; noiseOctaves: number; noisePersistence: number; noiseLacunarity: number; }; } | undefined;
10499

105100
const { terrainColliderKey, enhancedColliderConfig, hasEffectiveCustomColliders } =
106101
useColliderConfiguration({
@@ -197,7 +192,7 @@ export const EntityRenderer: React.FC<IEntityRendererProps> = React.memo(
197192
rotationRadians={rotationRadians}
198193
scale={scale}
199194
enhancedColliderConfig={enhancedColliderConfig}
200-
meshCollider={meshCollider}
195+
meshCollider={meshCollider && Object.keys(meshCollider.data || {}).length > 0 ? meshCollider as { data: IMeshColliderData } : null}
201196
/>
202197
</group>
203198
);

src/editor/components/panels/ViewportPanel/components/EntityColliderVisualization.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export const EntityColliderVisualization: React.FC<IEntityColliderVisualizationP
3838
? [
3939
enhancedColliderConfig.terrain.widthSegments + 1,
4040
enhancedColliderConfig.terrain.depthSegments + 1,
41-
]
41+
] as [number, number]
4242
: undefined;
4343

4444
const terrainPositions =

src/editor/components/panels/ViewportPanel/components/EntityPhysicsBody.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export const EntityPhysicsBody: React.FC<IEntityPhysicsBodyProps> = React.memo(
4848
return (
4949
<RigidBody
5050
key={terrainColliderKey}
51-
type={rigidBodyProps.type}
51+
type={rigidBodyProps.type as any}
5252
mass={rigidBodyProps.mass}
5353
friction={rigidBodyProps.friction}
5454
restitution={rigidBodyProps.restitution}
@@ -64,7 +64,7 @@ export const EntityPhysicsBody: React.FC<IEntityPhysicsBodyProps> = React.memo(
6464
? false
6565
: hasCustomColliders || hasEffectiveCustomColliders
6666
? false
67-
: colliderType
67+
: (colliderType as any)
6868
}
6969
>
7070
{/* Custom Colliders - now properly handling heightfield */}

0 commit comments

Comments
 (0)