x

Search in
Sort by:

Question Status:

Search help

  • Simple searches use one or more words. Separate the words with spaces (cat dog) to search cat,dog or both. Separate the words with plus signs (cat +dog) to search for items that may contain cat but must contain dog.
  • You can further refine your search on the search results page, where you can search by keywords, author, topic. These can be combined with each other. Examples
    • cat dog --matches anything with cat,dog or both
    • cat +dog --searches for cat +dog where dog is a mandatory term
    • cat -dog -- searches for cat excluding any result containing dog
    • [cats] —will restrict your search to results with topic named "cats"
    • [cats] [dogs] —will restrict your search to results with both topics, "cats", and "dogs"

► React to Editor Destroying/Deleting an Actor

Hello,

my Actor is spawning some other actors using GetWorld()->SpawnActor. I store them inside an Array and I can already destroy all of them if needed. The problem is that it is possible to delete the main Actor using the editor without destroying the spawned ones.

So I thought that I need to override Destroy() or K2_DestroyActor() and add a call to my custom destroy function there. That does work ingame, but not in the editor.

Which function do I have to override to do that?

Thanks!

// Edit: Please ignore the explanation in this question. Look at the newer ones down there in the comments.

Product Version: Not Selected
Tags:
more ▼

asked Mar 08 '15 at 03:10 PM in Bug Reports

avatar image

holzlag0r
39 10 11 14

avatar image BigKevSexyMan Apr 21 '15 at 02:27 AM

I'm trying to do the same thing and have been running into the same issues you have.

In the meantime I'm placing all of the spawned actors to their own folder path. That way, when I want to delete the object, I just delete the main one, and then the subfolder.

 AGameBoard_Column* added = World->SpawnActor<AGameBoard_Column>(AGameBoard_Column::StaticClass());
 
 added->SetFolderPath("GameBoardColumns");
 Columns.Add(added);

SetFolderPath will automatically create the folder, so all you have to do is delete the folder every time you reset.

Not a permanent solution, but a good workaround.

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

3 answers: sort voted first

Hey holzlag0r-

Just to make sure I understand what you're trying to do, when you delete the main actor in the editor you want its destructor to delete the other actors it spawned? While it seems this is related to the other post you linked, would you be able to add a check to the spawned actors for the main actor(pseudo code):

 if(!"main Actor")
 {
 dectructor();
 }

This way each spawned actor would destroy itself if the main actor doesn't exists.

more ▼

answered Mar 12 '15 at 03:51 PM

avatar image holzlag0r Mar 12 '15 at 07:54 PM

Hello, yes, that's what I want to do. And I guess that your solution would work. However, where would I put that code? Problem is that I can't set any variables from the main actor, since I loose all references to the spawned ones upon destruction. Another way would be to let the spawned actors check themselves, however that would require some kind of tick function, which had to be called in editor mode (waste of resources).

You know, I don't really even need that functionality (although it would be nice). Don't get me wrong - I really appreciate that you want to help me doing this! However, I think that the real problem are BeginDestroy() and Destructor themselves: - TArray (and other stuff, see //Edit) getting emptied before BeginDestroy and Destructor ( I guess that shouldn't really happen, since nothing should already be destroyed on BeginDestroy - as the name suggests. Or maybe some other kind of function to intercept destruction before its happening) - Destructors & BeginDestroy() are only called once, Undoing that does not call them again. In my case that's not a huge problem, but I guess this could eventually lead to some things not getting cleaned up properly.

I don't know that much about C++, so I'm not able to read and understand every line of engine code, however I think that you are emptying TArrays before letting the Actor destroy itself when deleting it in the editor.

// Edit: Actually, this applies to any UPROPERTY. It seems like they get set to their default state. Look at my boolean example.

So here is the code now that I used to test this:

https://gist.github.com/holzlag0r/c9d1236b3dc9c88a54f1

Output:

md: DELETE

Cmd: ACTOR DELETE

LogEditorActor: Deleted Actor: BP_MyActor_C

Test:Warning: BeginDestroy @ false bTestBool

Test:Warning: BeginDestroy @ 0 comps

Test:Warning: Destructor @ false bTestBool

Test:Warning: Destructor @ 0 comps

LogEditorActor: Deleted 1 Actors (0.011 secs)

I hope that you can reproduce it like that.

avatar image Doug E ♦♦ STAFF Mar 14 '15 at 05:07 PM

Hey holzlag0r-

How do you have the Parent actor spawning the children actors in code? I'm trying to reproduce what you have and want to make sure I'm using the same process. If possible could you post the code for your main actor or walk through how it is setup.

Cheers

Doug Wilson

avatar image holzlag0r Mar 14 '15 at 09:31 PM

Hi Doug,

here is the code I'm using:

OAWorld.h

     /** World Component for the StarBox. */
     UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Components)
     TSubclassOf<class AOAWorldComponent> StarBox;
 
     /** Array that holds the currently spawned world components. */
     UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Components)
     TArray<AActor*> Comps;
 
     /** Called when the Universe should be updated. */
     UFUNCTION(BlueprintCallable, Category = Setup)
     void OnRefresh();
 
     /** Destroys all comps and clears array, returns number of destroyed comps. */
     UFUNCTION(BlueprintCallable, Category = Setup)
     void DestroyAllComps();


