Try to create dotnet helper LyraApi package for guests
This commit is contained in:
parent
01bb7d0bc8
commit
faa5387f93
|
@ -0,0 +1,28 @@
|
||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.0.31903.59
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LyraApi", "guests/csharp/LyraApi/LyraApi.csproj", "{A4003DF0-C8FF-4A50-A66C-9777E900ED21}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "dotnet-guest-test", "guests/csharp/dotnet-guest-test\dotnet-guest-test.csproj", "{68F96E6F-472F-409E-B36E-9C5E7206CCDE}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{A4003DF0-C8FF-4A50-A66C-9777E900ED21}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{A4003DF0-C8FF-4A50-A66C-9777E900ED21}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{A4003DF0-C8FF-4A50-A66C-9777E900ED21}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{A4003DF0-C8FF-4A50-A66C-9777E900ED21}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{68F96E6F-472F-409E-B36E-9C5E7206CCDE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{68F96E6F-472F-409E-B36E-9C5E7206CCDE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{68F96E6F-472F-409E-B36E-9C5E7206CCDE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{68F96E6F-472F-409E-B36E-9C5E7206CCDE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
|
@ -0,0 +1,2 @@
|
||||||
|
bin
|
||||||
|
obj
|
|
@ -0,0 +1,10 @@
|
||||||
|
namespace LyraApi.Ecs;
|
||||||
|
using ImportsWorld.wit.imports.lyra.api;
|
||||||
|
|
||||||
|
public class Entity(IEcs.Entity entity) {
|
||||||
|
internal IEcs.Entity Inner { get; set; } = entity;
|
||||||
|
|
||||||
|
public ulong Id { get => Inner.id.id; }
|
||||||
|
public ulong Generation { get => Inner.generation; }
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
using ImportsWorld.wit.imports.lyra.api;
|
||||||
|
|
||||||
|
namespace LyraApi.Ecs;
|
||||||
|
|
||||||
|
public interface IComponent {
|
||||||
|
public static string HostName { get; }
|
||||||
|
public static ulong HostSize { get; }
|
||||||
|
public static ulong HostAlignment { get; }
|
||||||
|
public static ulong TypeId { get; }
|
||||||
|
|
||||||
|
public IEcs.ComponentInfo GetComponentInfo() {
|
||||||
|
var typeId = new IEcs.WasmTypeId((TypeId, 0));
|
||||||
|
return new IEcs.ComponentInfo(HostName, HostSize, HostAlignment, typeId);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
namespace LyraApi.Ecs;
|
||||||
|
|
||||||
|
using ImportsWorld.wit.imports.lyra.api;
|
||||||
|
using LyraApi;
|
||||||
|
|
||||||
|
public class World(IEcs.EcsWorld world) {
|
||||||
|
private IEcs.EcsWorld Inner { get; set; } = world;
|
||||||
|
|
||||||
|
public Entity Spawn(params IComponent[] comps) {
|
||||||
|
List<IEcs.ComponentInfo> infos = comps.Select(c => c.GetComponentInfo()).ToList();
|
||||||
|
byte[] bytes = comps.SelectMany(c => Marshalling.GetBytes(c)).ToArray();
|
||||||
|
return new Entity(Inner.Spawn(bytes, infos));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
<RootNamespace>LyraApi</RootNamespace>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
|
||||||
|
<RuntimeIdentifier>wasi-wasm</RuntimeIdentifier>
|
||||||
|
<UseAppHost>false</UseAppHost>
|
||||||
|
<PublishTrimmed>true</PublishTrimmed>
|
||||||
|
<InvariantGlobalization>true</InvariantGlobalization>
|
||||||
|
<SelfContained>true</SelfContained>
|
||||||
|
<IlcExportUnmanagedEntrypoints>true</IlcExportUnmanagedEntrypoints>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="BytecodeAlliance.Componentize.DotNet.Wasm.SDK" Version="0.4.0-preview00007" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Wit Remove="**\*.wit" />
|
||||||
|
<Wit Include="wit" World="imports" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="runtime.linux-x64.Microsoft.DotNet.ILCompiler.LLVM" Version="10.0.0-alpha.1.24531.4" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
|
@ -0,0 +1,47 @@
|
||||||
|
namespace LyraApi;
|
||||||
|
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
public static class Marshalling {
|
||||||
|
internal struct AlignmentHelper<T> where T : unmanaged
|
||||||
|
{
|
||||||
|
public byte Padding;
|
||||||
|
public T Target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int AlignmentOf<T>() where T : unmanaged
|
||||||
|
{
|
||||||
|
return (int)Marshal.OffsetOf<AlignmentHelper<T>>(nameof(AlignmentHelper<T>.Target));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] GetBytes<T>([DisallowNull] T data) {
|
||||||
|
int size = Marshal.SizeOf(data);
|
||||||
|
byte[] arr = new byte[size];
|
||||||
|
|
||||||
|
IntPtr ptr = IntPtr.Zero;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ptr = Marshal.AllocHGlobal(size);
|
||||||
|
Marshal.StructureToPtr(data, ptr, true);
|
||||||
|
Marshal.Copy(ptr, arr, 0, size);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Marshal.FreeHGlobal(ptr);
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static T? FromBytes<T>(byte[] data) where T : struct
|
||||||
|
{
|
||||||
|
var ptr = GCHandle.Alloc(data, GCHandleType.Pinned);
|
||||||
|
try {
|
||||||
|
var res = (T?) Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(T));
|
||||||
|
return res;
|
||||||
|
} finally {
|
||||||
|
ptr.Free();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<configuration>
|
||||||
|
<packageSources>
|
||||||
|
<!--To inherit the global NuGet package sources remove the <clear/> line below -->
|
||||||
|
<clear />
|
||||||
|
<add key="dotnet-experimental" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-experimental/nuget/v3/index.json" />
|
||||||
|
<add key="nuget" value="https://api.nuget.org/v3/index.json" />
|
||||||
|
</packageSources>
|
||||||
|
</configuration>
|
|
@ -0,0 +1,81 @@
|
||||||
|
package lyra:api;
|
||||||
|
|
||||||
|
interface ecs {
|
||||||
|
record entity-id {
|
||||||
|
id: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
record entity {
|
||||||
|
id: entity-id,
|
||||||
|
generation: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
record wasm-type-id {
|
||||||
|
// represents a u128, can be converted into that with mem::transmute
|
||||||
|
inner: tuple<u64, u64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
record component-info {
|
||||||
|
host-name: option<string>,
|
||||||
|
/// The size of the component in memory.
|
||||||
|
size: u64,
|
||||||
|
/// The alignment of the component in memory.
|
||||||
|
alignment: u64,
|
||||||
|
/// The type id of the component.
|
||||||
|
///
|
||||||
|
/// This must be unique between component types since its used to identify the components
|
||||||
|
/// in spawning and querying.
|
||||||
|
type-id: wasm-type-id,
|
||||||
|
}
|
||||||
|
|
||||||
|
resource ecs-dynamic-view {
|
||||||
|
constructor(wrld: borrow<ecs-world>, component-infos: list<component-info>);
|
||||||
|
|
||||||
|
/// Get the bytes of the next row in the view.
|
||||||
|
///
|
||||||
|
/// A row contains multiple component serialized as bytes. The buffer is tighly packed.
|
||||||
|
next: func() -> option<tuple<entity, list<u8>>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
resource ecs-world {
|
||||||
|
constructor();
|
||||||
|
|
||||||
|
/// Spawn an entity.
|
||||||
|
///
|
||||||
|
/// Parameters:
|
||||||
|
/// * `components`: A tightly packed byte buffer containing the components to spawn
|
||||||
|
/// with the entity. This expects the components in the same order of `component-infos`.
|
||||||
|
/// * `component-infos`: A list of `component-infos` uses to identify the components
|
||||||
|
/// and specify the layouts of them.
|
||||||
|
spawn: func(components: list<u8>, component-infos: list<component-info>) -> entity;
|
||||||
|
|
||||||
|
/// Insert components into an existing entity.
|
||||||
|
///
|
||||||
|
/// Parameters:
|
||||||
|
/// * `en`: The entity to insert into.
|
||||||
|
/// * `components`: A tightly packed byte buffer containing the components to spawn
|
||||||
|
/// with the entity. This expects the components in the same order of `component-infos`.
|
||||||
|
/// * `component-infos`: A list of `component-infos` uses to identify the components
|
||||||
|
/// and specify the layouts of them.
|
||||||
|
insert: func(en: entity, components: list<u8>, component-infos: list<component-info>);
|
||||||
|
|
||||||
|
/// Query for a list of entities and their components.
|
||||||
|
///
|
||||||
|
/// Parameters:
|
||||||
|
/// * `component-infos`: The `component-info`'s of the components that you are querying.
|
||||||
|
///
|
||||||
|
/// Returns: an iterator that returns the byte buffers of each row.
|
||||||
|
view: func(component-infos: list<component-info>) -> ecs-dynamic-view;
|
||||||
|
|
||||||
|
/// Query for components from a single entity.
|
||||||
|
///
|
||||||
|
/// Parameters:
|
||||||
|
/// * `en`: The entity to query components from.
|
||||||
|
/// * `component-infos`: The `component-info`'s of the components that you are querying.
|
||||||
|
///
|
||||||
|
/// Returns: A row of components serialized as bytes. The buffer is tighly packed.
|
||||||
|
view-one: func(en: entity, component-infos: list<component-info>) -> option<list<u8>>;
|
||||||
|
|
||||||
|
//with_system: func(stage: string, component-infos: list<component-info>, system: func(components: list<u8>));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
package lyra:api;
|
||||||
|
|
||||||
|
world imports {
|
||||||
|
import ecs;
|
||||||
|
}
|
|
@ -3,15 +3,12 @@
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using ExampleWorld.wit.imports.lyra.api;
|
using ExampleWorld.wit.imports.lyra.api;
|
||||||
|
using LyraApi;
|
||||||
|
using LyraApi.Ecs;
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
struct Vec3(float x, float y, float z)
|
struct Vec3(float x, float y, float z) : IComponent
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Unique TypeId of Vec3 that the host can use. This corresponds to the type id of vec3 on the host.
|
|
||||||
/// </summary>
|
|
||||||
public const ulong TypeId = 4124409524;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The X component.
|
/// The X component.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -24,6 +21,11 @@ struct Vec3(float x, float y, float z)
|
||||||
/// The Z component
|
/// The Z component
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public float Z { get; set; } = z;
|
public float Z { get; set; } = z;
|
||||||
|
|
||||||
|
public static string HostName { get => "Vec3"; }
|
||||||
|
public static ulong HostSize { get => (ulong)Marshal.SizeOf<Vec3>(); }
|
||||||
|
public static ulong HostAlignment { get => (ulong)Marshalling.AlignmentOf<Vec3>(); }
|
||||||
|
public static ulong TypeId { get => 4124409524; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ExampleWorldImpl : IExampleWorld
|
public class ExampleWorldImpl : IExampleWorld
|
||||||
|
@ -71,16 +73,18 @@ public class ExampleWorldImpl : IExampleWorld
|
||||||
|
|
||||||
public static void OnInit(IEcs.EcsWorld gameWorld, IEcs.Entity owningEntity)
|
public static void OnInit(IEcs.EcsWorld gameWorld, IEcs.Entity owningEntity)
|
||||||
{
|
{
|
||||||
|
var pos = new Vec3(7.0f, 30.0f, 18.0f);
|
||||||
var size = new IEcs.WasmTypeId((Vec3.TypeId, 0));
|
var size = new IEcs.WasmTypeId((Vec3.TypeId, 0));
|
||||||
var info = new IEcs.ComponentInfo("Vec3", (ulong) Marshal.SizeOf<Vec3>(), (ulong) AlignmentOf<Vec3>(), size);
|
var info = new IEcs.ComponentInfo("Vec3", (ulong) Marshal.SizeOf<Vec3>(), (ulong) AlignmentOf<Vec3>(), size);
|
||||||
var pos = new Vec3(7.0f, 30.0f, 18.0f);
|
|
||||||
var infos = new List<IEcs.ComponentInfo>
|
var infos = new List<IEcs.ComponentInfo>
|
||||||
{
|
{
|
||||||
info
|
info
|
||||||
};
|
};
|
||||||
|
|
||||||
IEcs.Entity entity = gameWorld.Spawn(GetBytes(pos), infos);
|
var world = new World(gameWorld);
|
||||||
Console.WriteLine("C#: Spawned {0}", entity.id.id);
|
Entity entity = world.Spawn(pos);
|
||||||
|
//IEcs.Entity entity = gameWorld.Spawn(GetBytes(pos), infos);
|
||||||
|
Console.WriteLine("C#: Spawned {0}", entity.Id);
|
||||||
|
|
||||||
IEcs.EcsDynamicView res = gameWorld.View(infos);
|
IEcs.EcsDynamicView res = gameWorld.View(infos);
|
||||||
(IEcs.Entity, byte[])? row = res.Next();
|
(IEcs.Entity, byte[])? row = res.Next();
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Library</OutputType>
|
<OutputType>Library</OutputType>
|
||||||
<TargetFramework>net9.0</TargetFramework>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
<!-- <RootNamespace>dotnet_guest_test</RootNamespace> -->
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
|
||||||
|
@ -15,22 +14,21 @@
|
||||||
<IlcExportUnmanagedEntrypoints>true</IlcExportUnmanagedEntrypoints>
|
<IlcExportUnmanagedEntrypoints>true</IlcExportUnmanagedEntrypoints>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<!-- <Target Name="BeforeBuild">
|
<!-- Copy WIT files from LyraApi to lyra-api wit folder -->
|
||||||
<Exec Command="rm -r wit/deps/lyraapi" />
|
<Target Name="CopyFolderOnBuild" BeforeTargets="WitCompile_InvokeTool">
|
||||||
<Exec Command="cp -r ../common-api/wit wit/deps/lyraapi" />
|
<ItemGroup>
|
||||||
</Target> -->
|
<MyFiles Include="..\LyraApi\wit\**\*.wit" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Copy SourceFiles="@(MyFiles)" DestinationFolder="wit\deps\lyraapi\%(RecursiveDir)" />
|
||||||
|
</Target>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="BytecodeAlliance.Componentize.DotNet.Wasm.SDK" Version="0.4.0-preview00007" />
|
<PackageReference Include="BytecodeAlliance.Componentize.DotNet.Wasm.SDK" Version="0.4.0-preview00007" />
|
||||||
<!-- <PackageReference Include="runtime.linux-x64.Microsoft.DotNet.ILCompiler.LLVM" Version="10.0.0-alpha.1.24508.1" /> -->
|
|
||||||
<!-- <ProjectReference Include=".\componentize-dotnet\src\WasmComponent.Sdk\WasmComponent.Sdk.csproj" /> -->
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<!-- dotnet add -->
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Wit Remove="**\*.wit" />
|
<Wit Remove="**\*.wit" />
|
||||||
<Wit Include="wit/deps/lyraapi" World="imports" />
|
<!-- <Wit Include="wit/deps/lyraapi" World="imports" /> -->
|
||||||
<Wit Include="wit" World="example" />
|
<Wit Include="wit" World="example" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
@ -38,4 +36,7 @@
|
||||||
<PackageReference Include="runtime.linux-x64.Microsoft.DotNet.ILCompiler.LLVM" Version="10.0.0-alpha.1.24531.4" />
|
<PackageReference Include="runtime.linux-x64.Microsoft.DotNet.ILCompiler.LLVM" Version="10.0.0-alpha.1.24531.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\LyraApi\LyraApi.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
|
||||||
# Visual Studio Version 17
|
|
||||||
VisualStudioVersion = 17.5.002.0
|
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-guest-test", "dotnet-guest-test\dotnet-guest-test.csproj", "{84E6E3EF-CAF8-40FB-B209-9144DFFCC304}"
|
|
||||||
EndProject
|
|
||||||
Global
|
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
|
||||||
Debug|Any CPU = Debug|Any CPU
|
|
||||||
Release|Any CPU = Release|Any CPU
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
|
||||||
{84E6E3EF-CAF8-40FB-B209-9144DFFCC304}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{84E6E3EF-CAF8-40FB-B209-9144DFFCC304}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{84E6E3EF-CAF8-40FB-B209-9144DFFCC304}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{84E6E3EF-CAF8-40FB-B209-9144DFFCC304}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
|
||||||
HideSolutionNode = FALSE
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
|
||||||
SolutionGuid = {EB233F5A-B23E-444C-8C04-895EAFB95F5C}
|
|
||||||
EndGlobalSection
|
|
||||||
EndGlobal
|
|
Loading…
Reference in New Issue