Compare commits

...

4 Commits

8 changed files with 80 additions and 59 deletions

View File

@ -26,15 +26,15 @@ public class GameObject
public Transform Transform { get; } public Transform Transform { get; }
public GameObject? Parent; public GameObject? Parent;
public Dictionary<Type, Component> Components = new(); public Dictionary<Type, Component> Components;
private GameObject(ulong id, uint nativePoolIndex) private GameObject(ulong id, uint nativePoolIndex)
{ {
_id = id; _id = id;
_index = nativePoolIndex; _index = nativePoolIndex;
// constructor doesn't work without writing to console // Do not move this line or mono runtime will throw SEGFAULT.
// TODO: FIX THIS BULLSHIT // Mono runtime can't set values in field declaration, but initializing everything in constructor is OK.
Console.WriteLine($"GameObject(id: {id}, nativePoolIndex: {nativePoolIndex})"); Components = new();
} }
static public GameObject Create() static public GameObject Create()

View File

@ -7,23 +7,23 @@ std::ostream& operator<<(std::ostream& s, Transform& t){
return s; return s;
} }
GameObject::GameObject(Mono::Object managed_obj, GameObject *parent) GameObject::GameObject(Mono::Object managed_obj)
: object_handle(managed_obj), parent(parent) : object_handle(managed_obj)
{} {}
GameObject::GameObject(GameObject &&o) : GameObject::GameObject(GameObject &&o) :
transform(o.transform),
components(std::move(o.components)),
object_handle(std::move(o.object_handle)), object_handle(std::move(o.object_handle)),
parent(o.parent) parent(o.parent),
transform(o.transform),
components(std::move(o.components))
{ {
} }
GameObject& GameObject::operator=(GameObject &&o){ GameObject& GameObject::operator=(GameObject &&o){
transform = o.transform;
components = std::move(o.components);
object_handle = std::move(o.object_handle); object_handle = std::move(o.object_handle);
parent = o.parent; parent = o.parent;
transform = o.transform;
components = std::move(o.components);
return *this; return *this;
} }

View File

@ -26,12 +26,17 @@ std::ostream& operator<<(std::ostream& s, Transform& t);
class GameObject { class GameObject {
Transform transform;
std::map<std::u16string, Component> components;
Mono::ObjectHandle object_handle; Mono::ObjectHandle object_handle;
GameObject* parent; GameObject* parent;
Transform transform;
std::map<std::u16string, Component> components;
public: public:
GameObject(Mono::Object managed_obj, GameObject* parent); /// @warning Do not use this to create objects.
/// This constructor creates null values for GameObject arrays
/// GameObject* array = new GameObject[10];
/// array[0] = GameObject(initialized_mono_object_ptr)
GameObject() = default;
GameObject(Mono::Object managed_obj);
GameObject(const GameObject& o) = delete; GameObject(const GameObject& o) = delete;
GameObject(GameObject&& o); GameObject(GameObject&& o);

View File

@ -7,7 +7,7 @@ GameObjectPool::GameObjectPool(u32 size)
useful_assert(size % 64 == 0, "size of GameObjectPool must be a multiple of 64"); useful_assert(size % 64 == 0, "size of GameObjectPool must be a multiple of 64");
this->size = size; this->size = size;
first_unused_index = 0; first_unused_index = 0;
buffer = new char[size*sizeof(GameObject)]; buffer = new GameObject[size];
used_indices = new u64[size/64]; used_indices = new u64[size/64];
// std::memset(buffer, 0, size*sizeof(GameObject)); // std::memset(buffer, 0, size*sizeof(GameObject));
std::memset(used_indices, 0, size/8); std::memset(used_indices, 0, size/8);
@ -15,13 +15,8 @@ GameObjectPool::GameObjectPool(u32 size)
GameObjectPool::~GameObjectPool() GameObjectPool::~GameObjectPool()
{ {
// int i = 0; delete[] buffer;
for(auto&& p : *this){ delete[] used_indices;
// std::cout<<"~GameObjectPool i="<<i++<<std::endl;
p.second.~GameObject();
}
delete (char*)buffer;
delete used_indices;
} }
bool GameObjectPool::isIndexUsed(u32 index) bool GameObjectPool::isIndexUsed(u32 index)
@ -81,7 +76,7 @@ GameObject& GameObjectPool::get(u32 index)
throw UsefulException(format("index %i is out of size %i", index, size)); throw UsefulException(format("index %i is out of size %i", index, size));
if(!isIndexUsed(index)) if(!isIndexUsed(index))
throw UsefulException(format("there is no object at index %i", index)); throw UsefulException(format("there is no object at index %i", index));
return ((GameObject*)buffer)[index]; return buffer[index];
} }
std::pair<u32, GameObject&> GameObjectPool::emplace(GameObject&& new_obj) std::pair<u32, GameObject&> GameObjectPool::emplace(GameObject&& new_obj)
@ -89,7 +84,9 @@ std::pair<u32, GameObject&> GameObjectPool::emplace(GameObject&& new_obj)
u32 i = first_unused_index; u32 i = first_unused_index;
if(i == u32(-1)) if(i == u32(-1))
throw UsefulException("can't put new GameObject to GameObjectPool because it's full"); throw UsefulException("can't put new GameObject to GameObjectPool because it's full");
GameObject& r = ( ((GameObject*)buffer)[i] = std::move(new_obj) );
buffer[i] = std::move(new_obj);
GameObject& r = buffer[i];
used_indices[i/64] |= u64(1)<<(i%64); // mark index bit as used used_indices[i/64] |= u64(1)<<(i%64); // mark index bit as used
first_unused_index = getNearestUnusedIndex(i+1); first_unused_index = getNearestUnusedIndex(i+1);
return std::pair<u32, GameObject&>(i, r); return std::pair<u32, GameObject&>(i, r);
@ -101,27 +98,29 @@ void GameObjectPool::erase(u32 index)
throw UsefulException(format("index %i is out of size %i", index, size)); throw UsefulException(format("index %i is out of size %i", index, size));
if(!isIndexUsed(index)) if(!isIndexUsed(index))
throw UsefulException(format("there is no object at index %i", index)); throw UsefulException(format("there is no object at index %i", index));
((GameObject*)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;
} }
GameObjectPool::iterator::iterator(GameObjectPool* p, u32 index) GameObjectPool::iterator::iterator(GameObjectPool* pool, u32 index)
: p(p), index(index) : pool(pool), index(index)
{ {
} }
std::pair<u32, GameObject&> GameObjectPool::iterator::operator*() std::pair<u32, GameObject&> GameObjectPool::iterator::operator*()
{ {
if(index >= p->size) if(index >= pool->size)
throw UsefulException("can't get value of end() iterator"); throw UsefulException("can't get value of end() iterator");
GameObject& r = ((GameObject*)p->buffer)[index];
GameObject& r = pool->buffer[index];
return std::pair<u32, GameObject&>(index, r); return std::pair<u32, GameObject&>(index, r);
} }
GameObjectPool::iterator& GameObjectPool::iterator::operator++() GameObjectPool::iterator& GameObjectPool::iterator::operator++()
{ {
index = p->getNearestUsedIndex(index+1); index = pool->getNearestUsedIndex(index+1);
return *this; return *this;
} }

