How to check if a data member exists in a SkInstance without triggering an assertion?


#1

I’m using following code to check if a data member exists:

SkInstance* data = instance->get_data_by_name(FStringToASymbol(SOME_NAME));

 if (data != SkBrain::ms_nil_p)    // data member exists
  {
  DO_STUFF_HERE
  }

But that will trigger assertion when the data member not exists:

Is there a method to check if the data member exists beforehand? Something like:

If (instance->data_exists(SOME_ASYMBOL)) 
  {
  ...
  }

#2

[If you are looking for a Unreal Engine Blueprint variable field - the next update will contain accessor methods for those variables. They aren’t SkookumScript data members.]

If you are working with SkookumScript data members - an instance object test for a data member isn’t available, however you can test its class:

// Test for instance or class data member
if (instance_p->get_class()->get_data_type(FStringToASymbol(SOME_NAME)))
  {
  DO_STUFF_HERE
  }

// Test for instance data member
if (instance_p->get_class()->get_instance_data_table().find(FStringToASymbol(SOME_NAME)))
  {
  DO_STUFF_HERE
  }

// Test for class data member
if (instance_p->get_class()->get_class_data_table().find(FStringToASymbol(SOME_NAME)))
  {
  DO_STUFF_HERE
  }

Note that if you can create the ASymbol that you want to test for ahead of time it would be more efficient than using FStringToASymbol().

I’ve also added a find_data_by_name() method to SkObjectBase and its subclasses (such as SkInstance) that is more likely what you wanted in the first place. It will be available in the next update.

//---------------------------------------------------------------------------------------
// Finds and returns the uppermost scoped data instance of the requested name.
// 
// Returns: pointer to instance or nullptr
// Params:
//   name: name of data member to retrieve.
//     
// See: get_data_by_name(), set_data_by_name()
SkInstance * find_data_by_name(const ASymbol & name) const

#3

Thanks Noolarch! instance_p->get_class()->get_data_type(...) do the trick!

But it seems both the get_instance_data_table and get_class_data_table methods don’t take any arguments, is that because version difference?

Also for the virtual SkClassDescBase * get_data_type(const ASymbol & data_name, eSkScope * scope_p = nullptr) const;, why scope_p is a pointer to enum value, that make not much sense?


#4

Also you mentioned that you can test ASymbol ahead of time for efficiency, how to do that?


#5

Right - I’ve updated the example code to include .find() which should make them work. [Sorry - didn’t test the example code. :blush:]

Here is the comment - from the .cpp file - for get_data_type():

//---------------------------------------------------------------------------------------
// Determines if data member exists and if so its class type and optionally the scope
// where it was found.
// 
// Returns: class type of data member or nullptr if not found
// 
// Params:
//   data_name: name of data member
//   scope_p:
//     Optional address to store scope location where data member was found - see eSkScope.
//     If set to nullptr or not found then it will be unchanged.

If you look at eSkScope you can see that scope_p can be set to:

  SkScope__none,     // Variable does not exist in current scope
  SkScope_class,     // Class members
  SkScope_instance,  // Instance members
  SkScope_local      // Temporary variables, arguments [& perhaps variables higher on call stack?]

We plan to move all the comments from our .cpp files to our .hpp files. We assumed that most people would be just using SkookumScript at the scripting level first so we’ve been prioritizing that. Though obviously some people such as yourself would probably really appreciate being able to see all the extensive C++ comments that we have.


#6

Yes you can create a ASymbol if you know ahead of time what it will be and then use it repeatedly so that you don’t have to make one each time through the code.

Just store it somewhere that you have access to like as a static class data member or even as locally static to the function that you are writing if it is the only place that uses that symbol - for example:

void my_func()
  {
  static s_some_symbol(ASymbol::create("SomeName"));

  // Test for instance or class data member
  if (instance_p->get_class()->get_data_type(s_some_symbol))
    {
    DO_STUFF_HERE
    }
  }

There are other more sophisticated ways to store symbols though it may be overkill for the way you are doing it. Take a look at SkookumScript\SkSymbolDefs.hpp for an example. In the future we’ll be sure to go over symbols and how to use them efficiently in your project in greater detail.


#7
//   scope_p:
//     Optional address to store scope location where data member was found - see eSkScope.
//     If set to nullptr or not found then it will be unchanged.

Oh, I see. I thought it’s mean to be passed in get_data_by_name method to limit the result, like get_data_name(SOME_DATA_NAME, SkScope_instance), totally get it wrong :slight_smile: Thanks!

I think I should explain why I need those C++ access in the first place. I have added 3 method in SkUEActor to interact with Blueprint property:


// Get value from Blueprint property
// e.g.
//    bp_var_get("MyMesh") // return a StaticMeshComponent object
//                         // assume a "MyMesh" Blueprint variable exists
bp_var_get(String blueprint_property_name) Object

// Set Blueprint Property property
// e.g.
//  !hero: Actor.named("MyHero")<>Hero
//  !robot:Actor.named("RoboChar1")
//  hero.bp_var_set("MyRobot", robot) // set "MyRobot" Blueprint property to "RoboChar1" actor
bp_var_set(String blueprint_proerpty_name, Object val_obj)

// Init Instance data members from Blueprint properties base on naming convention
// All data member starts with "bp_" will be synced with Blueprint property after this call
//  e.g.
//      a "bp_MyRobot" data member will be updated with value of  "MyRobot" Blueprint property
bp_vars_sync()

To make bp_vars_sync works, I iterate through blueprint properties of current actor class, and check if there’s “bp_BLUEPRINT_PROP” data member match in current SkookumScript class. With the help of get_data_type() method, I can do the check without triggering the “data member not exists” assertion.