OAWorld.cpp

 void AOAWorld::OnRefresh()
 {
     // Delete old Components
     DestroyAllComps();
 
         // Spawn new Components
     if (StarBox)
         Comps.Add(GetWorld()->SpawnActor<AOAWorldComponent>(StarBox, GetActorLocation(), GetActorRotation()));
 }
 
 
 void AOAWorld::DestroyAllComps()
 {
     for (int i = 0; i < Comps.Num(); ++i)
     {
         if (Comps[i])
             Comps[i]->Destroy();
     }
     Comps.Empty();
 }


That's basically it. AOAWorldComponent is just a class deriven from AActor, nothing else. The spawning itself works fine and I'm able to destroy every actor by calling DestroyAllComps(). It also is (sometimes) called if the main actor is destroyed by the editor - but then the array is suddenly empty.

avatar image Doug E ♦♦ STAFF Mar 16 '15 at 04:53 PM

Hey holzlag0r-

Just so I can be sure I'm following the same setup that you're using could you also include the code for how your OAWorldComponent is spawning other actors? Also, in the editor are you creating a blueprint based on your OAWorldComponent class or are you adding an instance of the class itself to the scene?

avatar image holzlag0r Mar 16 '15 at 07:08 PM

Hello Doug, I uploaded everything related to this issue. Also, I added another Actor ("AExample") which should illustrate the other problem regarding non-reliable destructor and BeginDestroy() calls.

OAWorldComponent is not spawning other actors, it basically just is an actor, nothing else. I didn't override anything so far. If you want I can upload another example, that shows that UPROPERTYs get reset upon deleting the actor.

https://github.com/holzlag0r/Shared/blob/master/Answerhub.zip?raw=true

avatar image Doug E ♦♦ STAFF Mar 17 '15 at 07:08 PM

