Version highlights 1.20.0
  • 01 Aug 2023
  • 7 Minutes to read
  • Contributors
  • Dark

Version highlights 1.20.0

  • Dark

Article summary

List of all changes in 1.20.0

With version 1.20 we are releasing a large update to Combeenation's computational engine that has been a long time in development. The greatest part of this update won't have any directly visible effects for our users, but brings a number of performance and stability improvements that should make our configurators even more delightful to work with.

This update also lays the foundation for more advanced features that would not have been possible in the old system. Stay tuned for some juicy new features in the near future! Until then, we have a couple of new things for you to play with and a host of fixes and quality of life improvements for our ConfiguratorEditor.

One noteworthy improvement revolves around renaming components and changing their type: in the past, the ConfiguratorEditor sometimes failed to show all effects of these changes. We've completely re-designed the way we process such changes and have re-written the configurator-wide error analyser to be more reliable and efficient.

Other impactful changes are outlined in the sections below. Of particular importance is the following section as it will significantly affect your day-to-day work with the ConfiguratorEditor.

Using components with the # Operator

Hidden identifiers can now be accessed with the new # operator. The operator must also be used to access the Records, Value and SelectedKey properties of a RecordComponent.

Naming things is hard. Poorly chosen component names can confuse your colleagues (or yourself) and sometimes they can get you into awkward situations. Imagine a GraphicComponent and inside it a visual with the name "Width". Now imagine you had to use both the "Width" visual and the component's Width property – how can you tell them apart? They are both called "Width" after all.

This is where the new Escape Operator comes in: Width refers to the "closer" thing, in this case the visual, while #Width refers to the "hidden" or more distant thing, in this case the component's width property. For the most part, you can avoid landing in situations like this by picking meaningful names – but in case you do end up in one, the escape operator is there to help you.
This is also where the operator got its name – and because a number sign (#) resembles prison bars (and because naming things is hard).



There is a second, more frequently occurring scenario that requires the use of the # operator, and it has to do with certain kinds of components, like the RecordComponent. These components have always been two things at once: a component and a value produced by the component. The RecordComponent for instance possesses properties like Records and SelectedKey, while its value is the selected record.

Up until now you could just write the component's name and then access either its properties or those of its value. For example, myComponent.Records would return the Records property and myComponent.Price would return the "Price" column of the selected Record.

Things got ugly if both the component and its value contained a property with the same name. In that case you had to know which one the system would use, and how to get a hold of the other one. For RecordComponents, that meant you had to write e.g. myComponent.Value.Name instead of myComponent.Name (because "Name" would refer to the component's Name, not the "Name" column of its value).

Confusing, isn't it? Our goal is to remove these complicated scenarios, but to get there we first had to stop the system from choosing one out of two possible properties for you. Unfortunately that means that for now, you have to do the choosing.

Specifically, to access any property of a RecordComponent, you now have to use the Escape Operator. For example, to access the Records property you have to write #myComponent.Records. This is now required. On the plus side, myComponent.Name will now always refer to the "Name" column (if there is one), meaning you no longer have to write myComponent.Value.Name.

Under the hood

If you're wondering why we chose the Escape Operator to discern component properties, then this section is for you. If you had enough of obscure compiler mumbo jumbo, feel free to move on to the next section.

At the beginning of this section we mentioned that certain components are two things at once – a component and its value. This is no longer the case. A component and its value are now two separate entities, where the value is "closer" to you, the user. As a result you always work with the value by default, and if you want to use the "hidden" component you need to "escape" the value first.

Other components that are affected by this change are, in theory, the ValueComponent and ResourceComponent. However, contrary to the RecordComponent, it is unlikely that you will end up needing any of their properties, so don't worry about it. And in case you do need to access one of them, just use the Escape Operator.

General Features

We have added two new variables that can be used to obtain various kinds of information about your configurator: configurator and presets. For more details, check out their documentation. The configurator variable is a replacement for the plan keyword, which will be removed in a future version.

In addition to single-line comments, you can now also write comments that span multiple lines or just a portion of a single line. Start the comment with /* and end it with */, further details and examples can be found in the documentation.

Changes to Text in Hive

Text comparison is now case sensitive by default, new functions and features have been added to Text.

Comparing texts in Hive used to be case insensitive, meaning "hi" = "Hi" would return true. This was convenient in some cases but problematic in others, for example when you have to deal with case-sensitive product IDs or SKUs.

Text is now case sensitive, meaning "hi" = "Hi" will return false. However, we added a ~= operator for Text that ignores casing to support existing use cases: "hi" ~= "Hi" will return true, just like the = operator used to.

This change also affects Maps such as Resources or Components. When you wish to retrieve e.g. a Resource by constructing its Name dynamically, you need to use the exact same case you used when creating the Resource.
For example, if you have a ResourceComponent called "pics" and within it a Resource with the name "Pic1", you must write pics.Resources.Get("Pic1") to retrieve it. Writing Get("pic1") will not return it. (Note that this does not affect direct references to the resource! These are still case-insensitive, meaning that pics.Pic1 will work)

We also added two new functions to Text: contains can be used to check if a Text contains certain characters or words and replace can be used to replace them with a different Text. Check out the Text docs for more details and examples!

More Helpful Hive Errors

Error messages are more precise, easier to understand and include more helpful information.

We've completely rewritten all compiler errors to be more understandable and less technical. Each error now briefly states what the problem is and may contain a hint at the end to further explain why it occurred and/or provide guidance for inexperienced users.

We also improved the code snippets that are shown in the error message to more precisely highlight where the error occurred. These snippets now also work properly when the affected area spans multiple lines.

Here is an example:

-- ERROR in TestComponent --------------------------------------------------------------------------

The branches of this 'if' produce different types of values:
The 'then' branch has type Number but the 'else' branch is Text.

3|   if true then 1 else "2" end

Hint: All branches must have the same type so that no matter which one we take, we always get back the same type of value.

New: DynamicVisual Items

You can now access the individual items generated by a DynamicVisual with its new Items property.

Items is a list of visuals, which means you first need to pick the one you are interested in with the Get function. You can then access all properties of that visual, such as its X or Y coordinates or its Texture or Shape:

// get the 'x' coordinate of the 2nd visual of the 'boxes' DynamicVisual

The number of items matches that of the DynamicVisual's ItemSource property.

Was this article helpful?