Working with Instances and Filtering on Data
As mentioned in the previous module, the current square subscribers is subscribing to any of the colors of squares. Looking at the type definition, the color is defined as the key field which means that different values for the color will be handled as a different instance.
struct ShapeType
{
string<128> color; //@key
long x;
long y;
long shapesize;
};
Given that the color is the key value, there are two options to filter on color:
- Using instances, which means to read samples related to just a specific instance instead of all samples.
- Or, to use query conditions which allows us to filter on any values in the data as well as some of the meta data.
This example uses query conditions for the following reasons:
- Instance identifiers are not known until the first sample of that instance is received. In our case we know at startup the color we want to subscribe for, but not the instance identifier. If you plan on dynamically creating the game object as instances are discovered using instances handles, this will work well.
- Query conditions are more flexible as conditions can be set to not only filter on key values but also on other fields. For example, we could set up the query condition to only receive blue squares when x is greater than 100.
To receive samples for just blue squares, the filter for the query condition is “color MATCH ‘BLUE’”. More information about the syntax for DDS Queries and Filters can be found here.
In our case, we want to filter on the color. To allow different instances of this class to filter on different color values, the color is defined as a UPROPERTY so it can be configured on a per instance basis.
Now let’s see how we can add the filter. To do this we need to know which color we want to filter on. To do this we add a UPROPERTY to the header file with the color this instance subscribes to. That way we can configure the color for each object we place in the viewport of the Unreal Engine editor. It will be added to the same category (Connext) where we already have the topic name and domain id.
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Connext")
FString Color = FString("BLUE");
Now in the AShapeSub::Tick function, we need to set up the query conditions before taking samples. We need to change the take call to just take the samples which match the query conditions. Let’s add the following code
FString Filter("color MATCH '" + Color +"'");
dds::sub::cond::QueryCondition query_condition(
dds::sub::Query(reader, TCHAR_TO_UTF8(*Filter)),
dds::sub::status::DataState::any());
The DataState class describes the state of a sample and includes the information about the sample's InstanceState, ViewState, and SampleState.
We also need to update the take statement to apply the query condition:
rti::sub::LoanedSamples<dds::core::xtypes::DynamicData> samples =
reader.select().condition(query_condition).take();
Now the square only subscribes to the color it is set to. A blue square will only subscribe to samples for a blue square. Any other instances (colors) are ignored. If you publish a red square from shapes, the cube in Unreal Engine will not move.
Now we can add another shape, such as a red circle. First, a new blueprint class of type circle needs to be created. Browse to C++ Classes -> Unreal_Shapes in the Content browser. Right click on the ShapeSub class and select “Create Blueprint class based on ShapeSub”. Name the new class “Circle” and place it in the same folder as the Square Blueprint class. Now you can drag the new class on the viewport and configure it to be a red circle. Set the static mesh to a sphere and select red as the material.
The blue cube will only move when blue squares are being published by Shapes. The red sphere will only move when red circles are being published. Any other colors are ignored.
Looking at this in Admin Console, we still have one issue which is that each shape creates its own participant and reader. In order to scale and have multiple game objects at the same time, DDS instances need to be shared. There is no need to create more than one domain participant for each domain. The next section goes into details on how to share DDS entities.
Module 7 Demo:
This video covers the steps for Module 7.