diff --git a/src/Engine.AI/AiCommandProcessor.cs b/src/Engine.AI/AiCommandProcessor.cs index 1ee1425..1d2cb64 100644 --- a/src/Engine.AI/AiCommandProcessor.cs +++ b/src/Engine.AI/AiCommandProcessor.cs @@ -6,6 +6,7 @@ using Engine.AI.Commands; using Engine.AI.Serialization; using Engine.Core; using Engine.Core.Components; +using Engine.Graphics; using Flecs.NET.Core; namespace Engine.AI; @@ -78,7 +79,17 @@ public sealed class AiCommandProcessor private AiCommandResult SpawnModel(SpawnModelCommand command) { - var mesh = _modelLoader(command.ModelPath); + Mesh mesh; + if (command.Shape == "sphere") + { + var r = MathF.Max(MathF.Max(command.Scale.X, command.Scale.Y), command.Scale.Z) * 0.5f; + mesh = ProceduralMesh.CreateSphere(r, 24, 12, new Vector3(0.5f, 0.6f, 0.9f)); + } + else + { + mesh = _modelLoader(command.ModelPath); + } + var entity = _world.Entity(command.Name) .Set(new Transform(command.Position, command.Rotation, command.Scale)) .Set(mesh); @@ -86,11 +97,17 @@ public sealed class AiCommandProcessor if (command.Physics) { var maxScale = MathF.Max(MathF.Max(command.Scale.X, command.Scale.Y), command.Scale.Z); - var rb = RigidBody.DynamicBox(new Vector3(maxScale * 0.5f), mass: maxScale * 2f); - entity.Set(rb); + if (command.Shape == "sphere") + { + entity.Set(RigidBody.DynamicSphere(maxScale * 0.5f, mass: maxScale * 2f)); + } + else + { + entity.Set(RigidBody.DynamicBox(new Vector3(maxScale * 0.5f), mass: maxScale * 2f)); + } } - return AiCommandResult.Ok($"Spawned entity '{command.Name}' with model '{command.ModelPath}' (id {(ulong)entity.Id})."); + return AiCommandResult.Ok($"Spawned entity '{command.Name}' with shape '{command.Shape}' (id {(ulong)entity.Id})."); } private AiCommandResult SetTransform(SetTransformCommand command) diff --git a/src/Engine.AI/Commands/SpawnModelCommand.cs b/src/Engine.AI/Commands/SpawnModelCommand.cs index c7cc5f6..45ca3f0 100644 --- a/src/Engine.AI/Commands/SpawnModelCommand.cs +++ b/src/Engine.AI/Commands/SpawnModelCommand.cs @@ -13,4 +13,5 @@ public sealed record SpawnModelCommand : AiCommand public Quaternion Rotation { get; init; } = Quaternion.Identity; public Vector3 Scale { get; init; } = Vector3.One; public bool Physics { get; init; } = false; + public string Shape { get; init; } = "cube"; } diff --git a/src/Engine.AI/Engine.AI.csproj b/src/Engine.AI/Engine.AI.csproj index df8a9f9..318c4dc 100644 --- a/src/Engine.AI/Engine.AI.csproj +++ b/src/Engine.AI/Engine.AI.csproj @@ -13,6 +13,7 @@ + diff --git a/src/Engine.AI/Mcp/EngineMcpTools.cs b/src/Engine.AI/Mcp/EngineMcpTools.cs index c2c151d..1e6fab8 100644 --- a/src/Engine.AI/Mcp/EngineMcpTools.cs +++ b/src/Engine.AI/Mcp/EngineMcpTools.cs @@ -25,7 +25,8 @@ public sealed class EngineMcpTools [Description("Optional position as [x, y, z] (default: 0,0,0)")] IReadOnlyList? position = null, [Description("Optional rotation as [x, y, z, w] quaternion (default: identity)")] IReadOnlyList? rotation = null, [Description("Optional scale as [x, y, z] (default: 1,1,1)")] IReadOnlyList? scale = null, - [Description("Optional: enable physics (default: false)")] bool physics = false) + [Description("Optional: enable physics (default: false)")] bool physics = false, + [Description("Optional: shape type 'cube' or 'sphere' (default: cube)")] string shape = "cube") { var cmd = new SpawnModelCommand { @@ -34,7 +35,8 @@ public sealed class EngineMcpTools Position = ToVector3(position, Vector3.Zero), Rotation = ToQuaternion(rotation, Quaternion.Identity), Scale = ToVector3(scale, Vector3.One), - Physics = physics + Physics = physics, + Shape = shape }; return EnqueueAndReturnMessage(cmd);