Jump to content

LoadMap bug when shared_ptr in entitys are set as variables


Andy90
 Share

Go to solution Solved by Josh,

Recommended Posts

 

Hello, the following error occurs when loading the map: Enitiys with components containing shared_ptr are also loaded in the new map. I noticed this with my animator component. However, when creating the demo project I noticed that the door is also included in the new scene. 

However, I also have components in my other project where I set shared_ptr as variables and which do not cause a problem. Could it be related to the flowgraph parameters? As this is my only component where I use it.

https://streamable.com/a0g6p4


You can reproduce the error (at least for the animatior) if you commend like this
 

bool Animator::Load(table& properties, shared_ptr<Stream> binstream, shared_ptr<Map> scene, const LoadFlags flags)
{
    //this->model = this->GetEntity()->As<Model>();
    this->animationName = properties["animationName"];
    this->animationSpeed = properties["animationSpeed"];
    this->loop = properties["loop"];
    this->bleed = properties["bleed"];
    this->autoplay = properties["autoplay"];
    return true;
}

the door is still geting transfered within the new map.
 

Demo Project: AnimatorBug.zip

Link to comment
Share on other sites

Nothing is being loaded in a new scene, it's just failing to be deleted.

Probably a circular reference is being created by the engine in the component system, where the entity and component reference each other and keep each other in memory.

This is all C++, right?

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

I am testing with a simple map. The mover component does not seem to have any problem, but the door component does, so that make me think this is an issue with joints creating a circular reference.

start.zip

#include "UltraEngine.h"
#include "ComponentSystem.h"

using namespace UltraEngine;

void main(const char* args, const int argc)
{
    RegisterComponents();

    //Get the displays
    auto displays = GetDisplays();

    //Create a window
    auto window = CreateWindow("Ultra Engine", 0, 0, 1280 * displays[0]->scale, 720 * displays[0]->scale, displays[0], WINDOW_TITLEBAR | WINDOW_CENTER);

    //Create a framebuffer
    auto framebuffer = CreateFramebuffer(window);

    //Create a world
    auto world = CreateWorld();

    auto camera = CreateCamera(world);
    camera->Move(0, 0, -3);
    camera->SetClearColor(0.125f);

    auto scene = LoadMap(world, "Maps/start.ultra");
    Assert(not scene->entities[0]->components.empty());

    //Main loop
    while (!window->Closed() and !window->KeyHit(KEY_ESCAPE))
    {
        if (window->KeyHit(KEY_SPACE))
        {
            scene = nullptr;
        }

        //Update world
        world->Update();

        //Render world
        world->Render(framebuffer, true);
    }
}

 

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

I can confirm joints do hold the entity in memory. With a component design, I am not sure how to approach this, since the component needs to keep the joint in memory as well.

#include "UltraEngine.h"
#include "ComponentSystem.h"

using namespace UltraEngine;

void main(const char* args, const int argc)
{
    RegisterComponents();

    //Get the displays
    auto displays = GetDisplays();

    //Create a window
    auto window = CreateWindow("Ultra Engine", 0, 0, 1280 * displays[0]->scale, 720 * displays[0]->scale, displays[0], WINDOW_TITLEBAR | WINDOW_CENTER);

    //Create a framebuffer
    auto framebuffer = CreateFramebuffer(window);

    //Create a world
    auto world = CreateWorld();

    auto camera = CreateCamera(world);
    camera->Move(0, 0, -3);
    camera->SetClearColor(0.125f);

    auto box = CreateBox(world);
    box->SetMass(10);
    auto joint = CreateHingeJoint(Vec3(0), Vec3(0, 0, 1), nullptr, box);
    //joint = nullptr;

    box->AddTorque(0, 0, 1000);

    //Main loop
    while (!window->Closed() and !window->KeyHit(KEY_ESCAPE))
    {
        if (window->KeyHit(KEY_SPACE))
        {
            //joint = nullptr;
            box = nullptr;
        }

        //Update world
        world->Update();

        //Render world
        world->Render(framebuffer, true);
    }
}

 

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

I might have some further info for you Josh.  Create a new C++ project, load up the project in visual studio.  Make this your loop:

//Main loop
while (window->Closed() == false and window->KeyDown(KEY_ESCAPE) == false)
{
  if (window->KeyHit(KEY_SPACE)) {
    Print("------DELETING MAP------");
    scene = nullptr;
  }

    world->Update();
    world->Render(framebuffer);

#ifdef STEAM_API_H
    Steamworks::Update();
#endif

}

You will see in the output that it says all the material, textures and models are being deleted but nothing actually disappears from the scene.  I think this is because the camera is being deleted with the map.  Hope this helps.  Maybe an error should be thrown if we try to render the world and there is no camera present?

Link to comment
Share on other sites

@Andy90 I believe I got your original upload to work as you expect it too.

 if (g_window->KeyHit(KEY_ENTER)) {
     if (g_scene != nullptr) {
         g_scene = nullptr;
     }
     else{
         g_scene = LoadMap(g_world, "Maps/TestScene.ultra");
     }
 }

 //if (g_scene != NULL) {
     g_itemMover.Update(g_window);
     g_playerInventory->Update(g_window);
     g_world->Update();
     g_world->Render(framebuffer);
//}

It seems that setting the scene to nullptr will delete everything but your check to not update and render the world if it was nullptr meant that would never work.  By removing that check and giving it a chance to delete on the first enter press I got it to work.  However, the second issue I saw was the crash to RecordDraw and the framebuffer wasn't actually being cleared.  This was because by deleting the map there was no longer any 3D camera available.

By adding this line after creating the framebuffer, the above code worked.

auto g_camera = CreateCamera(g_world);

The second map also loaded okay and the player could harvest from the rock.  I also got the error with the AnimationBone or something.  I think that was a combination of the lack of 3D camera and not letting the first map actually clear before loading the next one.

I hope this actually helps and I have not completely barked up the wrong tree. :)

Link to comment
Share on other sites

@Andy90 As you posted on Discord, I downloaded your recent project from here.  The problems that I can see are a little different because you've got your teleport function as a component that I'm pretty sure is being deleted when you erase your map so it's causing the issue.  My only advice is put your teleport code somewhere within main.cpp so that it can handle the map changes on the highest level - so that it is not part of the maps your erasing.

You still need to solve the camera issue by making sure a camera is always available to render too.  These are the only issues that I can see, by fixing it this way I managed to get your game working without crashes.  I think the current errors seem random because of the multithreading and sometimes it's not catching the fact there is no camera.  Welcome to multithreading. :)

Link to comment
Share on other sites

  • Solution

I have made the required change to the Joint class and it will be included in the next update. The other issues were reportedly caused by circular reference in user-created components, so I will close this issue now.

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

On 2/6/2024 at 11:55 PM, SpiderPig said:

You still need to solve the camera issue by making sure a camera is always available to render too.  These are the only issues that I can see, by fixing it this way I managed to get your game working without crashes.  I think the current errors seem random because of the multithreading and sometimes it's not catching the fact there is no camera.  Welcome to multithreading. :)

The engine is designed to protect you from any worries about multithreading if you are not using your own threads.

This seems more like it should be in the other thread, since the issue being reported here is objects not getting deleted automatically.

  • Like 1

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...