Compare commits

..

3 Commits

Author SHA1 Message Date
7e7454278d cimgui update 2026-01-09 12:12:45 +05:00
346779060e something something 2026-01-09 11:57:24 +05:00
175fe61e5c implemented functions from NativeFunctions.cs 2025-07-05 03:22:48 +03:00
11 changed files with 91 additions and 31 deletions

View File

@@ -14,6 +14,14 @@ public class ExampleComponent : Component
Console.WriteLine($"C# deltaTime {deltaTime} object id {Owner.Id}"); Console.WriteLine($"C# deltaTime {deltaTime} object id {Owner.Id}");
ImGui.Begin("C# WINDOW"); ImGui.Begin("C# WINDOW");
ImGui.Text("Hello from ExampleComponent!"); ImGui.Text("Hello from ExampleComponent!");
if (ImGui.Button("create GameObject"))
{
GameObject.Create();
}
if (ImGui.Button("GC Collect"))
{
GC.Collect();
}
ImGui.End(); ImGui.End();
} }
} }

View File

@@ -39,8 +39,9 @@ public class GameObject
static public GameObject Create() static public GameObject Create()
{ {
NativeMethods.createGameObject(out ulong id, out uint index); NativeFunctions.createGameObject(out ulong id, out uint index);
var o = new GameObject(id, index); var o = new GameObject(id, index);
Console.WriteLine($"C# created object with id {id}, index {index}");
return o; return o;
} }
@@ -49,23 +50,29 @@ public class GameObject
if(_isDestroyed) if(_isDestroyed)
return; return;
_isDestroyed = NativeMethods.destroyGameObject(_index); _isDestroyed = NativeFunctions.freeGameObject(_index);
if(!_isDestroyed) if(!_isDestroyed)
throw new Exception($"Can't destroy GameObject({_id})"); throw new Exception($"Can't destroy GameObject({_id})");
} }
~GameObject()
{
// destroys object native part when managed part is garbage-collected
Destroy();
}
/// <param name="t">type derived from Component</param> /// <param name="t">type derived from Component</param>
/// <returns>true if new component instance was created, false if component of the same tipe is already added to GameObject</returns> /// <returns>true if new component instance was created, false if component of the same tipe is already added to GameObject</returns>
/// <exception cref="Exception"></exception> /// <exception cref="Exception"></exception>
public bool TryCreateComponent(Type t) public bool TryCreateComponent(Type t)
{ {
if(!t.IsSubclassOf(typeof(Component))) if (!t.IsSubclassOf(typeof(Component)))
throw new Exception($"type {t.FullName} is not a derived class of {typeof(Component).FullName}"); throw new Exception($"type {t.FullName} is not a derived class of {typeof(Component).FullName}");
if(Components.ContainsKey(t)) if (Components.ContainsKey(t))
return false; return false;
Component component = (Component?)Activator.CreateInstance(t, this) Component component = (Component?)Activator.CreateInstance(t, this)
?? throw new Exception($"can't create instance of class {t.FullName}"); ?? throw new Exception($"can't create instance of class {t.FullName}");
Components.Add(t, component); Components.Add(t, component);
return true; return true;
@@ -78,7 +85,9 @@ public class GameObject
private void InvokeUpdate(double deltaTime) private void InvokeUpdate(double deltaTime)
{ {
foreach(var p in Components) Console.WriteLine("C# InvokeUpdate");
Console.WriteLine($"id {_id}, index {_index}, destroyed {_isDestroyed}");
foreach (var p in Components)
{ {
p.Value.Update(deltaTime); p.Value.Update(deltaTime);
} }

View File

@@ -0,0 +1,12 @@
using System.Runtime.CompilerServices;
namespace Ougge;
internal static class NativeFunctions
{
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static void createGameObject(out ulong id, out uint index);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static bool freeGameObject(uint index);
}

View File

@@ -1,13 +0,0 @@
using System;
using System.Runtime.InteropServices;
namespace Ougge;
internal static class NativeMethods
{
[DllImport("__Internal")]
internal extern static bool destroyGameObject(uint index);
[DllImport("__Internal")]
internal extern static void createGameObject(out ulong id, out uint index);
}

View File

@@ -48,7 +48,7 @@ void Engine::stopLoop(){
void Engine::handleModuleError(IEngineModule& module, const char* type, const char* method, const char* error){ void Engine::handleModuleError(IEngineModule& module, const char* type, const char* method, const char* error){
std::string error_message = ougge_format( std::string error_message = ougge_format(
"Catched %s at %s.%s(): %s", "Catched %s at %s.%s(): %s",
type, module.getName(), method, error); type, module.getName().c_str(), method, error);
std::cerr<<error_message<<std::endl; std::cerr<<error_message<<std::endl;
error_messages.push_back(error_message); error_messages.push_back(error_message);
} }

View File

@@ -94,17 +94,20 @@ std::pair<u32, GameObject&> GameObjectPool::emplace(GameObject&& new_obj)
return std::pair<u32, GameObject&>(i, r); return std::pair<u32, GameObject&>(i, r);
} }
void GameObjectPool::erase(u32 index) bool GameObjectPool::erase(u32 index)
{ {
if(index >= size) if(index >= size)
throw UsefulException(ougge_format("index %i is out of size %i", index, size)); throw UsefulException(ougge_format("index %i is out of size %i", index, size));
if(!isIndexUsed(index)) if(!isIndexUsed(index)){
throw UsefulException(ougge_format("there is no object at index %i", index)); // throw UsefulException(ougge_format("there is no object at index %i", index));
return false;
}
buffer[index] = GameObject(); buffer[index] = GameObject();
used_indices[index/64] &= ~(u64(1)<<(index%64)); // mark index bit as unused used_indices[index/64] &= ~(u64(1)<<(index%64)); // mark index bit as unused
if(index < first_unused_index) if(index < first_unused_index)
first_unused_index = index; first_unused_index = index;
return true;
} }
GameObjectPool::iterator::iterator(GameObjectPool* pool, u32 index) GameObjectPool::iterator::iterator(GameObjectPool* pool, u32 index)

View File

@@ -45,7 +45,7 @@ public:
~GameObjectPool(); ~GameObjectPool();
GameObject& get(u32 index); GameObject& get(u32 index);
std::pair<u32, GameObject&> emplace(GameObject&& new_obj); std::pair<u32, GameObject&> emplace(GameObject&& new_obj);
void erase(u32 index); bool erase(u32 index);
#pragma region iterator class #pragma region iterator class
class iterator { class iterator {

View File

@@ -40,7 +40,7 @@ public:
void createExampleObject(Engine& engine){ void createExampleObject(Engine& engine){
std::cout<<"creating ExampleObject"<<std::endl; std::cout<<"creating ExampleObject"<<std::endl;
auto& monoSystem = engine.getModule<modules::MonoGameObjectSystem>(); auto& monoSystem = engine.getModule<modules::MonoGameObjectSystem>();
game::GameObject& exampleObj = monoSystem.createGameObject(); game::GameObject& exampleObj = monoSystem.createAndConstructGameObject();
std::string componentClassName = "Ougge.ExampleComponent"; std::string componentClassName = "Ougge.ExampleComponent";
if(!monoSystem.tryCreateComponent(exampleObj, componentClassName)) if(!monoSystem.tryCreateComponent(exampleObj, componentClassName))
throw UsefulException(ougge_format("couldn't create component '%s'", componentClassName.c_str())); throw UsefulException(ougge_format("couldn't create component '%s'", componentClassName.c_str()));

View File

@@ -15,18 +15,55 @@ MonoGameObjectSystem::MonoGameObjectSystem(Engine& engine, u32 max_game_objects)
gameObjectCtor = Mono::Method<void(u64, u32)>(gameObjectClass, ".ctor"); gameObjectCtor = Mono::Method<void(u64, u32)>(gameObjectClass, ".ctor");
gameObjectInvokeUpdate = Mono::Method<void(f64)>(gameObjectClass, "InvokeUpdate"); gameObjectInvokeUpdate = Mono::Method<void(f64)>(gameObjectClass, "InvokeUpdate");
gameObjectTryCreateComponent = Mono::Method<Mono::Bool(Mono::String)>(gameObjectClass, "TryCreateComponent_internal"); gameObjectTryCreateComponent = Mono::Method<Mono::Bool(Mono::String)>(gameObjectClass, "TryCreateComponent_internal");
registerNativeCallbacks();
}
// sets implementations for extern functions from src-csharp/NativeFunctions.cs
void MonoGameObjectSystem::registerNativeCallbacks(){
static MonoGameObjectSystem* this_static = this;
if(this_static != this)
throw new UsefulException("creation of more than one instance of MonoGameObjectSystem is not allowed");
auto createGameObject_callback = static_cast<void(*)(u64*, u32*)> (
[](u64* id_out, u32* index_out) -> void {
std::cout<<"createGameObject_callback"<<std::endl;
this_static->createGameObjectInPool(id_out, index_out);
}
);
mono_add_internal_call("Ougge.NativeFunctions::createGameObject", (void*)createGameObject_callback);
auto freeGameObject_callback = static_cast<bool(*)(u32)>(
[](u32 index) -> bool {
std::cout<<"freeGameObject_callback"<<std::endl;
return this_static->gameObjectPool.erase(index);
}
);
mono_add_internal_call("Ougge.NativeFunctions::freeGameObject", (void*)freeGameObject_callback);
} }
void MonoGameObjectSystem::beginFrame(){ void MonoGameObjectSystem::beginFrame(){
for(auto pair : gameObjectPool){ for(auto pair : gameObjectPool){
gameObjectInvokeUpdate(pair.second.getObjectHandle().getObject(), engine.deltaTime);
auto obj = pair.second.getObjectHandle().getObject();
std::cout<<"updating obj: "<<obj<<std::endl;
gameObjectInvokeUpdate(obj, engine.deltaTime);
} }
} }
game::GameObject& MonoGameObjectSystem::createGameObject(){ // is used in NativeFunctions.cs
game::GameObject& MonoGameObjectSystem::createGameObjectInPool(u64* id_out, u32* index_out){
auto pair = gameObjectPool.emplace(game::GameObject(mono.createObject(gameObjectClass))); auto pair = gameObjectPool.emplace(game::GameObject(mono.createObject(gameObjectClass)));
*id_out = ++obj_id;
*index_out = pair.first;
game::GameObject& obj = pair.second; game::GameObject& obj = pair.second;
gameObjectCtor(obj.getObjectHandle().getObject(), ++obj_id, pair.first); return obj;
}
game::GameObject& MonoGameObjectSystem::createAndConstructGameObject(){
u64 obj_id;
u32 obj_index;
game::GameObject& obj = createGameObjectInPool(&obj_id, &obj_index);
gameObjectCtor(obj.getObjectHandle().getObject(), obj_id, obj_index);
return obj; return obj;
} }

View File

@@ -24,8 +24,12 @@ public:
const std::string& getName() override; const std::string& getName() override;
void beginFrame() override; void beginFrame() override;
game::GameObject& createGameObject(); game::GameObject& createAndConstructGameObject();
bool tryCreateComponent(game::GameObject& obj, const std::string& componentClassName); bool tryCreateComponent(game::GameObject& obj, const std::string& componentClassName);
private:
void registerNativeCallbacks();
game::GameObject& createGameObjectInPool(u64* id_out, u32* index_out);
}; };
} }