Jump to content
  • Advertisement

noizex

GDNet+
  • Content Count

    188
  • Joined

  • Last visited

  • Days Won

    1

noizex last won the day on September 30

noizex had the most liked content!

Community Reputation

1445 Excellent

About noizex

  • Rank
    Member

Personal Information

  • Role
    Creative Director
    Producer
    Programmer
  • Interests
    Art
    Education
    Production
    Programming

Social

  • Twitter
    no1zex

Recent Profile Visitors

10963 profile views
  1. noizex

    Moving to Game Programming industry

    I was having the same thoughts, having 15+ years of professional experience but in web development & e-commerce. Always wanted to make games, and I'm pushing my hobby project forward, slowly. Every now and then I have these thoughts that I'd like to work for game industry, but then I read/hear some impressions about how it looks like, and not even counting barriers to entry (my experience will probably not mean much, which means way lower negotiating position when it comes to salary), I feel that maybe I should stay where I am So just as you, I can't afford starting from the scratch, and I have kid & family too - so I need as much time as possible for my personal life too, which doesn't seem to go along with the "working culture" in game dev. Maybe I'm wrong, but it all seems to not be up to what I'm used to in web dev - both salary and time-wise. Maybe I should just sit on the edge of this and enjoy doing my project rather than get involved into "real thing" and regret. Sorry for not helping, just wanted to share I'm in similar mood from time to time and haven't really figured it out yet
  2. noizex

    how is character creation usually done?

    I think that's how it's usually done. I managed to set this in Blender using drivers, and it kind of worked, then exported this as "shape key" data and did vertex morphing in my engine. Proof of concept worked, I think it poses a lot of challenges when it comes to armour because armour has to scale with the body properly, which I think means you have the same amount of sliders and you work with 2 extremes for armour too? For face it's probably more suitable to use bones instead of morph targets.
  3. *SOLVED* This forum becomes sometimes my rubber duck.. I don't know how I missed that... I forgot the fact that when passing reference to a method, it's addRef'd, but then release is up on the user. So it was addRefing when passing CollisionObject to RigidBody constructor... I had this in my RigidBody. And when I removed it to "not affect" the CollisionShape - I removed both - unnecessary AddRef but also Release, the one that will zero the ref count in the very end... class Rigidbody { Rigidbody(CollisionObjectProxy* collisionObject, ...) { collisionObject_ = collisionObject; collisionObject_->addRef(); // <<<<<<-------- THIS IS NOT NEEDED BECAUSE ANGELSCRIPT ALREADY ADDREF'D COLLISION OBJECT // WHEN IT WAS PASSED TO RigidBody() script constructor } ~RigidBody() { collisionObject->release(); } } and was doing this: asCHECK(engine->RegisterObjectBehaviour("RigidBody", asBEHAVE_FACTORY, "RigidBody@ f(Transform@, CollisionShape@, float)", asMETHOD(DynamicsWorld, makeRigidBody), // ^^^^^^^^^^^^^^^ addRef, but release up to user which created RigidBody(...) It's actually in documentation (https://www.angelcode.com/angelscript/sdk/docs/manual/doc_obj_handle.html) but it wasn't about constructing CollisionShape, it was about passing it to other constructor. I will try to create some refadd/release flow for AS, maybe it helps others too, as it's sometimes easy to miss when script does something for you and when it wants you to do something...
  4. I tried to make a simplified test case and it's getting weird... In the test case it does not do this additional addRef which causes the trouble: So it seems that it DOES work as expected even when using factory global function, so something must be wrong in my code that causes this addRef
  5. SOLVED BY RUBBER-DUCKING @WitchLord, one quick idea that made me wonder - the only difference is creation through global "factory function", not factory itself - isn't it like: for factory behaviour, AS does not increase refcount on top of what it does for handling of the call, because it assumes user is setting refCount to 1 when returning new object - but global function does not assume this, and it additionally increases refCount of the object returned from it? So we end up with 1 refcount from constructor and 1 refcount from Angelscript, even though we don't want it because method is acting like factory and already returned refcount 1? That's why I had idea to initially set it to 0 for creation from method and not factory behaviour, but the order in which it happens is: ++, --, ++, RETURN which meant that if we 0++, then 1-- it ends up deleting itself. I think I can't do much because once I return that object from my C++ makeBox(), it's then processed by AngelScript. Andreas, can you confirm the above behaviour for registered global function that would increase refcount when returning something declared like this? And that its indeed different than factory behaviour? asCHECK(engine->RegisterGlobalFunction("CollisionShape@ makeBox(const vec3 &in)", asMETHOD(CollisionShapeFactory, makeBox), asCALL_THISCALL_ASGLOBAL, this)); I guess it totally make sense for non-factory type of functions, especially when Foo@ is a script object (this has to happen because on script side you have no way to increase refcount), but if FooCpp@ is actually on C++ side we can do this manually when returning the object. Most of the time we also want this, but not for factory functions. How to work around it when one can have more factory methods and not necessarily just create through constructor. Here I'd actually need "CollisionShape@-" kind of thing it seems. I wanted to make it explicit by the func name what's created: makeBox, makeSphere, makeCapsule because if I did it thorugh ctor it would not be encapsulated and have to be more in way of CollisionShape(Shapes::Box, boxparam1, boxparam2) which is not really good and can cause problems if user mismatches params & type enum. So the possibility to have global factory functions not registered as behaviour would be great. Although according to the docs this should be possible: A function that creates an object and returns it to the script engine might look like this: // Registered as "obj@ CreateObject()" obj *CreateObject() { // The constructor already initializes the ref count to 1 return new obj(); } I also checked, just in case, behaviour of calling this (a bit nonsensical) code: shared class Plane: Std::TangibleObject { Plane() { CollisionShape::makePlane(vec3(0, 1, 0), 0.0f); } void cleanUp() override { TangibleObject::cleanUp(); @rigidBody = null; @collisionShape = null; @mesh = null; } CollisionShape@ collisionShape; RigidBody@ rigidBody; StaticMesh@ mesh; } and it seems to result in just single FREE, taking refCount from 1(initial, from ctor) -> 0 and removing the created object asap. This works without crashes - just not sure why it FREEs without adding ref, so it must expect the outside the be adding ref probably? It's not that clear to me how AS calls addRef/release during various situations - I will try to make some diagram once I get the hang of it, but the case with factory function is a weird one.
  6. UPDATE: SOLVED BY RUBBER-DUCKING Thanks for looking at it! The problem is, I can't see any obvious trace of it, nor I recall writing any. Searching through the code also does not show anything, especially when compared to other classes behaviour which is fine. Also - wouldn't it not show like this on the callstack where it looks like 2 refadds are initiated from within script engine, not from the outside? There should be refadd & refdel when AS is dealing with the returned object, but where does that second refadd comes from? It's also initiated within scripting. This is debugger just before the created instance is handed over to AngelScript: Here is how makeBox looks: CollisionShapeScriptProxy* CollisionShapeFactory::makeBox(const glm::vec3& halfExtents) { auto handle = store_.emplace(CollisionShape::Type::Box, std::make_unique<btBoxShape>(btVector3(halfExtents.x, halfExtents.y, halfExtents.z))); return makeCollisionShapeScriptProxy(handle); } That's makeBox - it creates an instance (store_.emplace) but this has nothing to do with scripting, it's C++ only and not refcounted. Then it passes the created instance to proxy, which does this: CollisionShapeScriptProxy* CollisionShapeFactory::makeCollisionShapeScriptProxy(CollisionShapes::Handle& handle) { return new CollisionShapeScriptProxy(store_, handle, 1); } Last parameter is initial refCount passed - I was trying to work around the problem, knowing there is one refcount too many coming from the scripting, and for this class only I tried to pass 0 (->release() would not work because it would cause object to be prematurely destroyed) but it didn't solve the issue and crashed. So that's all I have on non-Angelscript side, this call above is what is registered as asCHECK(engine->RegisterGlobalFunction("CollisionShape@ makeBox(const vec3 &in)", asMETHOD(CollisionShapeFactory, makeBox), asCALL_THISCALL_ASGLOBAL, this)); later. When CollisionShapeScriptProxy is created above, its refcount is 1 and then something happens inside the script that changes it - the code for script itself I already pasted. Just for the sake of completion this is part of the base ScriptProxy class that implements refCounting for all the classes (the ones that work and CollisionShape): ScriptProxy(SlotMap<T>& container, const typename SlotMap<T>::Handle& handle) : ScriptProxy(container, handle, 1) { } ScriptProxy(SlotMap<T>& container, const typename SlotMap<T>::Handle& handle, int16_t initialRefcount) : containerRef_(container), handle_(handle), refCount_(initialRefcount) { } void addRef() { VLOG(3) << typeid(T).name() << "[" << this << "]++ (" << refCount_ << ") -> \n" << getCallStack(2,6); refCount_++; } void release() { VLOG(3) << typeid(T).name() << "[" << this << "]-- (" << refCount_ << ") -> \n" << getCallStack(2,6); CHECK(handle_ != SlotMap<T>::NullHandle); if (--refCount_ == 0) delete this; }
  7. I managed to solve most of my problems, but encountered a new one - and since it's related to refcounting script registered OBJ_REF classes, I thought I will continue here rather than start a new topic. I've spent some hours debugging this and I have literally no idea why this happens, so hope @WitchLord or anyone knowing AS internals much better than me will be able to help. asCHECK(engine->RegisterObjectType("CollisionShape", 0, asOBJ_REF)); asCHECK(engine->RegisterObjectBehaviour("CollisionShape", asBEHAVE_ADDREF, "void f()", asMETHOD(CollisionShapeScriptProxy, addRef), asCALL_THISCALL)); asCHECK(engine->RegisterObjectBehaviour("CollisionShape", asBEHAVE_RELEASE, "void f()", asMETHOD(CollisionShapeScriptProxy, release), asCALL_THISCALL)); asCHECK(engine->SetDefaultNamespace("CollisionShape")); asCHECK(engine->RegisterGlobalFunction("CollisionShape@ makeSphere(float)", asMETHOD(CollisionShapeFactory, makeSphere), asCALL_THISCALL_ASGLOBAL, this)); asCHECK(engine->RegisterGlobalFunction("CollisionShape@ makePlane(const vec3 &in, float)", asMETHOD(CollisionShapeFactory, makePlane), asCALL_THISCALL_ASGLOBAL, this)); asCHECK(engine->RegisterGlobalFunction("CollisionShape@ makeBox(const vec3 &in)", asMETHOD(CollisionShapeFactory, makeBox), asCALL_THISCALL_ASGLOBAL, this)); asCHECK(engine->SetDefaultNamespace("")); Important note on what's different here than my other classes (which work fine!): this class has no factory registered, because I want to have several factory functions which are registered as globals to make different kinds of the same CollisionShape. Now, the class has the same mechanism of refcounting as my other component-classes (transform, animator, skeleton etc.) but only this class has weird behaviour of AddRef happening one time too many. Lifetime of this class is as follow: 1. Inside Script Object it's created via @collisionShape = CollisionShape::makeBox(...); 2. Default ref count is 1, class is created with new CollisionShapeProxy, then it's destroyed when refcount reaches 0. 3. CollisionShape is passed to RigidBody which AddRefs it during its lifetime then Releases, but the problem does not lie there, and to rule it out I stopped affecting refcount when it's passed to RigidBody for now. So all that keeps hold on that object is @collisionShape assignment shown above. 4. When I destroy the object, it cleans up doing this: @collisionShape = null; So this should effectively delete the proxy because neither RigidBody nor ScriptObject holds reference anymore... but it doesn't. All other objects behave like this but this one stays on 1 refcount for some unknown reason. I started dumping all addrefs & releases including few lines of callstack and this is what happens during its lifetime: 1 2018-10-21 21:08:59,136891 slot_map.h:88 [VERBOSE] [class CollisionShape] Creating new element @ sparseIndex 0, version: 0 2 2018-10-21 21:09:02,875345 slotmap_script_proxy.h:61 [VERBOSE] class CollisionShape[1370FB38]++ (1) -> 3 asCScriptEngine::CallObjectMethod [as_scriptengine.cpp:4069] 4 asCScriptEngine::CallObjectMethod [as_scriptengine.cpp:4013] 5 asCContext::ExecuteNext [as_context.cpp:2893] 6 asCContext::Execute [as_context.cpp:1328] 7 2018-10-21 21:09:02,875345 slotmap_script_proxy.h:67 [VERBOSE] class CollisionShape[1370FB38]-- (2) -> 8 asCScriptEngine::CallObjectMethod [as_scriptengine.cpp:4069] 9 asCScriptEngine::CallObjectMethod [as_scriptengine.cpp:4013] 10 asCContext::ExecuteNext [as_context.cpp:2815] 11 asCContext::Execute [as_context.cpp:1328] 12 2018-10-21 21:09:06,515185 slotmap_script_proxy.h:61 [VERBOSE] class CollisionShape[1370FB38]++ (1) -> 13 asCScriptEngine::CallObjectMethod [as_scriptengine.cpp:4069] 14 asCScriptEngine::CallObjectMethod [as_scriptengine.cpp:4013] 15 asCContext::ExecuteNext [as_context.cpp:4152] 16 asCContext::Execute [as_context.cpp:1328] --- here script object is destroyed, all resources released (except CollisionShape which stays alive --- 17 2018-10-21 21:09:08,394326 slotmap_script_proxy.h:67 [VERBOSE] class CollisionShape[1370FB38]-- (2) -> 18 asCScriptEngine::CallObjectMethod [as_scriptengine.cpp:4069] 19 asCScriptEngine::CallObjectMethod [as_scriptengine.cpp:4013] 20 asCContext::ExecuteNext [as_context.cpp:2888] 21 asCContext::Execute [as_context.cpp:1328] Numbers in ( ) are refCount BEFORE it's decreased or increased. So we begin with line 2, refcount (1) which is initial refcount and it's increased (2). Then it's decreased on line 7, so we're back to (1), but then again it's increased to (2) on line 12 and it stays like this. So the only thing that's referencing our CollisionShape is the script, and somehow it holds 2 references. Then at line 17 we have decref due to destruction, so it goes down to (1) and stays like this forever - it will never be cleaned up. Nothing like this happens with other classes using same base refcounted class... The only difference I see is that this class is the only one made not through factory behaviour but global function, but it has the same declaration as factory. I took screenshots of these 3 calls, inside context where it seems to be most relevant - 2 addrefs & 1 release: \ I have no idea what happens here - seems like there are two things that increase ref: asBC_REFCPY, then asBC_RefCpyV, but only one that decreases asBC_FREE. This leaves the proxy refcount at 2 (initial 1 + non-released ref during script execution). The whole thing happens during construction of script object that holds the reference, and CollisionShape@ is created inside its constructor like this: So... if anyone has any idea what's going on with this additional addRef - please halp! Sorry for that long post, but I lack the insight to follow what's going on there regarding lifetime and refcounting - I just don't know when AS increases those and when not etc. I hope that by providing that much information someone will spot the problem..
  8. noizex

    Problem with value type & opAssign

    Thanks! To be honest I'm not sure why I didn't make it asOBJ_POD - I'm pretty sure that would be the first thing to try for me.. I tried changing it and it now compiles and seems to work fine.
  9. Hi, I try to wrap my head around operator behaviour, documentation does not say much for the C++ side, so I guess it should be probably simple but I can't get this to work: # this works vec3 a(1.0f); vec3 b(0.0f); vec3 c = a - b; # this doesn't Transform@ transform = Transform(); vec3 a(1.0f); vec3 c = a - transform.position; (70): No appropriate opAssign method found in 'vec3' for value assignment (70): Previous error occurred while attempting to create a temporary copy of object Transform register: asCHECK(engine->RegisterObjectType("Transform", 0, asOBJ_REF)); asCHECK(engine->RegisterObjectBehaviour("Transform", asBEHAVE_FACTORY, "Transform@ f()", asMETHOD(SpatialWorld, makeTransform), asCALL_THISCALL_ASGLOBAL, this)); asCHECK(engine->RegisterObjectBehaviour("Transform", asBEHAVE_ADDREF, "void f()", asMETHOD(TransformScriptProxy, addRef), asCALL_THISCALL)); asCHECK(engine->RegisterObjectBehaviour("Transform", asBEHAVE_RELEASE, "void f()", asMETHOD(TransformScriptProxy, release), asCALL_THISCALL)); asCHECK(engine->RegisterObjectMethod("Transform", "vec3 get_forward() const", asMETHOD(TransformScriptProxy, getForward), asCALL_THISCALL)); asCHECK(engine->RegisterObjectMethod("Transform", "vec3 get_position() const", asMETHOD(TransformScriptProxy, getPosition), asCALL_THISCALL)); asCHECK(engine->RegisterObjectMethod("Transform", "void set_position(const vec3 &in)", asMETHOD(TransformScriptProxy, setPosition), asCALL_THISCALL)); vec3 register: // Type & behaviours asCHECK(m_engine->RegisterObjectType("vec3", sizeof(glm::vec3), asOBJ_VALUE | asGetTypeTraits<glm::vec3>())); asCHECK(m_engine->RegisterObjectBehaviour("vec3", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(vec3_ConstructorEmpty), asCALL_CDECL_OBJLAST)); asCHECK(m_engine->RegisterObjectBehaviour("vec3", asBEHAVE_CONSTRUCT, "void f(float, float, float)", asFUNCTION(vec3_Constructor), asCALL_CDECL_OBJFIRST)); asCHECK(m_engine->RegisterObjectBehaviour("vec3", asBEHAVE_CONSTRUCT, "void f(float)", asFUNCTION(vec3_ConstructorScalar), asCALL_CDECL_OBJFIRST)); asCHECK(m_engine->RegisterObjectBehaviour("vec3", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(vec3_Destructor), asCALL_CDECL_OBJFIRST)); // Properties asCHECK(m_engine->RegisterObjectProperty("vec3", "float x", asOFFSET(glm::vec3, x))); asCHECK(m_engine->RegisterObjectProperty("vec3", "float y", asOFFSET(glm::vec3, y))); asCHECK(m_engine->RegisterObjectProperty("vec3", "float z", asOFFSET(glm::vec3, z))); // Operators asCHECK(m_engine->RegisterObjectMethod("vec3", "vec3& opAddAssign(const vec3 &in) const", asMETHODPR(glm::vec3, operator+=, (const glm::vec3&), glm::vec3&), asCALL_THISCALL)); asCHECK(m_engine->RegisterObjectMethod("vec3", "vec3& opMulAssign(const vec3 &in) const", asMETHODPR(glm::vec3, operator*=, (const glm::vec3&), glm::vec3&), asCALL_THISCALL)); asCHECK(m_engine->RegisterObjectMethod("vec3", "vec3& opAssign(const vec3 &in) const", asMETHODPR(glm::vec3, operator=, (const glm::vec3&), glm::vec3&), asCALL_THISCALL)); asCHECK(m_engine->RegisterObjectMethod("vec3", "vec3 opAdd(const vec3 &in) const", asFUNCTIONPR(glm::operator+, (const glm::vec3&, const glm::vec3&), glm::vec3), asCALL_CDECL_OBJLAST)); asCHECK(m_engine->RegisterObjectMethod("vec3", "vec3 opSub(const vec3 &in) const", asFUNCTIONPR(glm::operator-, (const glm::vec3&, const glm::vec3&), glm::vec3), asCALL_CDECL_OBJLAST)); asCHECK(m_engine->RegisterObjectMethod("vec3", "vec3 opMul(const vec3 &in) const", asFUNCTIONPR(glm::operator*, (const glm::vec3&, const glm::vec3&), glm::vec3), asCALL_CDECL_OBJLAST)); asCHECK(m_engine->RegisterObjectMethod("vec3", "vec3 opMul_r(float) const", asFUNCTIONPR(glm::operator*, (float, const glm::vec3&), glm::vec3), asCALL_CDECL_OBJLAST)); asCHECK(m_engine->RegisterObjectMethod("vec3", "vec3 opDiv(const vec3 &in) const", asFUNCTIONPR(glm::operator/, (const glm::vec3&, const glm::vec3&), glm::vec3), asCALL_CDECL_OBJLAST)); // Methods asCHECK(m_engine->RegisterObjectMethod("vec3", "float length() const", asFUNCTIONPR(glm::length, (const glm::vec3&), float), asCALL_CDECL_OBJFIRST)); asCHECK(m_engine->RegisterObjectMethod("vec3", "float dot(const vec3& in) const", asFUNCTIONPR(glm::dot, (const glm::vec3&, const glm::vec3&), float), asCALL_CDECL_OBJFIRST)); asCHECK(m_engine->RegisterObjectMethod("vec3", "vec3 normalize() const", asFUNCTIONPR(glm::normalize, (const glm::vec3&), glm::vec3), asCALL_CDECL_OBJFIRST)); asCHECK(m_engine->RegisterObjectMethod("vec3", "string str()", asFUNCTIONPR(glm::to_string, (const glm::vec3&), std::string), asCALL_CDECL_OBJLAST)); Anyone knows what might be wrong here? Also if you spot some obvious inefficiencies please let me know - vec3 is small class (it's glm::vec3) that can be copied and used by value - maybe the problem is that I return a value from Transform::get_position() instead of reference? Or that I registered vec3::opAssign as returning reference, but without it I was having errors with registers and overall breakage...
  10. Hmm that sounds like a good idea! I'd have some way to identify these. One could be just having a list of the classes that are registered like this (there is limited set of those) and finding all occurences of such class in a object, then releasing it. Or more generic approach with some metainfo like [autoclean] - but first solution may be better considering there won't be a lot of these classes. Thanks, for some reason I haven't thought to use built-in script reflection for this kind of cleanup!
  11. After a bit of thinking I found some way, similar to what you mention. This will require some more care on script programmer's side. I added a "cleanup" interface which gets called when I want the object to be destroyed (both C++ & script side, but I can only guarantee C++ side goes away, and script side may be kept alive a little longer). This means I can release all references there instead of counting on destructor or scoped release. So I just do: void cleanup() { @transform = null; @mesh = null; } and because both Transform and Mesh are C++ registered classes, they're released as soon as their refcount reaches 0 and no GC is involved. This is more demanding than just relying on destructor but as you pointed out, there is no way to force destruction of object without risking dangerous side effects. So this is probably the only way I can do this, when the destruction of used resources matters (and it does, I want them gone when I say "this object is destroyed from world").
  12. Sorry, but I'm looking for an answer from someone who uses and appreciates Angelscript. Not sure how you ended up on this forum, but question about scripting language I'm using is rather weird.
  13. I already maintain 2-way slot_map to keep the objects in question (transform, mesh etc). I'd like to avoid this on script side, as each of those is already behind a proxy. My problem is proper clean-up of objects, because with Garbage Collection and deferred destruction destructors do not make sense really, as the object is already considered destroyed if unreferenced, yet it's kept alive like a real object. This is my problem - I'd like the object to go away as soon as the refcount from script/C++ side reaches 0, but I know that GC will keep one reference and then cleanup and try to resolve circular dependencies. Even if I use weak_ptr there will still be this step where GC runs, so my main question is: is there a way to make the object immediately destroyed without waiting for GC pass? My another cocnept, I think close to your 2-way check, is to implement in my proxy (do TransformProxy, MeshProxy) a way to cut the link and destroy the C++ object (so Transform, Mesh), while still being referenced in scripts due to deferred destruction. I'd then throw exception if accessing such reference where the C++ object has been destroyed, making it easier to spot obvious programming errors. But it seems like a lot of work and checking, while just destroying game object as soon as references are gone (assuming I won't ever keep reference to it outside for longer than using it when obtained from weakPtr) should work fine.
  14. Hello, I've run into weird ownership / object lifetime problem. My classes look as follow: shared abstract class Object: IScriptObjectInterface { // common "game object" functionality proxied to C++ side object } class Item: Object { Transform@ transform; Mesh@ mesh; } class Monster: Object { Transform@ transform; SkinnedMesh@ skinnedMesh; } Now, I'd like to be able to force destroy my game object. This poses several problems, one of them being - script objects are naturally reference counted, so destruction of object happens a) When no other objects reference that object b) Garbage Collector runs and destroys the object Now, composable objects like Transform, Mesh, SkinnedMesh are created on C++ side in a very optimized structure and are as much decoupled from game object as possible - to a point where game object is not needed to render Mesh instances, just mere presence in a container holding all meshes is enough. This means that object which has a reference to Mesh@ will keep that Mesh alive, and that object which I want to destroy does not have a deterministic destruction time because it may be destroyed sometime later. This means that object may be "destoyed" and unreferenced from world object list, but it will hold references to Mesh, SkinnedMesh, Physics etc. which will still exist (as they're refcounted too) meaning they'll be simulated, rendered etc. I have no idea how to solve this problem, every time I try some approach I run into some deadly reference dependency. One idea I had is to let these objects stay in the container, so Mesh will be in all_meshes on C++ side, but it will be `mesh.render = false` which can be sorted and processed probably fast enough. But ideal solution would be to be able to destroy object as soon as no references point to it without waiting for Garbage Collector run - I tried searching the docs and I see no way to make the object instantly call it's destructor once refcount reaches 1 (means GC is the only reference keeper). I don't intend on holding onto references in other objects, and if so I'll be using weak_ptr, so this means there should be no circular references and object should be safely destroyed ASAP, not sometime in the future. Any idea how to achieve this scenario and/or how to solve above problem of object lifecycle?
  15. Hello, For performance reasons, I'm using slot map container on C++ side to store instances of some particular object Foo. This means I'm not actually storing pointers to elements of that container directly because the whole access goes through special slot tables that map a key to an exact object instance - so instead of having Foo* registered for scripting as a usual refcounted reference there is one layer of indirection - I hold a "handle" that can be used to retrieve the pointer which will be valid for the time of the call. In C++ I would overload -> operator to hide this indirection, and still be able to use foo_handle->foo_method(): Foo* operator->() { return slotmap.get(handle); } How can I register such handle on Angelscript side so I don't have to proxy all the methods to the actual retrieved Foo* instance? So instead of having this: class FooScriptProxy { FooHandle h; void addRef(); // refcounting the proxy void release(); void fooMethodA() { Foo* f = slot_map.get(h); if (f) f->fooMethodA(); else ?? } void fooMethodB() { Foo* f = slot_map.get(h); if (f) f->fooMethodB(); else ?? } } I'd like to just be able to register the handle without delegating all the method calls manually while retrieving the pointer thru handle - so dynamically retrieved like through -> operator: So whenever I do something like this in script: # C++ side: class FooHandle { SlotMapKey k; Foo* retrieve() { return slotmap.get(k); // returns Foo* if exists in a map or nullptr if it wasn't found } void AddRef(); void Release(); } engine->RegisterObjectType("Foo", 0, asOBJ_REF) engine->RegisterObjectBehaviour("Foo", asBEHAVE_ADDREF, "void f()", asMETHOD(FooHandle,AddRef), asCALL_THISCALL); assert( r >= 0 ); engine->RegisterObjectBehaviour("Foo", asBEHAVE_RELEASE, "void f()", asMETHOD(FooHandle,Release), asCALL_THISCALL); assert( r >= 0 ); -> here do some magic so it registers method "retrieve" in a way similar to arrow op? # AS side: Foo @foo = createFoo(); foo.fooMethodB(); # <---- when foo.method happens, it would mean Foo* f = FooHandle::retrieve; f.method() it would actually dynamically retrieve the pointer, and then call method "fooMethodB" on it. Umm, hope it makes sense
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!