Living Scenery Technology Developer Documentation

Overview

Living Scenery Technology, referred to as LST, is an X-Plane plugin enabling movement of objects along a route, and manipulation of datarefs which can be used to drive more complex animations. It serves a purpose similar to that of Marginal's GroundTraffic, but with enhanced capabilities. LST's features include:

  • Creation of datarefs
  • Setting of datarefs via simple mathematical operations with 2 operands
  • Setting of datarefs by keyframing them to another dataref
  • Capping of datarefs to a min/max value
  • Simple menu system to allow users to trigger dataref changes (typically to drive animations)
  • Placing of static objects in the world (allowing access to systems such as the particle system and sound systems)
  • Pilot Controlled Lighting that triggers a dataref (which can drive animated lights)
  • Animation of objects along a route

LST "Packages" enable these features. Packages are simply an element in an XML file. There can be many XML files per scenery, and many packages per XML file, though the web editor only supports one package per XML. Each package file must end in .lst.xml for the LST plugin to recognize it. Each package file must have a north/south/east/west boundary, the package will only be active when the user's aircraft is within this zone. Packages can also specify a minimum version of LST required, and they can specify a "priming time", which allows them to "prime" routes with objects at a much faster speed (1 second per frame) for a given duration, so they are fully populated with objects before they show.

LST features can be configured via the web editor. Routes however are configured via WED shapes (more on this in the route section), so you can see routes in relation to your scenery. Routes will show in a Leaflet map in the editor, however this is only for a sanity check that they were imported properly. All fields should be clearly labelled, and the interface should be simple to navigate. The purpose of this article is not to explain the parameters, rather, it is to explain what these features do. The parameters are explained via their names, and tooltips in the editor, and each section in this article corresponds to a section in the editor.

Notes about The Editor

When using the editor, you will need to choose your Package.lst.xml via File > Open, and save it via File > Save. You will likely get a security warning about XMLs being a dangerous file type - this is normal, XML is simply a convention of transporting dangerous, in and of itself there is nothing dangerous about them. Please note that your data is never uploaded, the Javascript code runs in your web browser. In fact, you could save the whole site and run it all locally if you really wanted!

Definitions

Some common terms will be used frequently through this article, you should be aware of what they mean:

  • Operand: This is a value, either a number, or the name of another dataref. If a dataref, it must be a numeric dataref.
  • Operator: This is either a binary math operator (+ - / * %), or a binary comparison operator (< > <= >= = !=)
  • Dataref: This is a value in the sim that animations can be keyframed to and other behaviors can be affected by

Please note all units are metric.

Static Objects

A static object exists in the world, it's always there until the package deactivates. It's primary purpose is to enable access to the particle system, and FMOD, which are gated to plugin and aircraft objects. You set the resource, position, and orientation.

Menus provide a way for users to trigger a dataref. They have 3 types:

  • Menu: This is a "container" of sorts, it's children are what do something.
  • Item: This is an entry in a menu that triggers a dataref when the user clicks it
  • Separator: This is purely visual, to separate elements in a menu

An example of this is a user clicking "X-Codr Designs KTEX > Hangars > Hangar 1 Door", "X-Codr Designs KTEX" is the top level menu, "Hangars" is a child of the top menu, and is a menu. "Hangar 1 Door" is an item that when the user clicks, will trigger a dataref

