BSL:String comparison: Difference between revisions

From OniGalore
Jump to navigation Jump to search
(Let's trample some hopes...)
 
m (copy-edit)
 
Line 1: Line 1:
==Summary of this page==
Even though the topic is a bit complicated, the key conclusion is that [[BSL]] does '''not''' reliably support string comparison. It is strongly advised to '''not''' rely on string comparison in your BSL scripts.
Even though the topic is a bit convoluted, the general information is that [[BSL]] does '''not''' reliably support string comparison.<br/>
 
It is strongly advised to '''not''' rely on string comparison in BSL scripts.
==Introduction==
As a lot of scripters already know, BSL seemingly allows string comparison, meaning it looks like the language should be capable of processing syntax similar to the following one:


==Topic==
As a lot of BSL scripters already know, BSL seemingly allows string comparison, meaning it looks like BSL should be capable of processing syntax similar to the following one:<br/>
<pre>
<pre>
func void some_ai_died(string ai_name){
func void some_ai_died(string ai_name)
   if (ai_name eq "A_t48") {
{
   if (ai_name eq "A_t48")
  {
     dmsg("A_t48 died!");
     dmsg("A_t48 died!");
   }
   }
   else {
   else
  {
     dmsg("Some other AI died!");
     dmsg("Some other AI died!");
   }
   }
Line 16: Line 18:
</pre>
</pre>


However, string comparison appears to be a bit unreliable - sometimes it looks like it works, sometimes it does not.<br/>
However, string comparison appears to be a bit unreliable sometimes it looks like it works, sometimes it does not. But why? The following research is an attempt to find the answer.
But why? The following research is an attempt to find the answer.


==Test setup==
==Test setup==
A test was set in the 1st savepoint of the EnvWarehouse level.
A test was set up in the first savepoint of EnvWarehouse.


The test comprized of:<br/>
The test was composed of:<br/>
# A test subject ("A_t48" ai2 character) and its slightly modified death function t48_dead(string ai_name).
# A test subject (the "A_t48" AI character) and its slightly modified death function "t48_dead(string ai_name)".
# A global BSL string variable "BOB_string".
# A global BSL string variable "BOB_string".
# A lot of wasted time while searching for all those damned addresses ^_^.
# A lot of wasted time while searching for all those damned addresses ^_^.


The test was set as follows:
The test was set as follows:
# There is a global BSL variable "BOB_string".<br/>Init value of the variable is a BSL string literal "A_t48".<br/>The variable can be set via custom BSL functions to represent one of these BSL string literals: "A_t40", "A_t41", "A_t42"
# There is a global BSL variable "BOB_string". The init value of the variable is the string literal "A_t48". The variable can be set via various BSL functions to one of these string literals: "A_t40", "A_t41", "A_t42".
# There is a BSL function ''t48_dead(string ai_name)''.<br/>The function is called by engine when the ai2 character "A_t48" dies.
# There is a BSL function "t48_dead(string ai_name)". This function is called by the engine when the AI character "A_t48" dies.
# Inside the BSL function t48_dead(), there is an immediate comparison of '''ai_name''' and '''BOB_string'''.
# Inside the function t48_dead(), there is an immediate comparison of "ai_name" and "BOB_string".
# After cca 5 seconds, BOB_string is set to be the same as ai_name and another comparison attempt is made.
# After about 5 seconds, "BOB_string" is set to be the same as "ai_name" and another comparison attempt is made.


==Test results==
==Test results==
Please see the enclosed series of figures.
Please see the enclosed series of figures. Figures show a relevant selection of runtime memory data.
Figures show a relevant selection of Oni application runtime memory data.
 
# Data regarding global BSL variable '''BOB_string'''.<br/>
#: [[Image:BSL-strcmp-01 gbStrVar-Ptr.png|256px]]  [[Image:BSL-strcmp-02 gbStrVar-PointedMemory.png|256px]]
# Data regarding local BSL variable '''ai_name'''.<br/>(relevant only during the execution of the t48_dead() BSL fnc)
#: [[Image:BSL-strcmp-03 ainame-Ptr.png|256px]]  [[Image:BSL-strcmp-04 ainame-PointedMemory.png|256px]]
# State of runtime memory data at the moment when BSL string 'comparison' got evaluated for the first time (evaluated 'false') and for the second time (evaluated 'true').
#: [[Image:BSL-strcmp-05 comparison-false.png|256px]]  [[Image:BSL-strcmp 06 comparison-true.png|256px]]


# Data regarding global variable "BOB_string".
#: [[Image:BSL-strcmp-01 gbStrVar-Ptr.png|256px]] [[Image:BSL-strcmp-02 gbStrVar-PointedMemory.png|256px]]
# Data regarding local variable "ai_name" (relevant only during the execution of the t48_dead() function).
#: [[Image:BSL-strcmp-03 ainame-Ptr.png|256px]] [[Image:BSL-strcmp-04 ainame-PointedMemory.png|256px]]
# State of memory at the moment when the string comparison was evaluated the first time (as 'false') and the second time (as 'true').
#: [[Image:BSL-strcmp-05 comparison-false.png|256px]] [[Image:BSL-strcmp 06 comparison-true.png|256px]]


==Conclusion==
==Conclusion==
# BSL string data seems to be stored as a C-style string. No additional special characters, simply a stream of bytes till the first 0x00 byte (string terminator).
# A BSL string variable seems to be stored as a C string; no additional special characters, simply a stream of bytes till the first 0x00 byte (null terminator).
# If there are several various independent strings which by chance represent a same text (e.g. "A_t48"), then engine keeps separate instances of these strings (no string grouping or any similar techniques).
# When keeping track of a BSL string, Oni thus uses a '''pointer''' to the given C string.
# For BSL strings, the 'string' BSL datatype does not seem to be a string itself, but it more probably represents a '''pointer''' to the given C-style string.
# If there are several independent strings which by chance contain the same text (e.g. "A_t48"), the engine still keeps separate instances of these strings (no string reuse to save memory, or any similar technique).
# When BSL string 'comparison' is attempted, it in fact most probably means that the values of pointers themselves are compared (meaning the addresses are compared), not strings themselves.
# When string comparison is attempted, it is most likely that the values of the pointers themselves (the memory addresses) are being compared, not the contents of the strings themselves.
# Engine allocates local BSL variables and parameters of BSL functions "on demand" and utilizes a memory area which is not exclusive for BSL strings, but is generally used for various purposes.<br/>This point effectively means that address of a local BSL string (think ai_name) can differ based on what happened in the game prior to the string allocation request.
# Since the engine allocates memory for local BSL variables and function arguments on demand, the address of a string such as "ai_name" will differ in each runtime session and cannot be expected at a particular position.
 


[[Category:BSL docs]]
[[Category:BSL docs]]

Latest revision as of 14:46, 3 April 2021

Even though the topic is a bit complicated, the key conclusion is that BSL does not reliably support string comparison. It is strongly advised to not rely on string comparison in your BSL scripts.

Introduction

As a lot of scripters already know, BSL seemingly allows string comparison, meaning it looks like the language should be capable of processing syntax similar to the following one:

func void some_ai_died(string ai_name)
{
  if (ai_name eq "A_t48")
  {
    dmsg("A_t48 died!");
  }
  else
  {
    dmsg("Some other AI died!");
  }
}

However, string comparison appears to be a bit unreliable — sometimes it looks like it works, sometimes it does not. But why? The following research is an attempt to find the answer.

Test setup

A test was set up in the first savepoint of EnvWarehouse.

The test was composed of:

  1. A test subject (the "A_t48" AI character) and its slightly modified death function "t48_dead(string ai_name)".
  2. A global BSL string variable "BOB_string".
  3. A lot of wasted time while searching for all those damned addresses ^_^.

The test was set as follows:

  1. There is a global BSL variable "BOB_string". The init value of the variable is the string literal "A_t48". The variable can be set via various BSL functions to one of these string literals: "A_t40", "A_t41", "A_t42".
  2. There is a BSL function "t48_dead(string ai_name)". This function is called by the engine when the AI character "A_t48" dies.
  3. Inside the function t48_dead(), there is an immediate comparison of "ai_name" and "BOB_string".
  4. After about 5 seconds, "BOB_string" is set to be the same as "ai_name" and another comparison attempt is made.

Test results

Please see the enclosed series of figures. Figures show a relevant selection of runtime memory data.

  1. Data regarding global variable "BOB_string".
    BSL-strcmp-01 gbStrVar-Ptr.png BSL-strcmp-02 gbStrVar-PointedMemory.png
  2. Data regarding local variable "ai_name" (relevant only during the execution of the t48_dead() function).
    BSL-strcmp-03 ainame-Ptr.png BSL-strcmp-04 ainame-PointedMemory.png
  3. State of memory at the moment when the string comparison was evaluated the first time (as 'false') and the second time (as 'true').
    BSL-strcmp-05 comparison-false.png BSL-strcmp 06 comparison-true.png

Conclusion

  1. A BSL string variable seems to be stored as a C string; no additional special characters, simply a stream of bytes till the first 0x00 byte (null terminator).
  2. When keeping track of a BSL string, Oni thus uses a pointer to the given C string.
  3. If there are several independent strings which by chance contain the same text (e.g. "A_t48"), the engine still keeps separate instances of these strings (no string reuse to save memory, or any similar technique).
  4. When string comparison is attempted, it is most likely that the values of the pointers themselves (the memory addresses) are being compared, not the contents of the strings themselves.
  5. Since the engine allocates memory for local BSL variables and function arguments on demand, the address of a string such as "ai_name" will differ in each runtime session and cannot be expected at a particular position.