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"

TMap FindChecked assertion with valid data

I have the following code set up in a UDataAsset subclass:

 .h
 UPROPERTY(EditDefaultsOnly)
 TMap<USkill*, UMasteryLevel*> MaxSkillMastery;
 
 .cpp
 AssetRegistry.OnAssetAdded() {
     ...
     MaxSkillMastery.Add(Skill, nullptr);
     MaxSkillMastery.KeySort(Func);
 }
 AssetRegistry.OnAssetRemoved() {
     ...
     Iter.RemoveCurrent();
 }

As objects of the Key type are created/removed, the map automatically updates itself to have 1 entry per object. The values are then set in a DataAsset in the editor. In my test case, I have 3 key objects and 3 value objects - in the DataAsset I assign 1 value per key.

alt text

I then have a unit test that runs in GameInstance::Init() with the following code:

 UPROPERTY()
 USkill* Chain;
 UPROPERTY()
 UMasteryLevel* Invalid;
 
 static ConstructorHelpers::FObjectFinder<USkill> ChainFinder(TEXT("Skill'/Game/GameInfo/Skills/Chain.Chain'"));
 Chain = ChainFinder.Object;
 
 AssetRegistery.OnFilesLoaded() {
     ...
     Invalid = Cast<UMasteryLevel>(Asset.GetAsset());
 }

I do this for all the skills/masteries, and the pointers are all valid and I can access them and everything is great.

Finally, during the unit test I make the following calls:

 auto X = MaxSkillMastery[Alchemy]; // success
 auto Y = MaxSkillMastery[Sword]; // success
 auto Z = MaxSkillMastery[Chain]; // crash sometimes

Sometimes the call with Chain asserts false in FindChecked (the [] operator), sometimes it doesn't. If I change the DataAsset in the editor from Invalid to Basic and back to Invalid, it seems to no longer crash, but some time later it will start crashing again consistently, until it decides it's done crashing and it won't do it again for hours. I've also ran the following code:

 for (auto X : CharacterClass->MaxSkillMastery) {
     UE_LOG(LogTemp, Warning, TEXT("%p, %p, %i"), Skill, X.Key, X.Value->IntVal);
 }

This code executes perfectly fine, and then immediately crash a few lines later when it gets to the [] operator. In fact, Skill and X.Key produce the same exact pointer value, and X.Value resolves properly without any nullptr issues. So I know that both the Key and Value are valid pointers, but for some reason FindChecked() is failing regardless.

Any thoughts at all would be appreciated.

Product Version: UE 4.17
Tags:
data-asset-map.jpg (14.6 kB)
more ▼

asked Jan 16 '18 at 08:51 AM in C++ Programming

avatar image

hapro
26 3 3 8

avatar image BrUnO XaVIeR Jan 16 '18 at 11:59 AM

The "sometimes" crash may be because sometimes the UObject is loaded and sometimes is not; Check to see if the Chain object is actually loaded:

 if (ChainFinder.Succeeded()) {
         Chain = ChainFinder.Object;
 } else {
         // meh! something wrong isn't right...
 }

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

1 answer: sort voted first

ChainFinder.Object is the prototype of the class, it's not supposed to be used. You're supposed to create an instance of the class that you get back from FObjectFinder.

FYI there's another option to FObjectFinder -- which I used to myself before I learned about this: Change your Chain declaration to TSubclassOf<USkill>. It will show up in the Gameinstance blueprint where you can set it to what you want. Then you can use it in your C++ code.

Just like with FObjectFinder, you still need to create a new object from the class.

more ▼

answered Jan 16 '18 at 09:13 AM

avatar image

Jin_VE
4.4k 32 79 42

avatar image hapro Jan 16 '18 at 09:41 AM

In this case, the skill is an immutable global object, so isn't that what FObjectFinder is for? I'm not sure that explains why the map is asserting, since I was under the impression that the pointer itself would be hashed, so as long as the pointer is const, so too would the hash.

avatar image Jin_VE Jan 16 '18 at 10:17 AM

It looks like Chain is a BP derived from USkill. In that case you need to create an instance of Chain to use. FObjectFinder doesn't instantiate a new object for you, it's just returning the class of the BP at the path you provided.

Unless USkill is derived from UClass, I don't see how what you're doing now could be right. But I could be assuming something that isn't true or not getting something on some level. If that's the case, hopefully someone else can help.

That said, here's what I'd do:

Add a member variable to the Gameinstance that is TSubclassOf<USkill>. Call it "ChainClass". Open your Gameinstance blueprint and set that variable to the Chain BP class. Then in C++, use ChainClass to create the Chain object.

avatar image Jin_VE Jan 16 '18 at 10:22 AM

And if USkill is derived from UClass then you should still try what I'm suggesting: use TSubclassOf and set it in the BP. Then use that in your TMap. See if it works any better.

(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