:orphan: .. **************************************************************************** .. CUI .. .. The Advanced Framework for Simulation, Integration, and Modeling (AFSIM) .. .. The use, dissemination or disclosure of data in this file is subject to .. limitation or restriction. See accompanying README and LICENSE for details. .. **************************************************************************** script_struct -------------- .. command:: script_struct ... script_struct :block: .. parsed-literal:: script_struct Name :ref:`script_variables ` ... end_script_variables :ref:`script` ... ... end_script uncloneable_ end_script_struct .. warning:: Prior to WSF 2.0, script_struct instances were created with the :method:`struct.New` method and the variables and methods in the instance had to be accessed via the '->' operator. Unfortunately that implementation was not type-safe and lead to many hard-to-find errors. What is being described here is the new syntax. The old syntax should not be used unless you need the `struct on the fly`_ capabilities. Overview ======== The 'script_struct' block defines an new 'class' that behaves much like any of the built-in classes (e.g.: :class:`WsfGeoPoint`). Instances of the class can be used as arguments to or returned by script methods and be used as template types in the :class:`Array>`, :class:`Map>` and :class:`Set>` containers. **A script_struct block that defines a new class is valid only as a top-level command** (that is, they cannot be inside platforms, processors or any other block). In addition, a script_struct class must be defined before it is used. The following section demonstrates the creation and use of a struct. Commands ======== .. command:: uncloneable Specify that instances of this script_struct cannot be cloned. .. note:: ``script_struct``\s are cloneable by default. script_struct example ===================== .. parsed-literal:: script_struct Car script_variables WsfGeoPoint position = { }; Vec3 velocity = { }; string color = "red"; end_script_variables script void Honk() writeln(color, " car honks"); end_script end_script_struct on_initialize # Create a new instance of the struct Car car = Car(); # Clone the new instance Car clone = Car(car); # Assign some values. car.color = "blue"; car.position.Set(39, -90, 125.0); car.velocity.Set(20, 0, 0); # Call a script car.Honk(); # Print the contents of the struct writeln(car); end_on_initialize **output**:: blue car honks struct({"position": 39:00:00.0n 90:00:00.0w 125, "velocity": (20, 0, 0), "color": blue}) Another test that shows a struct being used as a container type .. parsed-literal:: script_struct Cat script_variables string name = "unknown"; int livesLeft = 9; end_script_variables script int UseA_Life() if (livesLeft > 0) livesLeft -= 1; if (livesLeft <= 0) { writeln("So sorry, ", name, " has used all of its lives"); } return livesLeft; end_script end_script_struct on_initialize Cat cat1 = { }; cat1.name = "fluffy"; Cat cat2 = { }; cat2.name = "morris"; cat1.UseA_Life(); cat1.UseA_Life(); cat1.UseA_Life(); cat1.UseA_Life(); cat1.UseA_Life(); cat1.UseA_Life(); cat1.UseA_Life(); cat1.UseA_Life(); int i1 = cat1.UseA_Life(); writeln(cat1.name, " has ", cat1.livesLeft, " lives left"); if (i1 != 0) { writeln("-FAIL- fluffy should have 0 lives left, but has ", i1); } int i2 = cat2.UseA_Life(); writeln(cat2.name, " has ", cat2.livesLeft, " lives left"); if (i2 != 8) { writeln("-FAIL- morris should have 8 lives left, but has ", i1); } # Some simple tests of Cats as container members. Not a full-blown test, # but at least it checks compilation. Array catArray = { }; catArray.PushBack(cat1); catArray.PushBack(cat2); writeln("CatArray: ", catArray); writeln("foreach over catArray"); foreach (Cat cat in catArray) { writeln(" cat=", cat); } Map catMap = { cat1.name : cat1, cat2.name : cat2 }; writeln("Cat Map: ", catMap); writeln("foreach over catMap"); foreach (string name : Cat cat in catMap) { writeln(" ", name, " ", cat); } Set catSet = { cat1, cat2 }; writeln("Cat Set: ", catSet); writeln("foreach over catSet"); foreach (Cat cat in catSet) { writeln(" cat=", cat); } end_on_initialize **output**:: So sorry, fluffy has used all of its lives fluffy has 0 lives left morris has 8 lives left CatArray: {struct({"name": fluffy, "livesLeft": 0}), struct({"name": morris, "livesLeft": 8})} foreach over catArray cat=struct({"name": fluffy, "livesLeft": 0}) cat=struct({"name": morris, "livesLeft": 8}) Cat Map: {fluffy : struct({"name": fluffy, "livesLeft": 0}), morris : struct({"name": morris, "livesLeft": 8})} foreach over catMap fluffy struct({"name": fluffy, "livesLeft": 0}) morris struct({"name": morris, "livesLeft": 8}) Cat Set: {struct({"name": fluffy, "livesLeft": 0}), struct({"name": morris, "livesLeft": 8})} foreach over catSet cat=struct({"name": fluffy, "livesLeft": 0}) cat=struct({"name": morris, "livesLeft": 8}) struct on the fly ================= .. warning:: This example uses the old syntax for creating an instance of a struct and accessing the variables and methods. **This is not type-safe** and should be avoided unless you need to dynamically add new variables to the struct. .. parsed-literal:: # A struct is best used with the basic types (int, double, bool, string). However, # it can be used to contain the data of complex types (WsfPlatform, WsfGeoPoint, etc) # script_variables WsfGeoPoint point1 = WsfGeoPoint(); point1.Set(0,0,1); end_script_variables platform test WSF_PLATFORM on_initialize2 # Empty structs can be created and used like this: struct container = struct(); container->a = 1.0; # Gets recognized as a double container->b = 5.0; # Gets recognized as a double container->c = "test1"; # Gets recognized as a string container->d = 10; # Gets recognized as an int container->e = false; # Boolean equal to false container->x = (string)"test2"; # type cast to a string (overkill) container->y = (double)10; # force a type cast number without a decimal point to a double container->z = (string)"500"; # type cast to a string (overkill) container->p1 = point1; # bring in an external complex type variable container->p2 = WsfGeoPoint(); # Create an empty GeoPoint complex type container->p3 = WsfGeoPoint.Construct(0,0,0); # Create a GeoPoint that has an LLA writeln(container); # The whole container can be passed around as one object... **# THE ONLY PERIOD "." METHODS AVAILABLE WHEN USING THE "->" OPERATOR ON COMPLEX TYPES** **# ARE ToString(), IsValid(), and IsNull().** writeln("p1 in container is ", container->p1.ToString() ); writeln("p2 in container is ", container->p2.ToString() ); writeln("p3 in container is ", container->p3.ToString() ); # The following illustrates how to update objects in a container. # If a struct variable is a complex type, a typical period "." method CANNOT # be used directly on the variable because the type is not known using the "->" operator. container->a = container->a + 1; # Add 1 to var a. Since it is not using a ".", it will work. #container->p2 = container->p2.Set(0,0,2); # Set p2 to a new LLA **#WRONG - THIS LINE WILL FAIL** #Use one of these: ((WsfGeoPoint)container->p2).Set(0,0,2); # Cast to WsfGeoPoint and call Set(); OR: WsfGeoPoint p2 = container->p2; # Get value and call Set() p2.Set(0,0,2); #container->p3.Set(0,0,3); # Set p3 to a new LLA **# WRONG - THIS LINE WILL FAIL** ((WsfGeoPoint)container->p3).Set(0,0,3); # Cast to WsfGeoPoint and call Set(); OR: WsfGeoPoint p3 = container->p3; p3.Set(0,0,3); writeln("p2 in container after updating is ", container->p2.ToString() ); writeln("p3 in container after updating is ", container->p3.ToString() ); end_on_initialize2 end_platform **output**:: struct({"p1": WsfGeoPoint, "z": 500, "e": 0, "d": 10, "a": 1, "p3": WsfGeoPoint, "y": 10, "c": test1, "p2": WsfGeoPoint, "x": test2, "b": 5}) p1 in container is 00:00:00.0n 00:00:00.0e 1 p2 in container is 00:00:00.0n 00:00:00.0e 0 p3 in container is 00:00:00.0n 00:00:00.0e 0 p2 in container after updating is 00:00:00.0n 00:00:00.0e 2 p3 in container after updating is 00:00:00.0n 00:00:00.0e 3 Using a map containing a struct =============================== .. warning:: This example uses the old syntax for creating an instance of a struct and accessing the variables and methods. **This is not type-safe** and should be avoided unless you need to dynamically add new variables to the struct. .. parsed-literal:: platform TEST_VEHICLE WSF_PLATFORM add processor script_proc WSF_SCRIPT_PROCESSOR script_variables struct myContainer = struct(); # Make a struct named myContainer myContainer->counter = 1; # One field being a counter myContainer->JustAColor = "Gray"; # Another field with a string myContainer->JustANumber = 0; # Any number myContainer->MaxNumber = 50; # A maximum number end_script_variables update_interval 1 sec on_update extern struct myContainer; # Bring in the struct "myContainer" myContainer->AirplaneType = "F-18"; # Add a member to myContainer" Map MyMapWithStruct = Map(); # Create a map of a struct MyMapWithStruct[0] = myContainer; # Set index 0 of the map to the contents of myContainer foreach (int aKey : struct aData in MyMapWithStruct) { writeln("key, data ", aKey, ", ", aData); myContainer->JustANumber = MATH.Roll(1,10); if(myContainer->counter >= 25) myContainer->JustAColor = "Blue"; if(myContainer->counter >= (myContainer->MaxNumber - 5) ) WsfSimulation.Terminate(); myContainer->counter = myContainer->counter + 1; } end_on_update end_processor end_platform See Also ======== :class:`struct` - struct script class