View File

@ -28,7 +28,7 @@ operation 'forward_list::iterate' took 2.0823 ms
*/ */
class GameObjectPool { class GameObjectPool {
void* buffer; GameObject* buffer;
u64* used_indices; u64* used_indices;
u32 size; u32 size;
u32 first_unused_index; u32 first_unused_index;
@ -45,17 +45,19 @@ public:
std::pair<u32, GameObject&> emplace(GameObject&& new_obj); std::pair<u32, GameObject&> emplace(GameObject&& new_obj);
void erase(u32 index); void erase(u32 index);
#pragma region iterator class
class iterator { class iterator {
GameObjectPool* p; GameObjectPool* pool;
u32 index = 0; u32 index = 0;
public: public:
iterator(GameObjectPool* p, u32 index); iterator(GameObjectPool* pool, u32 index);
std::pair<u32, GameObject&> operator*(); std::pair<u32, GameObject&> operator*();
iterator& operator++(); iterator& operator++();
inline bool operator!=(const iterator& o) const { return index != o.index; }; inline bool operator!=(const iterator& o) const { return index != o.index; };
inline bool operator==(const iterator& o) const { return index == o.index; }; inline bool operator==(const iterator& o) const { return index == o.index; };
}; };
#pragma endregion
inline iterator begin() { return iterator(this, 0); } inline iterator begin() { return iterator(this, 0); }
inline iterator end() { return iterator(this, -1); } inline iterator end() { return iterator(this, -1); }

View File

@ -24,6 +24,8 @@ typedef f64 Double;
typedef union { mono_bool wide_bool; } Bool; //USAGE: Bool t = {true}; typedef union { mono_bool wide_bool; } Bool; //USAGE: Bool t = {true};
typedef char16_t Char; typedef char16_t Char;
typedef MonoString* String; typedef MonoString* String;
/// @warning MonoObject can be moved in memory by GC in any time and raw pointer will be invalid.
/// Use ObjectHandle where it is possible.
typedef MonoObject* Object; typedef MonoObject* Object;
typedef void Void; typedef void Void;
@ -133,25 +135,39 @@ public:
std::shared_ptr<Assembly> loadAssembly(const std::string& name); std::shared_ptr<Assembly> loadAssembly(const std::string& name);
}; };
class ObjectHandle { /// @brief ObjectHandle can be used to store reliable reference to MonoObject.
Object object; /// MonoObject can be moved in memory by GC in any time and raw pointer will be invalid.
struct ObjectHandle {
u32 gc_handle; u32 gc_handle;
public:
inline ObjectHandle() : object(nullptr), gc_handle(0) {} inline ObjectHandle() : gc_handle(0) {}
inline ObjectHandle(Object obj) : object(obj) { gc_handle = mono_gchandle_new(obj, false); }
inline ObjectHandle(Object obj) {
gc_handle = mono_gchandle_new(obj, false);
}
/// implicitly create new ObjectHandle instead
inline ObjectHandle(const ObjectHandle& o) = delete; inline ObjectHandle(const ObjectHandle& o) = delete;
inline ObjectHandle(ObjectHandle&& o)
: object(o.object), gc_handle(o.gc_handle) inline ObjectHandle(ObjectHandle&& o) {
{ o.gc_handle = 0; }; gc_handle = o.gc_handle;
o.gc_handle = 0;
}
inline ObjectHandle& operator=(ObjectHandle&& o) { inline ObjectHandle& operator=(ObjectHandle&& o) {
object = o.object;
gc_handle = o.gc_handle; gc_handle = o.gc_handle;
o.gc_handle = 0; o.gc_handle = 0;
return *this; return *this;
}; }
inline ~ObjectHandle() { if(gc_handle) mono_gchandle_free(gc_handle); }
inline Object getObject() const { return object; } inline ~ObjectHandle() {
inline u32 getGCHandle() const { return gc_handle; } if(gc_handle)
mono_gchandle_free(gc_handle);
}
inline Object getObject() const {
return mono_gchandle_get_target(gc_handle);
}
}; };
} }

