feat: spawn spheres via MCP — shape parameter cube/sphere
- SpawnModelCommand: added Shape property (default 'cube') - AiCommandProcessor: if shape='sphere', uses ProceduralMesh.CreateSphere instead of loading OBJ file; physics uses DynamicSphere instead of DynamicBox - EngineMcpTools: added 'shape' parameter to SpawnModel tool - Engine.AI now references Engine.Graphics for ProceduralMesh access
This commit is contained in:
@@ -6,6 +6,7 @@ using Engine.AI.Commands;
|
|||||||
using Engine.AI.Serialization;
|
using Engine.AI.Serialization;
|
||||||
using Engine.Core;
|
using Engine.Core;
|
||||||
using Engine.Core.Components;
|
using Engine.Core.Components;
|
||||||
|
using Engine.Graphics;
|
||||||
using Flecs.NET.Core;
|
using Flecs.NET.Core;
|
||||||
|
|
||||||
namespace Engine.AI;
|
namespace Engine.AI;
|
||||||
@@ -78,7 +79,17 @@ public sealed class AiCommandProcessor
|
|||||||
|
|
||||||
private AiCommandResult SpawnModel(SpawnModelCommand command)
|
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)
|
var entity = _world.Entity(command.Name)
|
||||||
.Set(new Transform(command.Position, command.Rotation, command.Scale))
|
.Set(new Transform(command.Position, command.Rotation, command.Scale))
|
||||||
.Set(mesh);
|
.Set(mesh);
|
||||||
@@ -86,11 +97,17 @@ public sealed class AiCommandProcessor
|
|||||||
if (command.Physics)
|
if (command.Physics)
|
||||||
{
|
{
|
||||||
var maxScale = MathF.Max(MathF.Max(command.Scale.X, command.Scale.Y), command.Scale.Z);
|
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);
|
if (command.Shape == "sphere")
|
||||||
entity.Set(rb);
|
{
|
||||||
|
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)
|
private AiCommandResult SetTransform(SetTransformCommand command)
|
||||||
|
|||||||
@@ -13,4 +13,5 @@ public sealed record SpawnModelCommand : AiCommand
|
|||||||
public Quaternion Rotation { get; init; } = Quaternion.Identity;
|
public Quaternion Rotation { get; init; } = Quaternion.Identity;
|
||||||
public Vector3 Scale { get; init; } = Vector3.One;
|
public Vector3 Scale { get; init; } = Vector3.One;
|
||||||
public bool Physics { get; init; } = false;
|
public bool Physics { get; init; } = false;
|
||||||
|
public string Shape { get; init; } = "cube";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Engine.Core\Engine.Core.csproj" />
|
<ProjectReference Include="..\Engine.Core\Engine.Core.csproj" />
|
||||||
|
<ProjectReference Include="..\Engine.Graphics\Engine.Graphics.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition="'$(Configuration)' != 'ReleaseAOT'">
|
<ItemGroup Condition="'$(Configuration)' != 'ReleaseAOT'">
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ public sealed class EngineMcpTools
|
|||||||
[Description("Optional position as [x, y, z] (default: 0,0,0)")] IReadOnlyList<double>? position = null,
|
[Description("Optional position as [x, y, z] (default: 0,0,0)")] IReadOnlyList<double>? position = null,
|
||||||
[Description("Optional rotation as [x, y, z, w] quaternion (default: identity)")] IReadOnlyList<double>? rotation = null,
|
[Description("Optional rotation as [x, y, z, w] quaternion (default: identity)")] IReadOnlyList<double>? rotation = null,
|
||||||
[Description("Optional scale as [x, y, z] (default: 1,1,1)")] IReadOnlyList<double>? scale = null,
|
[Description("Optional scale as [x, y, z] (default: 1,1,1)")] IReadOnlyList<double>? 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
|
var cmd = new SpawnModelCommand
|
||||||
{
|
{
|
||||||
@@ -34,7 +35,8 @@ public sealed class EngineMcpTools
|
|||||||
Position = ToVector3(position, Vector3.Zero),
|
Position = ToVector3(position, Vector3.Zero),
|
||||||
Rotation = ToQuaternion(rotation, Quaternion.Identity),
|
Rotation = ToQuaternion(rotation, Quaternion.Identity),
|
||||||
Scale = ToVector3(scale, Vector3.One),
|
Scale = ToVector3(scale, Vector3.One),
|
||||||
Physics = physics
|
Physics = physics,
|
||||||
|
Shape = shape
|
||||||
};
|
};
|
||||||
|
|
||||||
return EnqueueAndReturnMessage(cmd);
|
return EnqueueAndReturnMessage(cmd);
|
||||||
|
|||||||
Reference in New Issue
Block a user