Additional LUA Key Set/Get Concepts - Dynamic Variables

Share your best strategies and tactics with other players by posting them here.

Moderator: MOD_Command

Post Reply
Dan109
Posts: 175
Joined: Thu Apr 27, 2017 1:04 pm

Additional LUA Key Set/Get Concepts - Dynamic Variables

Post by Dan109 »

Hi All,

I wanted to further add to the Get/Set Key Value discussion. I'm using in a fairly effective manner for my needs, per unit memory retention. Below is a simple example, but the variable a needs to be defined and hardcoded for each individual use.

a = ScenEdit_GetKeyValue("a")
ScenEdit_SetKeyValue("a","1")

The idea is to "create key names" so they can be used quite easily no matter how many units you add to a scenario, if you have the need for per unit variables. Space Characters (i.e. hex 32, x20) cannot be in the NAME of a Key (selector KeyStore.key), hence use GUID instead of NAME for your dynamic variable names.

The below example has two parts, 'initialization' and retrieval. If ScenEdit_GetKeyValue is called on a key name which has not been "set" prior, the get function will return "". This is a way of representing nil. However, it would be better practice to initialize the variables intended for use with your own customized value, so you will know in the future if it has ever been set. You can later set your key data to this customized nil in the case you might want to "logically" delete the data, which can be useful in some coding situations.

The intialization portion will assume that every key name will be prefixed with a similar definition. Here we use 'Data1'. This gives an opportunity as well to easily add comments to a single location, to explain the definitions (sometimes, you need to re-explain to yourself, haha) of your custom variables.

The suffix of course needs to be unique. From trial by fire, I have learned that the Keystore.key descriptor, or more simply put, the key name, cannot have any space characters (i.e. hex 32, x20). There may be other restrictions. However, numbers and the "-" character are allowed, hence GUID is the best approach to making each dynamic variable unique. The key's name will therefore be a string of the "Data1" string concatenated with the GUID string of the unit by using the LUA concatenatation operation of "dot dot". a..b is logically adding the strings a and b together. No need to convert data structures to/from strings. The data used to construct and use the key name are all strings.

Therefore below we see an example of creating several variable names, one per unit, and initializing them to a known value 'custom_nil'. The 2nd portion is an example of constructing the variable name, well after creation, and using the data.

my_side = 'US Navy'
my_data_prefix = 'Data1'
my_units = (VP_GetSide({name=my_side}) ).units
for index,tab_unit in pairs(my_units) do
my_unit = ScenEdit_GetUnit(tab_unit)

my_key_name = my_data_prefix..my_unit.guid
my_key_data = 'custom_nil'
ScenEdit_SetKeyValue(my_key_name,my_key_data)

end
-- later use in your code
my_units = (VP_GetSide({name=my_side}) ).units
for index,tab_unit in pairs(my_units) do
my_unit = ScenEdit_GetUnit(tab_unit)

my_key_name = my_data_prefix..my_unit.guid
my_key_data = ScenEdit_GetKeyValue(my_key_name)
print(my_key_data)

end

Here is another example of using the keys. Let's say 'Data1' is being defined as per unit memory retention, like the previous mission name, the timestamp of last time you "did or checked something" to the unit, or the name of the original homebase of a unit. Let's use timestamp. Specifically, let's do something based on the time the unit last detected something.

--initialization already done
--will need a 'Unit Detected' trigger to trigger this LUA
detecting_unit = ScenEdit_UnitY()
my_key_name = 'Data1'..detecting_unit.guid
if ScenEdit_GetKeyValue(my_key_name) ~= 'custom_nil' then
my_data_to_use = ScenEdit_GetKeyValue(my_key_name)
if ScenEdit_CurrentTime() > (tonumber(my_data_to_use) + my_time_offset_requirement) then
--do your thing
end
else
--do a different thing if the unit is detecting something for the first time
end
--Store current timestamp for next time the event triggers
ScenEdit_SetKeyValue(my_key_name,tonumber(ScenEdit_CurrentTime()))


The possibilities with per unit data are nearly limitless. The primary limiting factor I foresee is the current triggers we have in CMANO, which are certainly being expanded as we speak. I haven't tried any large scenarios, but I've been surprised from testing how little LUA affects time compression for a set time trigger to occur every 15 or 30 seconds. By putting LUA scripts in to check and do things quite frequently, one can certainly compensate for various triggers that are not yet currently implemented. Of course everything does have limitations, and based on scenario size, you could quite possibly slow down performance with your LUA. And I'm not sure what time compression (say set to x15min) will do to scripts running every 15 or 30s. Try it, until you break it, is my motto.