I apologize for my confusion, however I'm not sure I'm clear on what your question is. Your original post mentioned that you have an actor (mainActor) that is spawning other actors using GetWorld()->SpawnActor. The spawned actors are then being stored in an array (a TArray varaible of mainActor I'm guessing?) You then mentioned that you were having problems when the mainActor was destroyed while the spawned actors still exist inside the array, is that correct? If I am understanding the problem wrong please elaborate on the issue. It may also help in understanding if you have a small sample project with the bug occurring that you could upload to drop box. You can send me a private message on the forums with a link to the drop box if that works for you.

avatar image holzlag0r Mar 17 '15 at 09:51 PM

Okay, maybe my explanation was not that great, especially because I was mixing the two problems I have up.


  • Problem 1 - Serious bug from my POV **

What I was trying to do:

  • I have a main actor, which spawns many other actors. Pointers to these spawned ones are stored in a TArray variable in the main actor.

  • BeginDestroy() or the Destructor should loop over the loop when the main actor is destroyed/deleted and destroy every spawned actor.

What happens:

  • When deleting it in the editor (CMD DEL, or just del key), the main actor gets destroyed.

  • The Destructor or BeginDestroy() gets called, however the TArray is EMPTY by then. So lets say I spawned 5 actors, pointers of them are stored in the array. The moment I delete the main actor, this Array gets reset to 0 elements - I loose all reference, rendering me unable to destroy the spawned actors

What I think the bug is:

  • When destroying actors in the editor, variables like TArray or even a Bool get RESET. So a TArray is emptied and a Bool is false - everytime. It does not matter what you set it before. Once you reach the destructor / beginDestroy, the contents of these variables are gone, replaced by the default.


  • Problem 2 - Still bad, but not as serious as the 1st one **

What I was trying to do:

  • I have an actor which has a destructor and a BeginDestroy() function.

  • Deleting the actor should call these functions once and everytime I delete an actor of that kind in the editor.

What happens:

  • Sometimes BeginDestroy and the Destructor are called MULTIPLE times in a row!

  • If you delete an actor and undo your action in the editor (Ctrl + Z), and then delete it again, the destructor / beginDestroy will NEVER be called


Sorry for the long text, but I hope that we can solve it that way. If you still don't know what I am trying to do or why I think this is a bug, then I probably have a serious misconception about the way the engine works.

avatar image Doug E ♦♦ STAFF Mar 17 '15 at 11:24 PM

To answer your second question first, I was able to reproduce this. As discussed in the other thread you created (https://answers.unrealengine.com/questions/187184/c-destructor-runs-only-once.html) this has been bugged as UE-11680.

In testing the first problem you listed I created a class (DestroyTest) with a float and bool variable. I set each of them on the constructor and print out their value to the output log. In the destructor I set them to a different value and then print the value again. Both variables print the expected value (that set in the destructor) when I delete them. Could you post the code for how your mainActor creates the other spawned Actors as well as how it stores the references in the array? Then I can test creating/destroying the spawned actors on my end.

Cheers

Doug Wilson

avatar image holzlag0r Mar 18 '15 at 12:10 AM

Hi Doug,

I created an actor which works almost exactly the same way my original one does, but I removed all the the code which is not relevant for the problem.

ZipFile

The zip contains two files. Add them to your project, make the required changes (LogCategory, GAME.h) and then compile. Then create a Blueprint. Place it into the world, and assign "Actor to Spawn" to an actor of your choice. This should spawn the desired actor. Then delete the main actor.

I get the following Output:

 Omega:Warning: Comps.Num() = 1
 Cmd: DELETE
 Cmd: ACTOR DELETE
 LogEditorActor: Deleted Actor: BP_TEST_C
 Omega:Warning: Comps.Num() = 0
 LogEditorActor: Deleted 1 Actors (0.019 secs)


answerhub2.zip (1.3 kB)
avatar image Doug E ♦♦ STAFF Mar 18 '15 at 08:15 PM

Hey holzlag0r-

Using this call UE_LOG(LogTemp, Warning, TEXT("Mem Address = %i"), this); I checked the memory address of the main actor during OnConstruction() and when it is destroyed, which produced two separate results. This means that the mainActor that is creating the other actors during OnConstruction() and the mainActor that gets deleted are technically two different actors (which could cause other issues with hanging references). What exactly are you attempting to do as there may be safer ways to accomplish the same thing.

avatar image BigKevSexyMan Apr 21 '15 at 02:21 AM

I can confirm this, but it get's even more interesting. I know where the rogue actor(s) are coming from. It seems that whenever you drag an object over the editor pane, a new object is created. Then, when you release the object, an additional one is created. This additional one is what we see in the editor. In fact, if you pull in and out of the editor pane, you'll create multiple "phantoms." Things get weirder when you try to delete the object we can see in the editor. Apparently, the code will call BeginDestroy() on all the phantoms, but NOT the one in the editor that you actually deleted. Which is probably why we are seeing our arrays as empty when it is called. Weirder, the "real" actor ends up getting removed in the end, despite it never getting a BeginDestroy().

Here's and excerpt from the log I ran on this:

 // Dragging "Gameboard" class back and forth onto the pane.  I finally dropped it on "Gameboard_3"
 LogEditor: Attempting to add actor of class 'Gameboard' 
 LogTemp:Warning: Constructor: Gameboard_0
 LogEditor: Attempting to add actor of class 'Gameboard' 
 LogTemp:Warning: Constructor: Gameboard_1
 LogEditor: Attempting to add actor of class 'Gameboard' 
 LogTemp:Warning: Constructor: Gameboard_2
 LogEditor: Attempting to add actor of class 'Gameboard' 
 LogTemp:Warning: Constructor: Gameboard_3
 // Gameboard_3 is now visible
     
 // Deleting the Actor visible in the editor, yet it calls BeginDestroy on the phantoms
 LogEditorActor: Deleted Actor: Gameboard
 LogTemp:Warning: BeginDestroy: Gameboard_0
 LogTemp:Warning: BeginDestroy: Gameboard_1
 LogTemp:Warning: BeginDestroy: Gameboard_2
 LogEditorActor: Deleted 1 Actors (0.016 secs) // Gameboard_3 officially deleted here?
 // No BeginDestory called for Gameboard_3

I can provide code on request.

avatar image Doug E ♦♦ STAFF Apr 22 '15 at 03:42 PM

Hey BigKevSexyMan-

Thank you for the extra information. I have included this with the original bug report which is still being investigated.

Cheers

avatar image jeffvoigt May 29 '15 at 04:59 PM

You know it would be much better if we can tell if the user is just dragging an actor into the scene so we can avoid any unnecessary construction. Is this possible? I added my code below but wanted to raise the question.

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

Have you tried overriding AActor::BeginDestroy?

more ▼

answered Mar 08 '15 at 08:04 PM

avatar image

mcucuzza
28 1 4 6

avatar image holzlag0r Mar 09 '15 at 01:46 PM

Thank you for your answer.

I already messed around with BeginDestroy(), and it seems like it is bugged... https://answers.unrealengine.com/questions/187184/c-destructor-runs-only-once.html On top of that, I am unable to run most of my functions there (like destroying other actors). So I guess that the destruction already started. Also, keep in mind that I am talking about deleting it in the editor, not calling destroy() ingame.

avatar image holzlag0r Mar 09 '15 at 01:49 PM

So I just debugged it a bit more, and it seems like it clears my UPROPERTY TArray before it calls BeginDestroy(). That is a bug, right?

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

I'm trying to create a procedurally generated level, and the actor in question is responsible for previewing it Pre-PIE.

So I just added a bool uproperty now that allows me to destroy all spawned actors (checking it in OnConstruction) and I use that whenever I want to delete the main actor.

I don't think you have to track the behaviour described above as a bug - it's rather a little limitation. And I guess I'm also the only one who tries to do something like this - so rewriting that part of the editor is not necessary.

And by the way: Thank you for your patience, Doug. It seems like Epic really wants to support the community - and I really appreciate that! I guess that's it for now. Thank you and have a great day!

more ▼

answered Mar 18 '15 at 09:27 PM

avatar image

holzlag0r
39 10 11 14

avatar image jeffvoigt May 29 '15 at 04:34 PM

I'm also running into this as I also have a single Actor generate child actors prior to PIE. I have a Region actor that spawns Room actors and the Region actor needs to be able to remove the spawned children if they still exist.

avatar image jeffvoigt May 29 '15 at 04:47 PM

This seemed to work as expected for me. When I create my child actors I make sure to set their owner as the region so when the region is ::Destroyed() it will go through all world actors that contain the same owner and call their ->Destroy() method. Here is the code to get all child room actors w/the region as the owner:

 TArray<ARoom*> ARegion::GetRoomActors()
 {
     // get all child components
     TArray<ARoom*> result;
     for (TActorIterator<ARoom> room(GetWorld()); room; ++room)
     {
         if (!room || !room->IsValidLowLevel())
             continue;
 
         if (room->GetOwner() == this)
             result.Add(*room);
     }
     return result;
 }
avatar image jeffvoigt May 29 '15 at 04:48 PM

So I avoid storing a child actor pointer array but I have to pull it from the world when I need it. I guess that is the only difference.

avatar image jeffvoigt May 29 '15 at 04:59 PM

You know it would be much better if we can tell if the user is just dragging an actor into the scene so we can avoid any unnecessary construction. Is this possible?

avatar image Doug E ♦♦ STAFF Jun 01 '15 at 06:13 PM

Hey jeffvoigt-

I just want to confirm that the code you posted does in fact allow you to delete the parent actor which will automatically delete the child actors that the parent generated at creation? As for dragging into the scene creating a temporary actor, this is the expected behavior. When destroying the actor it is only destroyed via garbage collection when the engine does that operation. At that point any unrefrenced temporary actors would be destroyed. If your instances are still valid then they are not deleted.

(comments are locked)
10|2000 characters needed characters left
Viewable by all users
Your answer
toggle preview:

Up to 5 attachments (including images) can be used with a maximum of 5.2 MB each and 5.2 MB total.

Follow this question

Once you sign in you will be able to subscribe for any updates here

Answers to this question