Items trigger a dataref to transition from 0 to 1 for their on state, or 1 to 0 for their off state. You can specify a transition time (how long it takes to go from it's current value to the target), as well as a priority (if two things try to set a dataref, the one with the higher priority will be the one that controls the dataref)

Dataref Creation

A dataref is a value in the sim. You can keyframe animations, or even other behaviors to a dataref. Before you can use a dataref, you must create it. Datarefs in LST are doubles, there is no choice here. You simply must provide a name, this should be something like "myPackage/hangar_1_door". Spaces are not permitted.

Dataref Math Formulas

A dataref can be set via a simple math expression. A math expression is in the form of Operand 1, Operator, Operand 2. Operands can be either a number, or another dataref, and the operator can be + - / * or % (remainder or modulus). These work exactly like they do in normal math. You can also perform multiple math formulas on a single dataref, they are evaluated in the order they appear in the editor.

Dataref Caps

A dataref can be constrained to never go below, or above, a minimum and maximum value.

Dataref Keyframes

A dataref can be keyframed to another dataref. Keyframing sets a target, the dataref to set, based on the driver, the value we are watching. Each keyframe element has a series of keyframes that set the target to a given value when the driver is at a given value, these are interpolated between.

For example, I could keyframe dataref myPackage/dref1 to myPackage/dref2, with the keyframes of target = 5 when driver = 1 and target = -5 when driver = 2. In this scenario, when driver is 1, target is 5, when driver is 1.25, target is 2.5, when driver is 1.5, target is 0, and when target is 2, target is -5.

One important note: Your keyframes must be in order based on the driver! I.e. you cannot have keyframes target=5 when driver=2 and target=-5 when driver=1. If your keyframes are not ordered, the behavior is undefined.

Pilot Controlled Lighting

Real pilot controlled lighting operates by a pilot tunning their comm to an airports UNICOMM/CTAF, pressing their PTT button a given number of times in a given time period, and the runway lights turn on. Some airports let the pilots set a higher intensity with more clicks, i.e. 3 clicks in 5 seconds for low intensity, 5 clicks in 5 seconds for medium intensity, and 7 clicks in 5 seconds for high intensity.

LST's PCL system follows the real system. You specify the frequency in Hz (i.e. 122800), the lat/lon of the listening station, the range it can detect PTT clicks (in KM), the time period the user must click PTT in, how many clicks are required for each intensity, and how long the lights will stay on after they've been enabled. You will also need to set a target dataref - you will use this dataref in your custom runway/taxi light objects to show/hide the light.

Routes

Before we discuss how to create routes, it is important to understand what routes are. Routes are a series of waypoints, and an optional "spawner". Objects traverse these routes until they reach the end of a route, at which point they either disappear, or go back to the start. When objects are traversing routes, they can trigger datarefs, pause for a time or condition, reverse their heading (for backing up), or branch to other routes. Additionally, routes can enable collision checking, objects will slow down to avoid colliding with other objects.

Spawners

Highway Spawner

This spawns a stream of objects between a given min and max time. When objects reach the end of the route, they disappear.

Loop Spawner

This spawns a single object, once when the package is loaded. This object will never despawn, and when it reaches the end of a route, will progress back to the start. Note, the loop parameter applies to the route, it isn't attached to the object. If the object branches off from this route, it will behave like one spawned by a highway spawner.

Train Spawner

This spawns a variable number of objects, each with an offset. The lead car is referred to as the train, and the subsequent cars are referred to as train cars. Train cars will always follow the train, and point towards the car in front of them. Each train car will have an offset in meters from the car in front of it. Trains are excluded from branching features.

Dataref Setting

When an object reaches a waypoint, it can trigger setting a dataref to a given value, over a given time, with a given priority. If a number between 1 and 10 is provided instead of a dataref, an instance specific dataref (lst/anim_obj_1 through lst/anim_obj_10) will be set, rather than a global dataref. The value to set can be a number of another dataref.

You can also choose to cycle a dataref, this works just like setting, but will then return to 0 at the same rate it was set to the target. This is good for things like a door opening then closing.

Waiting

When an object reaches a waypoint, it can either pause of a time period (i.e. waiting 3 seconds at a stop sign), or wait for a condition (i.e. dataref myPackage/rail_crossing_1 = 0), before proceeding

Branching

When an object reaches a waypoint, it can branch to a different route, either every time, based on a random chance, or based on a condition. This is useful to allow you to say, spawn all your cars at an airport at the entrance highway, then have some take off ramps to other roads, and propagate throughout the airport.

Orientation Control

You can set the following flags for each waypoint, which are interpolated between their value at this waypoint, and their value at the next:

  • Altitude
  • Pitch
  • Roll
  • Pitchless (think a gondola hanging from a cable, it won't pitch from the underlying terrain)
  • Linear Altitude (again, think a gondola hanging from a cable, it won't move up and down with the terrain, it will go straight along the cable)

Creation in WED

Routes in LST are created with Shapes in WED. WED shapes are not exported as a scenery element, rather, they are exported into a separate doc.osm file. Vehicles flow in the direction of the shape (as indicated by the arrow). Each route has properties, settable in the properties panel in WED, these define the route properties. Additionally, each waypoint has properties, these define the properties of each waypoint. Unfortunately, properties in WED are a single line of text, so to chain multiple commands, separate them with a ;. It may be helpful to write the command in an external text editor and simply paste it into the property in WED.

To import these routes into the LST editor, use Edit > Import WED Shapes and select the "doc.osm" in your scenery root folder.

Please note: You cannot import the shapes from the project back into WED, it is a one way conversion.

Route Properties

These commands correspond to the previously discussed concepts. Substitute the parameter names for an appropriate value. Commas are used to separate parameters, ; to separate commands. Command names are case-insensitive

  • Highway Spawner: HIGHWAY,object_resource.obj,min spawn time,max spawn time
  • Loop Spawner: LOOP,object_resource.obj
  • Train Spawner: TRAIN,object_resource.obj; TRAINCAR,object_resource.obj,offset in meters
  • Collision Enabling: DoCollisions

The route name comes from the name you set for the route in WED.

Waypoint Properties

These commands correspond to the previously discussed concepts. Substitute the parameter names for an appropriate value. Commas are used to separate parameters, ; to separate commands. Command names are case-insensitive

  • Dataref Setting: SET, target dataref, value, transition time, priority or smooth (true/1); when both are needed, put smooth 6th
  • Dataref Cycle: CYCLE, target dataref, value, transition time, priority or smooth (true/1); when both are needed, put smooth 6th
  • Wait: WAIT,seconds
  • Conditional Wait: WAIT,operand 1, comparison operator, operand 2
  • Branching: BRANCH_Chance 0-1
  • Conditional Branching: BRANCHIF_operand 1, operator, operand 2
  • Altitude: Alt,meters
  • Pitch: Pitch,degrees
  • Roll: Roll,degrees
  • Linear Altitude: GONDOLASTART (note this is enabled until a waypoint with GONDOLAEND)
  • Pitchless: PITCHLESSSTART (note this is enabled until a waypoint with PITCHLESSEND

Branch Targets

You may have noticed the BRANCH commands are missing a target route - that is because having to set this manually would be extremely cumbersome. Instead, the target route is automatically determined by what route(s) have their first node colocated with this node. You can have multiple branch targets, though I would strongly discourage this for anything but chance branches as it is difficult to understand what is intended with them all overlapping, so you may not get the results you expect.

Route Behaviors and Customization

When objects move along on a route, they will curve smoothly, with a given turn radius. They will also accelerate, and decelerate smoothly, at fixed rates. When in collision avoidance mode, objects will scan for other objects that are/will be in their path, and the object furthest from the intersection will slow down to avoid hitting the other object (please note collision enabled routes that are too tight can create deadlocks and resource leaks!).

All these values customized with a .lst file for each name (i.e. mySedan.obj can have properties customized with mySedan.lst in the same folder). The format of this file is very simple, simply property=value, with one pair per line. The current values that can be customized are:

  • collisionPassingDistance: this is how close this object can pass to another. Specifically, how close the closest points on their projected routes can be before it is considered a collision
  • collisionDistance: this is how far an object must stay from another object if it is considered to collide with it.
  • turnRadius: this is how far away from a waypoint this object must start its smooth turn (this is internally adjusted based on the sharpness of the turn, set it for a value appropriate for a 90 degree turn)
  • accelRate: Desired meters per second when accelerating
  • decelRate: Desired meters per second when decelerating, this will be bypassed to avoid a collision
  • soundObject: The object to draw when within range for sounds, must be in the same folder.
  • soundRange: How close you must be for the sound object to be spawned

FMOD sounds have a limit of how many tracks can be played at once, therefore, to avoid running out of tracks, objects with sound must be aggressively loaded and unloaded. Therefore, you can specify an object that has the attached FMOD sounds, and how close you must be to the main object in order for the sound object to be loaded. While it is a different object, it will inherit the same position, orientation, and instance variables as the parent, which behaves normally.

Examples

You can download an example project here. This project demonstrates how to use various route features in WED, and how to use various features of LST in the web editor.

For Programmers

I highly encourage all users to use the web editor. But, if you are an adventurous developer, you CAN create your own LST files programmatically! But I won't help you ;). Ok actually I will, you can download the xml schema file from https://cdn.x-codrdesigns.com/lst-2.0.xsd, this tells you everything you need to know about the LST format. And if you have questions, feel free to shoot me a message/email from the support page!

Per Object Customization

Certain behaviors can be customized on a per-object basis. To do so, create a file with the same name as the .obj in the same folder, and give it the .lst extension. I.e. Sedan_Red.lst for Sedan_Red.obj. Inside that folder, you can specify customized values in the key=value form (keys are not case sensitive). The customizable behaviors are:

  • Range This is how far the object will draw from the camera, similar to a LOD. Moving objects in sim is expensive, so I recommend keeping this as low as reasonably possible. Defaults to 2500 meters.
  • SoundObject This is the name of an object in the same folder that has sounds. Since there is a limited number of sounds that can be played at once, this allows you to have objects with sound that only are draw/played when you are in a given range. Defaults to none.
  • SoundRange How close you must be to the object for the sound object to be displayed/played. Defaults to 0.
  • MinSpacing How far this object must stay from other objects if collisions are enabled. Defaults to 6.
  • MinSpacingRand How much variance there is in MinSpacing on a per-instance basis. Spacing can be up to half this amount greater, or half this amount less than MinSpacing (i.e. MinSpacing of 10 and MinSpacingRand of 5 yields a range of 7.5-12.5 for potential spacing values for each instance of this object). Defaults to 0.
  • MinLateralSpacing When doing collision calculations, how close two objects can pass without directly colliding before MinSpacing is factored in. Think of this as the width of the vehicle. Defaults to 0.75.
  • Accel How fast this object should accelerate in meters per second. Set to 0 to simply snap to the speed
  • AccelRand How much variance there is in Accel on a per-instance basis, works like MinSpacingRand
  • Decel Same as Accel, but for deceleration.
  • DecelRand Same as AccelRand, but for deceleration.
  • TurnRadius Distance in meters from a node that this object starts turning to the next route. Note this is always the lesser of this and 1/2 the length of the shortest of the current and next legs.