Expose asset manager, can load images now
This commit is contained in:
parent
3245b4dad4
commit
68cd259bf7
|
@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio Version 17
|
# Visual Studio Version 17
|
||||||
VisualStudioVersion = 17.0.31903.59
|
VisualStudioVersion = 17.0.31903.59
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "dotnet-guest-test", "guests/csharp/dotnet-guest-test\dotnet-guest-test.csproj", "{68F96E6F-472F-409E-B36E-9C5E7206CCDE}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "dotnet-guest-test", "guests\csharp\dotnet-guest-test\dotnet-guest-test.csproj", "{68F96E6F-472F-409E-B36E-9C5E7206CCDE}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
namespace ExampleWorld;
|
namespace ExampleWorld;
|
||||||
|
|
||||||
using ExampleWorld.wit.imports.lyra.api;
|
using ExampleWorld.wit.imports.lyra.api;
|
||||||
|
using LyraApi.Asset;
|
||||||
using LyraApi.Ecs;
|
using LyraApi.Ecs;
|
||||||
using LyraApi.Engine;
|
using LyraApi.Engine;
|
||||||
using LyraApi.Math;
|
using LyraApi.Math;
|
||||||
|
@ -19,9 +19,31 @@ public class ExampleWorldImpl : IExampleWorld
|
||||||
Console.WriteLine("C#: Found entity at ({0}, {1}, {2})", comp.X, comp.Y, comp.Z);
|
Console.WriteLine("C#: Found entity at ({0}, {1}, {2})", comp.X, comp.Y, comp.Z);
|
||||||
}
|
}
|
||||||
|
|
||||||
DeltaTime? dt = world.GetResource<DeltaTime>();
|
/* DeltaTime? dt = world.GetResource<DeltaTime>();
|
||||||
if (dt != null) {
|
if (dt != null) {
|
||||||
Console.WriteLine($"C#: Delta time: {dt?.Seconds:0.##}");
|
Console.WriteLine($"C#: Delta time: {dt?.Seconds:0.##}");
|
||||||
|
} */
|
||||||
|
|
||||||
|
AssetManager? man = world.GetAssetManager();
|
||||||
|
if (man != null)
|
||||||
|
{
|
||||||
|
Handle<ImageHandle> han = man.Request<ImageHandle>("test_assets/white.png");
|
||||||
|
Console.WriteLine($"C#: Asset uuid: {han.Uuid}");
|
||||||
|
|
||||||
|
// wait for asset to load before trying to get the data
|
||||||
|
han.WaitForLoadRecursive();
|
||||||
|
if (!han.IsLoaded)
|
||||||
|
{
|
||||||
|
Console.WriteLine("C#: Asset is still not loaded, even after waiting!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// will be null if the image hasn't loaded yet
|
||||||
|
ImageHandle? img = han.GetData();
|
||||||
|
Console.WriteLine($"C#: Size of image: ({img?.Width}, {img?.Height})");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine("C#: No manager found");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
using LyraApi.Ecs;
|
||||||
|
using ExampleWorld.wit.imports.lyra.api;
|
||||||
|
|
||||||
|
namespace LyraApi.Asset;
|
||||||
|
|
||||||
|
public class AssetManager(IAsset.AssetManager assetManager) : IResource
|
||||||
|
{
|
||||||
|
internal IAsset.AssetManager inner = assetManager;
|
||||||
|
|
||||||
|
public static ulong TypeId => 567234789345;
|
||||||
|
|
||||||
|
public static object? FromWasmResult(IEcs.WorldResourceResult result)
|
||||||
|
{
|
||||||
|
switch (result.Tag)
|
||||||
|
{
|
||||||
|
case IEcs.WorldResourceResult.NONE:
|
||||||
|
return null;
|
||||||
|
case IEcs.WorldResourceResult.WASM_RESOURCE_REP:
|
||||||
|
Console.WriteLine($"Got the resource rep: {result.AsWasmResourceRep}");
|
||||||
|
var handle = new IAsset.AssetManager.THandle((int)result.AsWasmResourceRep);
|
||||||
|
var inner = new IAsset.AssetManager(handle);
|
||||||
|
return new AssetManager(inner);
|
||||||
|
case IEcs.WorldResourceResult.BYTES:
|
||||||
|
return null;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public UntypedHandle Request(string path)
|
||||||
|
{
|
||||||
|
return new UntypedHandle(inner.Request(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Handle<T> Request<T>(string path) where T : IAssetHandle
|
||||||
|
{
|
||||||
|
return Request(path).AsHandle<T>();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
namespace LyraApi.Asset;
|
||||||
|
|
||||||
|
public class Handle<T>(UntypedHandle handle) where T : IAssetHandle
|
||||||
|
{
|
||||||
|
internal UntypedHandle inner = handle;
|
||||||
|
|
||||||
|
public bool Watched { get => inner.Watched; set => inner.Watched = value; }
|
||||||
|
public ulong Version { get => inner.Version; }
|
||||||
|
public Guid Uuid { get => inner.Uuid; }
|
||||||
|
public string Path { get => inner.Path; }
|
||||||
|
public bool IsLoaded { get => inner.IsLoaded; }
|
||||||
|
|
||||||
|
public void WaitForLoad()
|
||||||
|
{
|
||||||
|
inner.WaitForLoad();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WaitForLoadRecursive()
|
||||||
|
{
|
||||||
|
inner.WaitForLoadRecursive();
|
||||||
|
}
|
||||||
|
|
||||||
|
public T? GetData()
|
||||||
|
{
|
||||||
|
if (IsLoaded)
|
||||||
|
{
|
||||||
|
return (T?)T.FromRawHandle(inner);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
namespace LyraApi.Asset;
|
||||||
|
|
||||||
|
public interface IAssetHandle
|
||||||
|
{
|
||||||
|
public abstract static object? FromRawHandle(UntypedHandle untypedHandle);
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
using ExampleWorld.wit.imports.lyra.api;
|
||||||
|
|
||||||
|
namespace LyraApi.Asset;
|
||||||
|
|
||||||
|
public class ImageHandle(IAsset.ImageHandle handle) : IAssetHandle
|
||||||
|
{
|
||||||
|
internal IAsset.ImageHandle inner = handle;
|
||||||
|
|
||||||
|
public uint? Height => inner.Height();
|
||||||
|
public uint? Width => inner.Width();
|
||||||
|
|
||||||
|
public static object? FromRawHandle(UntypedHandle untypedHandle)
|
||||||
|
{
|
||||||
|
var handle = IAsset.ImageHandle.FromRawHandle(untypedHandle.inner);
|
||||||
|
return handle != null ? new ImageHandle(handle) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the image's pixels as native endian bytes.
|
||||||
|
/// </summary>
|
||||||
|
///
|
||||||
|
/// Keep in mind that this does copy the image's pixels from the host.
|
||||||
|
/// This is pretty slow.
|
||||||
|
public byte[]? GetImageBytes()
|
||||||
|
{
|
||||||
|
return inner.GetBytes();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
using ExampleWorld.wit.imports.lyra.api;
|
||||||
|
|
||||||
|
namespace LyraApi.Asset;
|
||||||
|
|
||||||
|
public class UntypedHandle(IAsset.AssetHandle handle)
|
||||||
|
{
|
||||||
|
internal IAsset.AssetHandle inner = handle;
|
||||||
|
|
||||||
|
public bool Watched { get => inner.IsWatched(); set => inner.SetWatched(value); }
|
||||||
|
public ulong Version { get => inner.Version(); }
|
||||||
|
public Guid Uuid { get => Guid.Parse(inner.Uuid()); }
|
||||||
|
public string Path { get => inner.Path(); }
|
||||||
|
public bool IsLoaded { get => inner.IsLoaded(); }
|
||||||
|
|
||||||
|
public void WaitForLoad()
|
||||||
|
{
|
||||||
|
inner.WaitForLoad();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WaitForLoadRecursive()
|
||||||
|
{
|
||||||
|
inner.WaitRecurseDependenciesLoad();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Handle<T> AsHandle<T>() where T : IAssetHandle
|
||||||
|
{
|
||||||
|
return new Handle<T>(this);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,15 +2,16 @@ namespace LyraApi.Ecs;
|
||||||
|
|
||||||
using ExampleWorld.wit.imports.lyra.api;
|
using ExampleWorld.wit.imports.lyra.api;
|
||||||
using LyraApi;
|
using LyraApi;
|
||||||
|
using LyraApi.Asset;
|
||||||
|
|
||||||
public class World(IEcs.EcsWorld world)
|
public class World(IEcs.EcsWorld world)
|
||||||
{
|
{
|
||||||
private IEcs.EcsWorld Inner { get; set; } = world;
|
internal IEcs.EcsWorld inner = world;
|
||||||
|
|
||||||
private Entity Spawn(List<IEcs.ComponentInfo> infos, params object[] comps)
|
private Entity Spawn(List<IEcs.ComponentInfo> infos, params object[] comps)
|
||||||
{
|
{
|
||||||
byte[] bytes = comps.SelectMany(c => MarshalUtils.GetBytes(c)).ToArray();
|
byte[] bytes = comps.SelectMany(c => MarshalUtils.GetBytes(c)).ToArray();
|
||||||
return new Entity(Inner.Spawn(bytes, infos));
|
return new Entity(inner.Spawn(bytes, infos));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Entity Spawn<T1>(T1 c1) where T1 : IComponent
|
public Entity Spawn<T1>(T1 c1) where T1 : IComponent
|
||||||
|
@ -24,13 +25,27 @@ public class World(IEcs.EcsWorld world)
|
||||||
List<Component> comps = [Component.FromComponent<T1>()];
|
List<Component> comps = [Component.FromComponent<T1>()];
|
||||||
List<IEcs.ComponentInfo> infos = comps.Select(c => c.GetComponentInfo().info).ToList();
|
List<IEcs.ComponentInfo> infos = comps.Select(c => c.GetComponentInfo().info).ToList();
|
||||||
|
|
||||||
IEcs.EcsDynamicView dynamicView = Inner.View(infos);
|
IEcs.EcsDynamicView dynamicView = inner.View(infos);
|
||||||
return new ViewResult(comps, dynamicView).Get<T1>();
|
return new ViewResult(comps, dynamicView).Get<T1>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public T? GetResource<T>() where T : IResource
|
public T? GetResource<T>() where T : IResource
|
||||||
{
|
{
|
||||||
IEcs.WorldResourceResult result = Inner.GetResource(Utils.ToWasmTypeId(T.TypeId));
|
IEcs.WorldResourceResult result = inner.GetResource(Utils.ToWasmTypeId(T.TypeId));
|
||||||
return (T?) T.FromWasmResult(result);
|
return (T?)T.FromWasmResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AssetManager? GetAssetManager()
|
||||||
|
{
|
||||||
|
IAsset.AssetManager? assetManager = IAsset.AssetManager.FromWorld(inner);
|
||||||
|
|
||||||
|
if (assetManager != null)
|
||||||
|
{
|
||||||
|
return new AssetManager(assetManager);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -18,13 +18,17 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<!-- Copy WIT files from LyraApi to lyra-api wit folder. -->
|
<!-- Copy WIT files from LyraApi to lyra-api wit folder. -->
|
||||||
<Target Name="CopyFolderOnBuild" BeforeTargets="WitCompile_InvokeTool">
|
<Target Name="CopyLyraApiWit" BeforeTargets="WitCompile_InvokeTool">
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<MyFiles Include="..\..\rust\common-api\wit\**\*.wit" />
|
<MyFiles Include="..\..\rust\common-api\wit\**\*.wit" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Copy SourceFiles="@(MyFiles)" DestinationFolder="wit\deps\lyraapi\%(RecursiveDir)" />
|
<Copy SourceFiles="@(MyFiles)" DestinationFolder="wit\deps\lyraapi\%(RecursiveDir)" />
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="CopyComponentGuestWit" BeforeTargets="WitCompile_InvokeTool">
|
||||||
|
<Copy SourceFiles="..\..\rust\witguest\wit\world.wit" DestinationFiles="wit\world.wit" />
|
||||||
|
</Target>
|
||||||
|
|
||||||
<!-- Remove bindgen of LyraApi WIT .-->
|
<!-- Remove bindgen of LyraApi WIT .-->
|
||||||
<!-- <Target Name="RemoveBindgenLyraApi" AfterTargets="WitCompile_InvokeTool">
|
<!-- <Target Name="RemoveBindgenLyraApi" AfterTargets="WitCompile_InvokeTool">
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
interface asset {
|
||||||
|
resource asset-handle {
|
||||||
|
set-watched: func(watched: bool);
|
||||||
|
version: func() -> u64;
|
||||||
|
uuid: func() -> string;
|
||||||
|
path: func() -> option<string>;
|
||||||
|
is-watched: func() -> bool;
|
||||||
|
is-loaded: func() -> bool;
|
||||||
|
wait-for-load: func();
|
||||||
|
wait-recurse-dependencies-load: func();
|
||||||
|
}
|
||||||
|
|
||||||
|
resource image-handle {
|
||||||
|
from-raw-handle: static func(raw-handle: borrow<asset-handle>) -> option<image-handle>;
|
||||||
|
|
||||||
|
height: func() -> option<u32>;
|
||||||
|
width: func() -> option<u32>;
|
||||||
|
get-bytes: func() -> option<list<u8>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
use ecs.{ecs-world};
|
||||||
|
|
||||||
|
resource asset-manager {
|
||||||
|
from-world: static func(w: borrow<ecs-world>) -> option<asset-manager>;
|
||||||
|
request: func(path: string) -> asset-handle;
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,4 +2,5 @@ package lyra:api;
|
||||||
|
|
||||||
world imports {
|
world imports {
|
||||||
import ecs;
|
import ecs;
|
||||||
|
import asset;
|
||||||
}
|
}
|
|
@ -11,6 +11,7 @@ interface math {
|
||||||
/// An example world for the component to target.
|
/// An example world for the component to target.
|
||||||
world example {
|
world example {
|
||||||
import math;
|
import math;
|
||||||
|
import lyra:api/asset;
|
||||||
use lyra:api/ecs.{ecs-world, entity};
|
use lyra:api/ecs.{ecs-world, entity};
|
||||||
|
|
||||||
import host-print: func(msg: string);
|
import host-print: func(msg: string);
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
interface asset {
|
||||||
|
resource asset-handle {
|
||||||
|
set-watched: func(watched: bool);
|
||||||
|
version: func() -> u64;
|
||||||
|
uuid: func() -> string;
|
||||||
|
path: func() -> option<string>;
|
||||||
|
is-watched: func() -> bool;
|
||||||
|
is-loaded: func() -> bool;
|
||||||
|
wait-for-load: func();
|
||||||
|
wait-recurse-dependencies-load: func();
|
||||||
|
}
|
||||||
|
|
||||||
|
resource image-handle {
|
||||||
|
from-raw-handle: static func(raw-handle: borrow<asset-handle>) -> option<image-handle>;
|
||||||
|
|
||||||
|
height: func() -> option<u32>;
|
||||||
|
width: func() -> option<u32>;
|
||||||
|
get-bytes: func() -> option<list<u8>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
use ecs.{ecs-world};
|
||||||
|
|
||||||
|
resource asset-manager {
|
||||||
|
from-world: static func(w: borrow<ecs-world>) -> option<asset-manager>;
|
||||||
|
request: func(path: string) -> asset-handle;
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,4 +2,5 @@ package lyra:api;
|
||||||
|
|
||||||
world imports {
|
world imports {
|
||||||
import ecs;
|
import ecs;
|
||||||
|
import asset;
|
||||||
}
|
}
|
|
@ -5,6 +5,7 @@ wit_bindgen::generate!({
|
||||||
|
|
||||||
with: {
|
with: {
|
||||||
"lyra:api/ecs": common_api::bindings::lyra::api::ecs,
|
"lyra:api/ecs": common_api::bindings::lyra::api::ecs,
|
||||||
|
"lyra:api/asset": common_api::bindings::lyra::api::asset,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
interface asset {
|
||||||
|
resource asset-handle {
|
||||||
|
set-watched: func(watched: bool);
|
||||||
|
version: func() -> u64;
|
||||||
|
uuid: func() -> string;
|
||||||
|
path: func() -> option<string>;
|
||||||
|
is-watched: func() -> bool;
|
||||||
|
is-loaded: func() -> bool;
|
||||||
|
wait-for-load: func();
|
||||||
|
wait-recurse-dependencies-load: func();
|
||||||
|
}
|
||||||
|
|
||||||
|
resource image-handle {
|
||||||
|
from-raw-handle: static func(raw-handle: borrow<asset-handle>) -> option<image-handle>;
|
||||||
|
|
||||||
|
height: func() -> option<u32>;
|
||||||
|
width: func() -> option<u32>;
|
||||||
|
get-bytes: func() -> option<list<u8>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
use ecs.{ecs-world};
|
||||||
|
|
||||||
|
resource asset-manager {
|
||||||
|
from-world: static func(w: borrow<ecs-world>) -> option<asset-manager>;
|
||||||
|
request: func(path: string) -> asset-handle;
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,4 +2,5 @@ package lyra:api;
|
||||||
|
|
||||||
world imports {
|
world imports {
|
||||||
import ecs;
|
import ecs;
|
||||||
|
import asset;
|
||||||
}
|
}
|
|
@ -11,6 +11,7 @@ interface math {
|
||||||
/// An example world for the component to target.
|
/// An example world for the component to target.
|
||||||
world example {
|
world example {
|
||||||
import math;
|
import math;
|
||||||
|
import lyra:api/asset;
|
||||||
use lyra:api/ecs.{ecs-world, entity};
|
use lyra:api/ecs.{ecs-world, entity};
|
||||||
|
|
||||||
import host-print: func(msg: string);
|
import host-print: func(msg: string);
|
||||||
|
|
|
@ -0,0 +1,155 @@
|
||||||
|
use std::any::TypeId;
|
||||||
|
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use tokio::task;
|
||||||
|
use wasmtime::component::Resource as WasmResource;
|
||||||
|
|
||||||
|
use crate::WasmError;
|
||||||
|
use crate::{lyra, Imports};
|
||||||
|
|
||||||
|
use lyra::api::asset as wasm_asset;
|
||||||
|
use lyra::api::ecs as wasm_ecs;
|
||||||
|
|
||||||
|
impl wasm_asset::Host for Imports {}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl wasm_asset::HostAssetManager for Imports {
|
||||||
|
async fn from_world(&mut self, world: WasmResource<wasm_ecs::EcsWorld>) -> Option<WasmResource<wasm_asset::AssetManager>> {
|
||||||
|
let world_entry = self
|
||||||
|
.world_slab
|
||||||
|
.get(world.rep() as _)
|
||||||
|
.ok_or(WasmError::InvalidResourceHandle("EcsWorld")).unwrap();
|
||||||
|
let world = &world_entry.world;
|
||||||
|
|
||||||
|
let man = world.get_resource_data::<lyra_engine::assets::ResourceManager>()?;
|
||||||
|
let man_rep = self.asset_manager_slab.insert(man);
|
||||||
|
|
||||||
|
Some(WasmResource::new_own(man_rep as _))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn request(
|
||||||
|
&mut self,
|
||||||
|
this: WasmResource<wasm_asset::AssetManager>,
|
||||||
|
path: String,
|
||||||
|
) -> WasmResource<wasm_asset::AssetHandle> {
|
||||||
|
let man = self.asset_manager_slab.get(this.rep() as _)
|
||||||
|
.unwrap()
|
||||||
|
.get::<lyra_engine::assets::ResourceManager>();
|
||||||
|
let res = man.request_raw(&path).unwrap();
|
||||||
|
let rep = self.asset_handles_slab.insert(res);
|
||||||
|
WasmResource::new_own(rep as _)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn drop(&mut self, this: WasmResource<wasm_asset::AssetManager>) -> wasmtime::Result<()> {
|
||||||
|
let rep = this.rep() as usize;
|
||||||
|
if self.asset_handles_slab.contains(rep) {
|
||||||
|
self.asset_manager_slab.remove(rep);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl wasm_asset::HostAssetHandle for Imports {
|
||||||
|
async fn set_watched(&mut self, this: WasmResource<wasm_asset::AssetHandle>, watched: bool) {
|
||||||
|
let han = self.asset_handles_slab.get(this.rep() as _)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn version(&mut self, this: WasmResource<wasm_asset::AssetHandle>) -> u64 {
|
||||||
|
let han = self.asset_handles_slab.get(this.rep() as _)
|
||||||
|
.unwrap();
|
||||||
|
han.version() as u64
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn uuid(&mut self, this: WasmResource<wasm_asset::AssetHandle>) -> String {
|
||||||
|
let han = self.asset_handles_slab.get(this.rep() as _)
|
||||||
|
.unwrap();
|
||||||
|
han.uuid().to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn path(&mut self, this: WasmResource<wasm_asset::AssetHandle>) -> Option<String> {
|
||||||
|
let han = self.asset_handles_slab.get(this.rep() as _)
|
||||||
|
.unwrap();
|
||||||
|
han.path()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn is_watched(&mut self, this: WasmResource<wasm_asset::AssetHandle>) -> bool {
|
||||||
|
let han = self.asset_handles_slab.get(this.rep() as _)
|
||||||
|
.unwrap();
|
||||||
|
han.is_watched()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn is_loaded(&mut self, this: WasmResource<wasm_asset::AssetHandle>) -> bool {
|
||||||
|
let han = self.asset_handles_slab.get(this.rep() as _)
|
||||||
|
.unwrap();
|
||||||
|
han.is_loaded()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn wait_for_load(&mut self, this: WasmResource<wasm_asset::AssetHandle>) {
|
||||||
|
let han = self.asset_handles_slab.get(this.rep() as _)
|
||||||
|
.unwrap().clone();
|
||||||
|
|
||||||
|
tokio::task::spawn_blocking(move || {
|
||||||
|
han.wait_for_load();
|
||||||
|
}).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn wait_recurse_dependencies_load(
|
||||||
|
&mut self,
|
||||||
|
this: WasmResource<wasm_asset::AssetHandle>,
|
||||||
|
) {
|
||||||
|
let han = self.asset_handles_slab.get(this.rep() as _)
|
||||||
|
.unwrap().clone();
|
||||||
|
|
||||||
|
tokio::task::spawn_blocking(move || {
|
||||||
|
han.wait_recurse_dependencies_load();
|
||||||
|
}).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn drop(&mut self, this: WasmResource<wasm_asset::AssetHandle>) -> wasmtime::Result<()> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl wasm_asset::HostImageHandle for Imports {
|
||||||
|
async fn from_raw_handle(&mut self, raw_handle: WasmResource<wasm_asset::AssetHandle>) -> Option<WasmResource<wasm_asset::ImageHandle>> {
|
||||||
|
let untyped = self.asset_handles_slab.get(raw_handle.rep() as _)?;
|
||||||
|
// image will be none if the asset is not an image asset
|
||||||
|
let image = untyped.as_typed::<lyra_engine::assets::Image>();
|
||||||
|
if image.is_some() {
|
||||||
|
Some(WasmResource::new_own(raw_handle.rep()))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn height(&mut self, this: WasmResource<wasm_asset::ImageHandle>) -> Option<u32> {
|
||||||
|
let untyped = self.asset_handles_slab.get(this.rep() as _)?;
|
||||||
|
let image = untyped.as_typed::<lyra_engine::assets::Image>()?;
|
||||||
|
let image = image.data_ref()?;
|
||||||
|
Some(image.height())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn width(&mut self, this: WasmResource<wasm_asset::ImageHandle>) -> Option<u32> {
|
||||||
|
let untyped = self.asset_handles_slab.get(this.rep() as _)?;
|
||||||
|
let image = untyped.as_typed::<lyra_engine::assets::Image>()?;
|
||||||
|
let image = image.data_ref()?;
|
||||||
|
Some(image.width())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_bytes(&mut self, this: WasmResource<wasm_asset::ImageHandle>) -> Option<Vec<u8>> {
|
||||||
|
let untyped = self.asset_handles_slab.get(this.rep() as _)?;
|
||||||
|
let image = untyped.as_typed::<lyra_engine::assets::Image>()?;
|
||||||
|
let image = image.data_ref()?;
|
||||||
|
Some(image.as_bytes().to_vec())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn drop(&mut self, this: WasmResource<wasm_asset::ImageHandle>) -> wasmtime::Result<()> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
92
src/main.rs
92
src/main.rs
|
@ -13,21 +13,24 @@ use lyra_ecs::{query::dynamic::DynamicViewOne, DynTypeId, World};
|
||||||
|
|
||||||
use lyra_ecs as ecs;
|
use lyra_ecs as ecs;
|
||||||
|
|
||||||
use ::lyra_engine::DeltaTime;
|
use lyra_engine::DeltaTime;
|
||||||
use lyra_reflect::{FromType, ReflectedResource, RegisteredType, TypeRegistry};
|
use lyra_reflect::{FromType, ReflectedResource, RegisteredType, TypeRegistry};
|
||||||
use slab::Slab;
|
use slab::Slab;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use wasmtime_wasi::{ResourceTable, WasiCtx, WasiCtxBuilder, WasiView};
|
use wasmtime_wasi::{ResourceTable, WasiCtx, WasiCtxBuilder, WasiView};
|
||||||
|
|
||||||
use wasmtime::component::Resource as WasmResource;
|
use wasmtime::component::{Resource as WasmResource, ResourceAny};
|
||||||
|
|
||||||
mod proxy;
|
mod proxy;
|
||||||
pub use proxy::*;
|
pub use proxy::*;
|
||||||
|
|
||||||
#[allow(unused_imports)]
|
mod asset;
|
||||||
|
pub use asset::*;
|
||||||
|
|
||||||
|
/* #[allow(unused_imports)]
|
||||||
pub(crate) mod lyra_engine {
|
pub(crate) mod lyra_engine {
|
||||||
pub use lyra_ecs as ecs;
|
pub use lyra_ecs as ecs;
|
||||||
}
|
} */
|
||||||
|
|
||||||
wasmtime::component::bindgen!({
|
wasmtime::component::bindgen!({
|
||||||
world: "example",
|
world: "example",
|
||||||
|
@ -84,12 +87,14 @@ struct DynamicViewEntry {
|
||||||
|
|
||||||
unsafe impl Send for DynamicViewEntry {}
|
unsafe impl Send for DynamicViewEntry {}
|
||||||
|
|
||||||
struct Imports {
|
pub(crate) struct Imports {
|
||||||
world_slab: Slab<WorldEntry>,
|
pub(crate) world_slab: Slab<WorldEntry>,
|
||||||
world_views_slab: Slab<DynamicViewEntry>,
|
pub(crate) world_views_slab: Slab<DynamicViewEntry>,
|
||||||
|
pub(crate) asset_manager_slab: Slab<lyra_ecs::ResourceData>,
|
||||||
|
pub(crate) asset_handles_slab: Slab<lyra_engine::assets::UntypedResHandle>,
|
||||||
|
|
||||||
ctx: WasiCtx,
|
pub(crate) ctx: WasiCtx,
|
||||||
table: ResourceTable,
|
pub(crate) table: ResourceTable,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WasiView for Imports {
|
impl WasiView for Imports {
|
||||||
|
@ -251,21 +256,30 @@ impl wasm_ecs::HostEcsWorld for Imports {
|
||||||
async fn get_resource(&mut self, this: wasmtime::component::Resource<wasm_ecs::EcsWorld>, type_id: wasm_ecs::WasmTypeId) -> wasm_ecs::WorldResourceResult {
|
async fn get_resource(&mut self, this: wasmtime::component::Resource<wasm_ecs::EcsWorld>, type_id: wasm_ecs::WasmTypeId) -> wasm_ecs::WorldResourceResult {
|
||||||
let world_entry = self
|
let world_entry = self
|
||||||
.world_slab
|
.world_slab
|
||||||
.try_remove(this.rep() as _)
|
.get(this.rep() as _)
|
||||||
.ok_or(WasmError::InvalidResourceHandle("EcsWorld")).unwrap();
|
.ok_or(WasmError::InvalidResourceHandle("EcsWorld")).unwrap();
|
||||||
let world = &world_entry.world;
|
let world = &world_entry.world;
|
||||||
|
|
||||||
let native_type = world.get_resource::<GuestTypeLookup>().unwrap();
|
let native_tid = {
|
||||||
let native_tid = native_type.lookup_type_id(type_id)
|
let native_type = world.get_resource::<GuestTypeLookup>().unwrap();
|
||||||
.expect("failed to find native type id of wasm type");
|
native_type.lookup_type_id(type_id)
|
||||||
|
.expect("failed to find native type id of wasm type")
|
||||||
|
};
|
||||||
|
|
||||||
let reg = world.get_resource::<TypeRegistry>().unwrap();
|
let data = {
|
||||||
let data = reg.get_type(native_tid).unwrap();
|
let reg = world.get_resource::<TypeRegistry>().unwrap();
|
||||||
let proxy = data.get_data::<WasmProxied>().unwrap();
|
reg.get_type(native_tid).unwrap().clone()
|
||||||
|
};
|
||||||
let refl = data.get_data::<ReflectedResource>().unwrap();
|
|
||||||
|
let proxy = data.get_data::<WasmProxied>().unwrap().clone();
|
||||||
|
let refl = data.get_data::<ReflectedResource>().unwrap().clone();
|
||||||
|
|
||||||
|
// SAFETY: reflecting the resource borrows from a different part of the world
|
||||||
|
// then marshaling would.
|
||||||
|
let w = NonNull::from(world);
|
||||||
|
let world = unsafe { w.as_ref() };
|
||||||
let refl = refl.reflect(world).unwrap();
|
let refl = refl.reflect(world).unwrap();
|
||||||
let res = proxy.marshal_to_bytes(refl.deref());
|
let res = proxy.marshal_to_bytes(self, refl.deref());
|
||||||
|
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
@ -439,12 +453,8 @@ async fn main() -> wasmtime::Result<()> {
|
||||||
// Configure the linker
|
// Configure the linker
|
||||||
let mut linker = wasmtime::component::Linker::new(&engine);
|
let mut linker = wasmtime::component::Linker::new(&engine);
|
||||||
|
|
||||||
//wasmtime_wasi::preview0::add_to_linker_sync(&mut linker, |s| s)?;
|
|
||||||
//wasmtime_wasi::bindings::Imports::add_to_linker(&mut linker, |s| s)?;
|
|
||||||
wasmtime_wasi::add_to_linker_async(&mut linker)?;
|
wasmtime_wasi::add_to_linker_async(&mut linker)?;
|
||||||
Example::add_to_linker(&mut linker, |s| s)?;
|
Example::add_to_linker(&mut linker, |s| s)?;
|
||||||
//lyra::api::ecs::add_to_linker(&mut linker, |s| s)?;
|
|
||||||
//Api::add_to_linker(&mut linker, |s| s)?;
|
|
||||||
|
|
||||||
let mut builder = WasiCtxBuilder::new();
|
let mut builder = WasiCtxBuilder::new();
|
||||||
builder.inherit_stdio();
|
builder.inherit_stdio();
|
||||||
|
@ -456,6 +466,8 @@ async fn main() -> wasmtime::Result<()> {
|
||||||
// wants another world for some reason.
|
// wants another world for some reason.
|
||||||
world_slab: Slab::with_capacity(1),
|
world_slab: Slab::with_capacity(1),
|
||||||
world_views_slab: Slab::with_capacity(10),
|
world_views_slab: Slab::with_capacity(10),
|
||||||
|
asset_manager_slab: Slab::with_capacity(1),
|
||||||
|
asset_handles_slab: Slab::with_capacity(25),
|
||||||
ctx: builder.build(),
|
ctx: builder.build(),
|
||||||
table: ResourceTable::new(),
|
table: ResourceTable::new(),
|
||||||
},
|
},
|
||||||
|
@ -470,10 +482,12 @@ async fn main() -> wasmtime::Result<()> {
|
||||||
let mut world = World::new();
|
let mut world = World::new();
|
||||||
|
|
||||||
world.add_resource(DeltaTime::from(100.00));
|
world.add_resource(DeltaTime::from(100.00));
|
||||||
|
world.add_resource(lyra_engine::assets::ResourceManager::default());
|
||||||
|
|
||||||
let mut lookup = GuestTypeLookup::default();
|
let mut lookup = GuestTypeLookup::default();
|
||||||
lookup.infos.insert(4124409524, lyra_ecs::ComponentInfo::new::<Vec3>());
|
lookup.infos.insert(4124409524, lyra_ecs::ComponentInfo::new::<Vec3>());
|
||||||
lookup.type_ids.insert(83716348954, TypeId::of::<::lyra_engine::DeltaTime>());
|
lookup.type_ids.insert(83716348954, TypeId::of::<lyra_engine::DeltaTime>());
|
||||||
|
lookup.type_ids.insert(567234789345, TypeId::of::<lyra_engine::assets::ResourceManager>());
|
||||||
world.add_resource(lookup);
|
world.add_resource(lookup);
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -506,36 +520,6 @@ async fn main() -> wasmtime::Result<()> {
|
||||||
call_script_stage_async(&mut store, &instance, "init", world_res_a, script_en.into()).await?;
|
call_script_stage_async(&mut store, &instance, "init", world_res_a, script_en.into()).await?;
|
||||||
//call_script_stage_async(&mut store, &instance, "update", world_res_b, script_en.into()).await?;
|
//call_script_stage_async(&mut store, &instance, "update", world_res_b, script_en.into()).await?;
|
||||||
println!("RUST: Guest is done");
|
println!("RUST: Guest is done");
|
||||||
|
|
||||||
let rep = world_res_b.rep();
|
|
||||||
if let Some(w) = store.data().world_slab.get(rep as _) {
|
|
||||||
let w = &w.world;
|
|
||||||
println!("RUST: Got {} archetypes", w.archetype_count());
|
|
||||||
for a in w.archetypes.values() {
|
|
||||||
println!("RUST: Archetype {}", a.id().0);
|
|
||||||
for col in &a.columns {
|
|
||||||
println!("RUST: Column type id: {:?}", col.info.type_id());
|
|
||||||
|
|
||||||
if col.info.type_id().is_id(DynTypeId::Unknown(4124409524)) {
|
|
||||||
println!("RUST: Found C# Vec3");
|
|
||||||
let pos = unsafe { col.get::<Vec3>(0) };
|
|
||||||
println!("RUST: Entity 0 pos: {:?}", *pos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut dv = w.dynamic_view();
|
|
||||||
dv.push(QueryDynamicType::from_info(lyra_ecs::ComponentInfo::new::<Vec3>()));
|
|
||||||
let iter = dv.into_iter();
|
|
||||||
|
|
||||||
for (_, comps) in iter {
|
|
||||||
let first = comps.first().unwrap();
|
|
||||||
unsafe {
|
|
||||||
let v: Vec3 = std::ptr::read(first.ptr.as_ptr() as _);
|
|
||||||
println!("RUST: Found native Vec3! {:?}", v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
25
src/proxy.rs
25
src/proxy.rs
|
@ -1,20 +1,20 @@
|
||||||
use crate::lyra::api::ecs as wasm_ecs;
|
use crate::{lyra::api::ecs as wasm_ecs, Imports};
|
||||||
use common_api::bytemuck;
|
use common_api::bytemuck;
|
||||||
use lyra_engine::DeltaTime;
|
use lyra_engine::DeltaTime;
|
||||||
use lyra_reflect::{FromType, Reflect};
|
use lyra_reflect::{FromType, Reflect};
|
||||||
|
|
||||||
pub trait WasmProxy {
|
pub trait WasmProxy {
|
||||||
fn marshal_to_bytes(&self) -> wasm_ecs::WorldResourceResult;
|
fn marshal_to_bytes(&self, imports: &mut Imports) -> wasm_ecs::WorldResourceResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct WasmProxied {
|
pub struct WasmProxied {
|
||||||
fn_marshal: for<'a> fn (&'a dyn Reflect) -> wasm_ecs::WorldResourceResult,
|
fn_marshal: for<'a> fn (&mut Imports, &'a dyn Reflect) -> wasm_ecs::WorldResourceResult,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WasmProxied {
|
impl WasmProxied {
|
||||||
pub fn marshal_to_bytes(&self, reflected: &dyn Reflect) -> wasm_ecs::WorldResourceResult {
|
pub fn marshal_to_bytes(&self, imports: &mut Imports, reflected: &dyn Reflect) -> wasm_ecs::WorldResourceResult {
|
||||||
(self.fn_marshal)(reflected)
|
(self.fn_marshal)(imports, reflected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,16 +24,25 @@ where
|
||||||
{
|
{
|
||||||
fn from_type() -> Self {
|
fn from_type() -> Self {
|
||||||
WasmProxied {
|
WasmProxied {
|
||||||
fn_marshal: |reflect| {
|
fn_marshal: |imports, reflect| {
|
||||||
let this: &T = reflect.as_any().downcast_ref().unwrap();
|
let this: &T = reflect.as_any().downcast_ref().unwrap();
|
||||||
this.marshal_to_bytes()
|
this.marshal_to_bytes(imports)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WasmProxy for DeltaTime {
|
impl WasmProxy for DeltaTime {
|
||||||
fn marshal_to_bytes(&self) -> wasm_ecs::WorldResourceResult {
|
fn marshal_to_bytes(&self, _: &mut Imports) -> wasm_ecs::WorldResourceResult {
|
||||||
wasm_ecs::WorldResourceResult::Bytes(bytemuck::bytes_of(&**self).to_vec())
|
wasm_ecs::WorldResourceResult::Bytes(bytemuck::bytes_of(&**self).to_vec())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WasmProxy for lyra_engine::assets::ResourceManager {
|
||||||
|
fn marshal_to_bytes(&self, imports: &mut Imports) -> wasm_ecs::WorldResourceResult {
|
||||||
|
//imports.
|
||||||
|
|
||||||
|
todo!()
|
||||||
|
//imports.asset_manager_slab.insert(val)
|
||||||
|
}
|
||||||
}
|
}
|
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
Loading…
Reference in New Issue