Now let's look at using multiple types of data, per unit. Three methods can exist

A) Simple Definition

The Use above would be a simple definition. Need 2 or 3 types of data stored per unit, just just 'Data2' and 'Data3'. But you might need much more.

B) Table of Definitions

Here we can use a table to store keyname prefix data, to offer a more elegant solution to use of multiple pieces of data per unit

my_key_name_prefixes = {'PreviousMissionName','LastDetectedUnitTimeStamp','LastTimeUnitEnteredArea','LastTimeUnitWasDamaged'}
-- unit is stored in my_unit
my_data = ScenEdit_GetKeyData(my_key_name_prefixes[2]..my_unit.guid)

C) Customized Complex Definition

One could even go as far as defining a customized data structure, and then converting it to/from strings for use. Let's say you want to create an extension of CMANO's LUA unit descriptor. Instead of individual single pieces of data, they might even contain tables. In the below example, the "custom unit" would have a simple keyname, say 'custom'..my_unit.guid. But the data it contains, is not standard at all.

custom_unit
custom_unit.PreviousMissionName - type string
custom_unit.LastDetectedUnitTimeStamp - type integer
custom_unit.LastTimeUnitEnteredArea - type integer
custom_unit.LastTimeOutOfComms - type integer
custom_unit.TableOfHighValueTargets - table of strings - can be names or GUIDs - upon unit contact, can fire SE_AttackContact or other offensive measures - can be used to override current mission, rather than via LUA creating a new mission and switching to it
custom_unit.TableOfEmmisionsToAvoid - table of strings - can be the DB ID of sensor components - upon unit contact and positive ID, can sort through contact's sensor components and trigger code to make your unit retreat, bypass it, etc
custom_unit.NumberOfHardKills - type integer

Now, the above could be defined via methods A and B, but it could get quite ugly. And its not dynamic. Hence, let's some concepts to create this structure. The only limit is the length of a string in LUA. Let's first define what we want the CMANO Key Data to look like:


DataType - enumerated type {STR,INT,TOS,TOI} - important to be fixed character length for simple parsing - hence will be represented by 0, 1, 2, or 3.
DataLength - tricky as its critical that this part is FIXED. The number of characters represent the length of the data next to it must well known and static. Let's pick 2 digits for max length for each structure (strings or integers)- however a length of 7 for example, must ALWAYS be defined as 07.
DataValue - the value of the data stored
MoreData - a one character bool to represent more data to parse - T or F
NumItems - number of items in a table - used only for data types 2 or 3 (Table of strings or integers) - also must be fixed - lets cap this at 3 digits

my_key_data = DataType..DataLength..DataValue..MoreData..DataType..DataLength..DataValue..MoreData..DataType..DataLength..DataValue..MoreData..DataType..NumItems..DataLength..DataValue.. Length/Value repeated for number of items ..MoreData..DataType..NumItems..DataLength..DataValue.. Length/Value repeated for number of items ..MoreData..DataType..DataLength..DataValue..MoreData

Ok, above was a logical view of what the my_key_data string would look like for our complex data structure. For practical purposes, let's show this data structure for the following items in LUA format

custom_unit.PreviousMissionName = 'Patrol Taiwan'
custom_unit.LastDetectedUnitTimeStamp = 1496790343.45846
custom_unit.LastTimeUnitEnteredArea = 1496795343.35324
custom_unit.LastTimeOutOfComms = nil
custom_unit.TableOfHighValueTargets = {'Tomcat #14','843c95e4-1747-4ad9-b54d-2d060564264e','USS Sean Spicer'}
custom_unit.TableOfEmmisionsToAvoid = {5634,7856,7543,3296,94} -- I've made all of these up, didn't bother looking any up
custom_unit.NumberOfHardKills = 4

my_key_data = 013PatrolTaiwanT1161496790343.45846T1161496795343.35324T100T200310Tomcat #1436843c95e4-1747-4ad9-b54d-2d060564264e15USS Sean SpicerT1014F

Using LUA string functions, you can parse out this data. Values can be changed, table entries added or deleted. By knowing the data type, you could know if you need to use tonumber function. I won't go into the code to do it because I personally don't yet have a need for this, but wanted to explain how it could be done. I've used method A, and using B now but I think a scenario would need A LOT of custom data to warrant method C. However, if the community combined efforts with customized LUA content requiring per unit data, this could be used as a community construct to help standardize things.

Thanks for reading all - I hope you, like me, continuing to be excited about the possibilities with CMANO LUA
Post Reply

Return to “The War Room”