View File

@ -11,7 +11,7 @@
using namespace ougge; using namespace ougge;
#define GAMEOBJECTPOOL_SIZE 64*1024 #define GAMEOBJECTPOOL_SIZE 64
#define optime(N, LABEL, CODE) {\ #define optime(N, LABEL, CODE) {\
nsec_t b = getMonotonicTimeNsec();\ nsec_t b = getMonotonicTimeNsec();\
@ -43,21 +43,20 @@ int main(int argc, const char** argv){
auto a = mono.loadAssembly("Ougge.dll"); auto a = mono.loadAssembly("Ougge.dll");
MonoClass* gameObjectClass = a->getClass("Ougge", "GameObject"); MonoClass* gameObjectClass = a->getClass("Ougge", "GameObject");
MonoObject* exampleObjectManaged = mono_object_new(mono.getDomain(), gameObjectClass);
u64 obj_id = 0; u64 obj_id = 0;
auto pair = p.emplace(GameObject(exampleObjectManaged, nullptr)); auto pair = p.emplace(GameObject(mono_object_new(mono.getDomain(), gameObjectClass)));
Mono::ObjectHandle& exampleObjectHandle = pair.second.getObjectHandle();
auto gameObjectCtor = Mono::Method<void(u64, u32)>(gameObjectClass, ".ctor"); auto gameObjectCtor = Mono::Method<void(u64, u32)>(gameObjectClass, ".ctor");
gameObjectCtor(exampleObjectManaged, obj_id++, pair.first); gameObjectCtor(exampleObjectHandle.getObject(), obj_id++, pair.first);
auto exampleObjectUpdate = Mono::Method<void(f64)>(gameObjectClass, "InvokeUpdate"); auto exampleObjectUpdate = Mono::Method<void(f64)>(gameObjectClass, "InvokeUpdate");
updateCallbacks.push_back([exampleObjectManaged, exampleObjectUpdate](f64 deltaTime) -> void { updateCallbacks.push_back([&exampleObjectHandle, exampleObjectUpdate](f64 deltaTime) -> void {
exampleObjectUpdate(exampleObjectManaged, deltaTime); exampleObjectUpdate(exampleObjectHandle.getObject(), deltaTime);
}); });
auto tryCreateComponent = Mono::Method<Mono::Bool(Mono::String)>(gameObjectClass, "TryCreateComponent_internal"); auto tryCreateComponent = Mono::Method<Mono::Bool(Mono::String)>(gameObjectClass, "TryCreateComponent_internal");
Mono::String componentNameManaged = mono_string_new(mono.getDomain(), "Ougge.ExampleComponent"); Mono::String componentNameManaged = mono_string_new(mono.getDomain(), "Ougge.ExampleComponent");
// Mono::ObjectHandle componentNameObjectHandle((MonoObject*)(void*)componentNameManaged); Mono::Bool created = tryCreateComponent(exampleObjectHandle.getObject(), componentNameManaged);
Mono::Bool created = tryCreateComponent(exampleObjectManaged, componentNameManaged);
if(!created.wide_bool) if(!created.wide_bool)
throw UsefulException("couldn't create ExampleComponent"); throw UsefulException("couldn't create ExampleComponent");

View File

@ -33,10 +33,10 @@ case "$OS" in
mv -v "$l" "dependencies/precompiled/mono-libs/$soname_without_version" mv -v "$l" "dependencies/precompiled/mono-libs/$soname_without_version"
done done
myprint "${BLUE}stripping debug symbols from mono shared libraries" # myprint "${BLUE}stripping debug symbols from mono shared libraries"
for l in $(find "dependencies/precompiled/mono-libs" -name '*.so') ; do # for l in $(find "dependencies/precompiled/mono-libs" -name '*.so') ; do
strip -g "$l" # strip -g "$l"
done # done
# copy mono c# libraries # copy mono c# libraries
managed_libraries="mscorlib.dll" managed_libraries="mscorlib.dll"