<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.trainzsimulator.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Windwalkr</id>
	<title>TrainzOnline - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.trainzsimulator.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Windwalkr"/>
	<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/wiki/Special:Contributions/Windwalkr"/>
	<updated>2026-11-05T06:50:45Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.46.2</generator>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=Help:VE173&amp;diff=45890</id>
		<title>Help:VE173</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=Help:VE173&amp;diff=45890"/>
		<updated>2026-02-04T04:39:10Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: Created page with &amp;quot;=Material &amp;#039;$(MATERIAL)&amp;#039; in mesh &amp;#039;$(FILE)&amp;#039; is not of a recognised material type.=  This error occurs when loading a legacy Trainz IM mesh file, or when importing from an [[FBX ...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Material &#039;$(MATERIAL)&#039; in mesh &#039;$(FILE)&#039; is not of a recognised material type.=&lt;br /&gt;
&lt;br /&gt;
This error occurs when loading a legacy Trainz IM mesh file, or when importing from an [[FBX file format|FBX mesh source file]]. It indicates that the mesh contains a [[Material Types|material type]] which is not supported by the game. Material types are typically determined by interpreting the material&#039;s name (as configured in the modelling program that created the file), however this may be overridden using a [[Mesh metadata file]].&lt;br /&gt;
&lt;br /&gt;
==FBX Mesh Source Files==&lt;br /&gt;
The FBX mesh importer first checks for a &#039;material-type&#039; tag in the mesh metadata file, if any. If present, this is used verbatim. Otherwise, it looks for the last occurrence of a period (&amp;quot;.&amp;quot;) character in the material name, and then uses the characters after that as the material type. From [[trainz-build]] v4.6 onwards, the importer also checks for a underscore (&amp;quot;_&amp;quot;) character if no period is present, and applies the same logic; this is to support the Maya LT modeller which doesn&#039;t allow periods in material names.&lt;br /&gt;
&lt;br /&gt;
The comparison is case sensitive. The supported material types are:&lt;br /&gt;
* tbumptex&lt;br /&gt;
* tbumpenv (prior to trainz-build v5.6)&lt;br /&gt;
* gloss (prior to trainz-build v5.6)&lt;br /&gt;
* tbumpgloss (prior to trainz-build v5.6)&lt;br /&gt;
* reflect (prior to trainz-build v5.6)&lt;br /&gt;
* onetex&lt;br /&gt;
* notex (prior to trainz-build v5.6)&lt;br /&gt;
* additive&lt;br /&gt;
* pbrmetal (at or above v4.6)&lt;br /&gt;
* pbrmetalmasked (at or above v4.6)&lt;br /&gt;
* pbrmetaldetail (at or above v4.6)&lt;br /&gt;
* leafcard (at or above v5.6)&lt;br /&gt;
* clutter (at or above v4.6)&lt;br /&gt;
* glass (at or above v4.6)&lt;br /&gt;
* leafcardbillboard (at or above v5.6)&lt;br /&gt;
* foliage (at or above v5.4)&lt;br /&gt;
&lt;br /&gt;
Unknown material types result in a warning at trainz-build versions prior to v4.6, and an error since then.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Legacy Trainz IM Mesh Files==&lt;br /&gt;
The mesh file reader looks for the last occurrence of a period (&amp;quot;.&amp;quot;) character in the material name, and then uses the characters after that as the material type. The comparison is case sensitive. The supported material types are:&lt;br /&gt;
* tbumptex&lt;br /&gt;
* tbumpenv&lt;br /&gt;
* gloss&lt;br /&gt;
* tbumpgloss&lt;br /&gt;
* reflect&lt;br /&gt;
* onetex&lt;br /&gt;
* notex&lt;br /&gt;
&lt;br /&gt;
Unknown material types result in a warning.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Validation Errors]]&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=DXT_Compression&amp;diff=45558</id>
		<title>DXT Compression</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=DXT_Compression&amp;diff=45558"/>
		<updated>2025-11-24T00:38:51Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: Remove some incorrect info.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The following are the DXT formats used in the Trainz (N3V) binary textures.&lt;br /&gt;
&lt;br /&gt;
===DXT1 Compression=== &lt;br /&gt;
DXT1 stores 16 input pixels in 64 bits of output, consisting of two 16-bit RGB 5:6:5 colour values and a 4x4 two bit lookup table.&lt;br /&gt;
&lt;br /&gt;
If the first colour value (c0) is numerically greater than the second colour value (c1) then the two other colours are calculated, such that&lt;br /&gt;
 &lt;br /&gt;
c2 = 2/3*c0 + 1/3*c1 and c3=1/3*c0 + 2/3*c1&lt;br /&gt;
&lt;br /&gt;
Otherwise if c0 &amp;amp;lt;= c1 then c2 = 1/2*c0 + 1/2*c1 and c3 is transparent.&lt;br /&gt;
&lt;br /&gt;
The lookup table is then consulted to determine the colour value of each pixel, with a value of 0 corresponding to c0 and a value of 3 corresponding to c3. DXT1 does not store alpha data enabling higher compression ratio of 8:1. DXT1 can be used for masked alpha textures.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===DXT3 Compression=== &lt;br /&gt;
DXT3 converts 16 input pixels to 128 bits of output, consisting of 64 bit of alpha channel data (four bits for each pixel) followed by 64 bits of colour data encoded the same way as DXT1 (with the exception that the 4 colour version of DXT1 algorithm is always used instead of deciding which version to use based on the relative values of c0 and c1). &lt;br /&gt;
&lt;br /&gt;
Typically DTX3 is well suited to images with sharp alpha transitions, between translucent and opaque areas. Compression ratio is 4:1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===DXT5 Compression=== &lt;br /&gt;
DXT5 converts 16 input pixels to 128 bits of output, consisting of 64 bits of alpha channel data (two 8 bit alpha values and a 4x4 3 bit lookup table) followed by 64 bits of colour data (encoded the same way as DXT3).&lt;br /&gt;
If a0 &amp;amp;gt; a1, then six other alpha values are calculated, such that&lt;br /&gt;
&lt;br /&gt;
a2 =(6a0 + a1)/7, a3 =(5a0 + 2a1)/7, a4 =(4a0 + 3a1)/7, a5 =(3a0 + 4a1)/7, a6 =(2a0 + 5a1)/7, a7 = (a0 + 6a1)/7&lt;br /&gt;
&lt;br /&gt;
Otherwise, if a0 &amp;amp;lt;= a1, four other alpha values are calculated as&lt;br /&gt;
&lt;br /&gt;
a2 =(4a0 + a1)/5, a3 =(3a0 + 2a1)/5, a4 =(2a0 + 3a1)/5, a5 =(a0 + 4a1)/5, with a6 = 0, and a7 = 255.&lt;br /&gt;
&lt;br /&gt;
The lookup table is then consulted to determine the alpha values for each pixel, with a value of 0 corresponding to a0 and a value of 7 corresponding to a7. &lt;br /&gt;
&lt;br /&gt;
Because DXT5 uses an interpolated alpha scheme it generally produces superior results for alpha (transparency) gradients than DXT3. &lt;br /&gt;
&lt;br /&gt;
Some consider DXT5 to be the most flexible general purpose compression codec. Compression ratio is 4:1.&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=Texture_file&amp;diff=43263</id>
		<title>Texture file</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=Texture_file&amp;diff=43263"/>
		<updated>2024-10-01T04:37:05Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{ORP-top}}&lt;br /&gt;
Trainz &#039;&#039;&#039;Texture files&#039;&#039;&#039; are ASCII text format specification files describing a single texture. Texture files have a &amp;quot;.texture.txt&amp;quot; name extension, however when a texture file is specified within a [[config.txt file]] or similar, the &amp;quot;.txt&amp;quot; must be omitted (as you are specifying a resource name, not a file path), leaving only the &amp;quot;.texture&amp;quot; extension.&lt;br /&gt;
&lt;br /&gt;
Texture files (*.texture.txt) should be distinguished from [[image file]]s (*.tga, etc.) and [[material]]s. A material may utilize zero or more texture files, and a texture file may utilize one or more image files. While we often refer to the image data as &amp;quot;a texture&amp;quot;, this usage isn&#039;t strictly correct as any given texture also has a number of metadata attributes which are not present in the source image. Additionally, a texture may be compressed (at installation time) which may actually lose some of the data originally present in the source image.&lt;br /&gt;
&lt;br /&gt;
When importing a [[trainzmesh file]] from an [[FBX file]], any image files referenced in the FBX which do not already have corresponding texture files will have generic texture files created automatically. These files may be suitable for basic purposes, but may need to be customized for more advanced functionality. Once the file has been created (and optionally customised) the importer will not recreate/overwrite it on subsequent runs.&lt;br /&gt;
&lt;br /&gt;
This page describes [[&amp;quot;Trainz-build&amp;quot; number|content format v5.6]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=File format=&lt;br /&gt;
&lt;br /&gt;
The user-editable *.texture.txt files are ASCII text formatted key-value pairs with the following options. Please note that this format is not the same (despite some similarities) as other text-based formats used by Trainz. Please be aware of the [[filename character restrictions]] when naming texture and image files.&lt;br /&gt;
&lt;br /&gt;
;Syntax&lt;br /&gt;
Each key is specified on a new line. There is no white space anywhere in the line. A empty value is sometimes valid. The syntax is:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;key&amp;gt;=&amp;lt;value&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Example:&lt;br /&gt;
 Primary=WayCoolTexture.tga&lt;br /&gt;
 Alpha=WayCoolTexture.tga&lt;br /&gt;
 Tile=st&lt;br /&gt;
 UsageHint=albedo&lt;br /&gt;
 AlphaHint=semitransparent&lt;br /&gt;
 MipAlgorithm=heavy-alpha&lt;br /&gt;
&#039;&#039;(Example only, not recommended settings)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Keys and Values==&lt;br /&gt;
&lt;br /&gt;
 Primary=diffusemap.bmp&lt;br /&gt;
&lt;br /&gt;
This tag specifies the filename of the image file representing the color (R, G, B) channels of the texture. Any alpha channel in the image file is ignored. The resultant texture will have a pure white (100%) alpha channel.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Primary=diffusemap.jpg&lt;br /&gt;
 Alpha=diffusemap.bmp&lt;br /&gt;
&lt;br /&gt;
This tag combination specifies the filenames of the image file representing the color (R, G, B) channels of the texture (Primary) and the image file representing the transparency of the texture (Alpha). The Alpha image should be grayscale. Neither file should contain an alpha (A) channel (ie, both images should be 24-bit). The two image files must be of identical size.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Primary=diffusemap.tga&lt;br /&gt;
 Alpha=diffusemap.tga&lt;br /&gt;
&lt;br /&gt;
This tag combination specifies the filename of a single image file representing the color and transparency (R, G, B, A) channels of the texture. In this case both tags must reference the same filename. The image file must contain an alpha channel.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Compression=dxt3&lt;br /&gt;
&lt;br /&gt;
This tag hints the usage of a particular texture compression scheme. If you don&#039;t have a specific effect in mind, don&#039;t include this tag. Valid options are currently &#039;none&#039;, &#039;dxt1&#039;, &#039;dxt3&#039;, &#039;dxt5&#039;. Refer [[DXT Compression]].&lt;br /&gt;
&lt;br /&gt;
The current selection logic for texture compression is as follows, however it should be noted that this may change between Trainz versions. The first matching rule is used.&lt;br /&gt;
&lt;br /&gt;
* Special texture formats (such as HDR) which don&#039;t support compression are stored uncompressed.&lt;br /&gt;
* &amp;quot;Compression=none&amp;quot; forces no compression. This gives the best visual result for a given input image, but typically yields worse visual results per output texture filesize. It is often better to activate compression and double the image dimensions, rather than disabling compression.&lt;br /&gt;
* Images with an &amp;quot;opaque&amp;quot; alpha hint use DXT1 compression.&lt;br /&gt;
* &amp;quot;Compression=dxt3&amp;quot; will use DXT3 compression.&lt;br /&gt;
* DXT5 compression is used.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 NormalMapHint=normalmap&lt;br /&gt;
&lt;br /&gt;
The &#039;NormalMapHint&#039; tag allows the texture to be specified as a [[normal map]]. By default, Trainz will assume that your texture is a [[diffuse map]] and will apply some processing options which are not appropriate for normal maps. You must specify this option for normal maps. Valid options are &#039;none&#039; and &#039;normalmap&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 ModifyMap=flipgreen&lt;br /&gt;
&lt;br /&gt;
The &#039;ModifyMap&#039; option allows a texture&#039;s green color channel to be flipped.  Some programs such as [[Autodesk 3ds Max]] create [[normal map]]s with the Y axis facing the opposite way to what is expected by the Trainz shaders.  This option can be used to make the bump effect look correct in Trainz. Valid options are &#039;none&#039; and &#039;flipgreen&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 AlphaHint=opaque&lt;br /&gt;
&lt;br /&gt;
The &#039;AlphaHint&#039; tag allows you to force a particular alpha mode on the texture. Valid options are &#039;opaque&#039; (meaning that the alpha channel is overwritten with pure white), &#039;semitransparent&#039; (meaning that the alpha channel is a grayscale blend) and &#039;masked&#039; (meaning that the alpha channel is clamped to a pure black&amp;amp;white bitmap based on a 50% threshold.) If omitted, Trainz will supply an appropriate value for this tag based on the actual contents of the Alpha channel.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Tile=st&lt;br /&gt;
&lt;br /&gt;
Tiling refers to the ability for texture coordinates outside the range of (0.0 .. 1.0) to be treated as valid coordinates on an infinitely tiled texture. With tiling active, coordinates which pass the right/bottom side of the texture effectively wrap back onto the left/top side, and so on. Valid options include &#039;s&#039; (tile horizontally), &#039;t&#039; (tile vertically), &#039;st&#039; (tile both horizontally and vertically), and &#039;none&#039; (do not tile the image).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 UsageHint=albedo&lt;br /&gt;
&lt;br /&gt;
Textures are processed slightly differently depending on their intended use in the rendering pipeline. Valid options are &#039;albedo&#039;, &#039;normal&#039;, and &#039;parameter&#039;. If no usage hint is supplied, the game will attempt to guess the ideal processing steps based on other clues, which may lead to undesirable outcomes if the guesses are wrong.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 MipAlgorithm=weight-by-alpha&lt;br /&gt;
&lt;br /&gt;
Specifies the [[mipmap]] generation algorithm to use for the texture. Valid options are &#039;weight-by-alpha&#039;, &#039;no-weight-by-alpha&#039;, and &#039;heavy-alpha&#039;. If not specified, the &#039;UsageHint&#039; for the texture is consulted to determine the default behaviour; for albedo textures the &#039;weight-by-alpha&#039; mechanism is used, while other textures default to &#039;no-weight-by-alpha&#039;. The &#039;weight-by-alpha&#039; mechanism treats the alpha channel as an opacity and prioritizes opaque texels over transparent ones. The &amp;quot;no-weight-by-alpha&amp;quot; hint can be used to ensure that the game will give equal weighting to texels regardless of their alpha channel, which is desirable if the alpha channel does not represent opacity. The &#039;heavy-alpha&#039; mechanism effectively increases the alpha channel on lower mip levels, which is useful on semitransparent foliage (eg. most trees) to avoid the tree appearing overly transparent in the distance.&lt;br /&gt;
&lt;br /&gt;
The value of this key is only relevant where [[Content Manager]] is responsible for producing mipmap images. It is not relevant on any mipmap images provided in the source images.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 nonpoweroftwo=1&lt;br /&gt;
&lt;br /&gt;
By default, all textures must have both their width and height as a power of two (eg. 8, 16, 32, 64, 128, 256, 512, 1024, 2048), though they need not be square. Setting the value &#039;1&#039; for the &#039;nonpoweroftwo&#039; key allows this restriction to be relaxed. This is currently considered experimental and may have unexpected performance, quality, or functionality outcomes. It is not recommended that end-users utilize this format at the current time.&lt;br /&gt;
&lt;br /&gt;
Non-power-of-two (NPOT) textures may not support mipmapping and thus may be noticeably affected by the moire effect in addition to having higher overall GPU bandwidth requirements.&lt;br /&gt;
&lt;br /&gt;
=Texture Formats=&lt;br /&gt;
The following texture formats are supported internally by Trainz on desktop platforms.&lt;br /&gt;
* R8 G8 B8 A8&lt;br /&gt;
* DXT1&lt;br /&gt;
* DXT3&lt;br /&gt;
* DXT5&lt;br /&gt;
* R32F G32F B32F A32F&lt;br /&gt;
&lt;br /&gt;
The selection of internal format depends on the source image format and the value of the &#039;Compression&#039; key.&lt;br /&gt;
&lt;br /&gt;
=Texture Size=&lt;br /&gt;
Textures must be no more than 4096 pixels in either dimension, although it is strongly recommended that textures are kept below this maximum to avoid performance problems. Small objects should typically use approximately 512x512. Large, highly detailed objects such as train vehicles or ground textures will typically use 2048x2048.&lt;br /&gt;
Uniform-color textures (ie. textures in which all [[texel]]s have the same color) should be 8x8, 2x2, or 1x1.&lt;br /&gt;
Textures must be a power-of-two size in each dimension (unless the &#039;nonpoweroftwo&#039; key is activated), but need not be square. Some materials may give unexpected results for non-square textures; consult the material-specific documentation for details.&lt;br /&gt;
&lt;br /&gt;
=Source Image Formats=&lt;br /&gt;
The following image formats are acceptable as source data for the texture file. Note that these formats are not used at runtime, and that format-specific benefits such as compression will apply to the DLS download size of the content but not to the runtime memory footprint or GPU bandwidth usage.&lt;br /&gt;
&lt;br /&gt;
* Targa (.tga) files. Targa is a lossless image format with optional compression and optional alpha channel. This is a sensible choice where compatibility with older versions of Trainz is desired.&lt;br /&gt;
* JPEG (.jpg) files. JPEG is a lossy image compression format with no alpha channel support. This format should generally be avoided since it will typically lead to the image being compressed in a lossy format (JPG), decompressed, recompressed again into another lossy format (DXT1), losing detail at each stage. Worse, if JPEG files are used during the creation of the image, each edit-save-test cycle may result in a loss of image quality.&lt;br /&gt;
* Windows Bitmap (.bmp) files. BMP is a lossless image format with no compression and optional alpha channel. This format should generally be avoided since it does not offer compression and has no redeeming benefits.&lt;br /&gt;
* HDR (.hdr) files. HDR is a lossless image format with 32 bits of precision per channel. The R32F G32F B32F A32F internal texture format is used, and texture compression is not supported. This is a very expensive format (in terms of memory and performance) and should only be used where absolutely essential. Textures created in this format should be kept as small as possible (eg. 256-512 pixels wide and high) but at least 8x8 pixels wide and high.&lt;br /&gt;
* PNG (.png) files. PNG is a lossless compressed image format with alpha channel support. This is the best choice where compatibility with older versions of Trainz is not required.&lt;br /&gt;
* DDS (.dds) files. This has very limited support intended for specific internal purposes; it is not recommended that end-users utilize this format at the current time.&lt;br /&gt;
&lt;br /&gt;
All images which comprise a given texture must have identical dimensions (width, height).&lt;br /&gt;
&lt;br /&gt;
Source images should use the SRGB color space except where material-specific documentation indicates otherwise.&lt;br /&gt;
&lt;br /&gt;
=Notes on Image Editors=&lt;br /&gt;
* The Targa Exporter plugin shipped with some older versions of Adobe Photoshop is broken and silently corrupts or discards alpha channels; a free update is available which resolves this issue.&lt;br /&gt;
* Some image editors do not support alpha channels on BMP files.&lt;br /&gt;
* By default, Photoshop does not allow for explicit editing of the alpha channel in PNG images. There is a free plugin called [https://www.fnordware.com/superpng/ SuperPNG] which integrates better PNG support to enable saving and editing of PNG alpha masks.&lt;br /&gt;
* [http://www.amnoid.de/ddsview/ ddsview ] is an open source image editor that can properly open all of the texture formats used by Trainz. This is an easy tool to quickly convert between PNG parameters and TGA parameters.&lt;br /&gt;
&lt;br /&gt;
=*.txt File Extension=&lt;br /&gt;
Texture files have a &amp;quot;.texture.txt&amp;quot; name extension, however when a texture file is specified within a [[config.txt file]] or similar, the &amp;quot;.txt&amp;quot; must be omitted, leaving the &amp;quot;.texture&amp;quot; extension.&lt;br /&gt;
For example, a texture file named &#039;&#039;grass.texture.txt&#039;&#039; is specified in a [[KIND Groundtexture]] config file using the syntax &#039;&#039;texture &amp;quot;grass.texture&amp;quot;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=Use of Image Files in Place of Texture Files=&lt;br /&gt;
Trainz previously supported using &#039;&#039;any supported image file&#039;&#039; type in place of a [[Texture file]]. [[TANE]] does not support this technique; a texture.txt file must be used.&lt;br /&gt;
&lt;br /&gt;
[[Category:File formats]]&lt;br /&gt;
[[Category:Modeling]]&lt;br /&gt;
[[Category:Content creation]]&lt;br /&gt;
{{ORP-bot}}&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=Category:Validation_Errors&amp;diff=42877</id>
		<title>Category:Validation Errors</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=Category:Validation_Errors&amp;diff=42877"/>
		<updated>2024-08-09T02:57:40Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Validation Error (VE) numbers are logged during content validation, to allow users to look up particular validation messages to better understand the source of the problem. Normal logs provide a substantial amount of technical detail about the error, but typically assume that the reader is familiar with the subject matter and will understand why the log is relevant. This wiki provides the necessary background information to understanding many of the logs, however a user who is unfamiliar with the area in question may not know where to start looking. VE numbers allow users to quickly find relevant pages in the wiki without any prior knowledge of the subject.&lt;br /&gt;
&lt;br /&gt;
This page serves as a master guide to all VE numbers currently logged by Trainz. This page does not provide detailed information on any given VE number- please refer to the individual VE number pages for specific details. The error text here is correct for the English localisation of Trainz at the time of writing, however the exact text may change from time to time. It is intended that the overall meaning of a VE number will never change- new VE numbers will be issued instead, and old VE numbers may be made obsolete.&lt;br /&gt;
&lt;br /&gt;
Logs which lack VE numbers do not belong on this page.&lt;br /&gt;
&lt;br /&gt;
The individual VE pages can be found at the links below, or can be accessed directly from [[Content Manager]] by right-clicking on the Validation Error in the results log, and selecting &amp;quot;View Help for This Message&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|1||[[Help:VE1|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Decimal value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|2||[[Help:VE2|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Integer value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|3||[[Help:VE3|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|4||[[Help:VE4|&amp;quot;&#039;$(TAG_NAME)&#039; must have a positive value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|5||[[Help:VE5|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|6||[[Help:VE6|&amp;quot;&#039;$(TAG_NAME)&#039; must not be zero.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|7||[[Help:VE7|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|8||[[Help:VE8|&amp;quot;The value for &#039;$(TAG_NAME)&#039; must be between &#039;$(MIN)&#039; and &#039;$(MAX)&#039; but was specified as &#039;$(VALUE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|9||[[Help:VE9|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|10||[[Help:VE10|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|11||[[Help:VE11|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|12||[[Help:VE12|&amp;quot;No string-table entry found with tag &#039;$(VALUE)&#039; for for string-token tag &#039;$(TAG)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|13||[[Help:VE13|&amp;quot;Missing or invalid selection for tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|14||[[Help:VE14|&amp;quot;Missing or invalid selection for tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|15||[[Help:VE15|&amp;quot;Attachment point &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must be found in mesh &#039;$(MESH_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|16||[[Help:VE16|&amp;quot;Container &#039;$(CONT_NAME)&#039; does not have an &#039;att-parent&#039; tag which is required to reference an attachment point.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|17||[[Help:VE17|&amp;quot;Attachment point &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must be found in mesh &#039;$(MESH_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|18||[[Help:VE18|&amp;quot;Attachment point &#039;$(TAG_VAL)&#039; referenced by tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; was not found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|19||[[Help:VE19|&amp;quot;Effect &#039;$(EFFECT_NAME)&#039; in &#039;$(CONT_NAME)&#039; was not found within the mesh table.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|20||[[Help:VE20|&amp;quot;Mesh &#039;$(MESH_NAME)&#039; referenced in &#039;$(CONT_NAME)&#039; was not found within the mesh table.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|21||[[Help:VE21|&amp;quot;Attachment point &#039;$(TAG_VAL)&#039; referenced by tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; was not found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|22||[[Help:VE22|&amp;quot;Missing or invalid selection for tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|23||[[Help:VE23|&amp;quot;Invalid tag name &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|24||[[Help:VE24|&amp;quot;Invalid tag name &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|25||[[Help:VE25|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|26||[[Help:VE26|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|27||[[Help:VE27|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must have a mesh file extension.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|28||[[Help:VE28|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must have an image file extension.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|29||[[Help:VE29|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must have an animation file extension.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|30||[[Help:VE30|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; refers to a nonexistent file: &#039;$(FILENAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|31||[[Help:VE31|&amp;quot;Invalid tag name &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|32||[[Help:VE32|&amp;quot;Alias mesh requires valid parent asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|33||[[Help:VE33|&amp;quot;Alias mesh &#039;$(FILE)&#039; not found in dependency $(KUID).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|34||[[Help:VE34|&amp;quot;Alias mesh &#039;$(FILE)&#039; not found in latest version ($(NEW_KUID)) of dependency $(OLD_KUID).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|35||[[Help:VE35|&amp;quot;Required alias mesh asset $(KUID) is missing and cannot be validated.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|36||[[Help:VE36|&amp;quot;The texture &#039;$(FILE)&#039; failed to load.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|37||[[Help:VE37|&amp;quot;The texture &#039;$(FILE)&#039; is not a power of 2, please resize it.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|38||[[Help:VE38|&amp;quot;The texture &#039;$(FILE)&#039; is not square. Cubemap textures need to have the same width and height.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|39||[[Help:VE39|&amp;quot;The texture &#039;$(FILE)&#039; is a uniform color.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|40||[[Help:VE40|&amp;quot;Unable to load $(TYPE) texture &#039;$(TEXTURE)&#039; for texture file &#039;$(FILE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|41||[[Help:VE41|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Integer value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|42||[[Help:VE42|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Decimal value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|43||[[Help:VE43|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Boolean value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|44||[[Help:VE44|&amp;quot;Tag &#039;$(TAG_NAME)&#039; in the container &#039;$(CONT_NAME)&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|45||[[Help:VE45|&amp;quot;The Tag &#039;$(TAG_NAME)&#039; is not permitted within a container of type &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|46||[[Help:VE46|&amp;quot;Internal Error: The template does not specify that a smoke container is valid in the container being parsed.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|47||[[Help:VE47|&amp;quot;Container &#039;$(CONT_NAME)&#039; is not permitted in this section.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|48||[[Help:VE48|&amp;quot;This asset uses an obsolete trainz-build number. Trainz-build numbers below $(LOWEST_TRAINZBUILD) are no longer supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|49||[[Help:VE49|&amp;quot;Required tag &#039;kind&#039; is not present. Ensure this is a valid config file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|50||[[Help:VE50|&amp;quot;Unsupported kind &#039;$(KIND)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|51||[[Help:VE51|&amp;quot;Tag &#039;$(TAG_NAME)&#039; in the container &#039;$(CONT_NAME)&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|52||[[Help:VE52|&amp;quot;The Tag &#039;$(TAG_NAME)&#039; is not permitted within a container of type &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|53||[[Help:VE53|&amp;quot;This container is no longer supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|54||[[Help:VE54|&amp;quot;The Tag &#039;$(TAG_NAME)&#039; is not permitted within a container of type &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|55||[[Help:VE55|&amp;quot;This container is no longer supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|56||[[Help:VE56|&amp;quot;Container &#039;$(CONT_NAME)&#039; is not permitted in this section.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|57||[[Help:VE57|&amp;quot;Container &#039;$(CONT_NAME)&#039; is not permitted in this section.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|58||[[Help:VE58|&amp;quot;The tag &#039;$(TAG_NAME)&#039; is not a valid container type (expected &#039;$(TYPE)&#039;).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|59||[[Help:VE59|&amp;quot;Internal error: unknown dataType - kind &#039;$(KIND)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|60||[[Help:VE60|&amp;quot;Required tag &#039;$(TAG_NAME)&#039; was missing and has been set to default.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|61||[[Help:VE61|&amp;quot;Required tag &#039;$(TAG_NAME)&#039; was missing and has been set to default.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|62||[[Help:VE62|&amp;quot;Required container &#039;$(CONT_NAME)&#039; is missing.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|63||[[Help:VE63|&amp;quot;The cubemap texture &#039;$(FILE)&#039; has missing images. Please verify the texture.txt file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|64||[[Help:VE64|&amp;quot;Cubemap texture &#039;$(FILE)&#039; contains images of different sizes.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|65||[[Help:VE65|&amp;quot;The *.texture.txt file is missing for texture resource &#039;$(FILE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|66||[[Help:VE66|&amp;quot;The texture file &#039;$(FILE)&#039; contains non-ANSI characters. Textures must be ANSI.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|67||[[Help:VE67|&amp;quot;The texture &#039;$(FILE)&#039; does not seem to have a primary texture set. Please verify the texture.txt file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|68||[[Help:VE68|&amp;quot;The primary and alpha texture are not the same size for &#039;$(FILE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|69||[[Help:VE69|&amp;quot;Binary conversion failed for texture resource &#039;$(FILE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|70||[[Help:VE70|&amp;quot;The KUID tag is not a valid KUID value: &#039;$(string)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|71||[[Help:VE71|&amp;quot;Unsupported SpeedTree version for mesh: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|72||[[Help:VE72|&amp;quot;Unable to load mesh file: &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|73||[[Help:VE73|&amp;quot;Image file &#039;$(FILE)&#039; is incorrectly used as both a texture.txt source file and a raw image file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|74||[[Help:VE74|&amp;quot;Image file &#039;$(FILE)&#039; is incorrectly used as both a texture.txt source file and a raw image file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|76||[[Help:VE76|&amp;quot;Unable to load mesh file: &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|77||[[Help:VE77|&amp;quot;Unable to load indexed mesh &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|79||[[Help:VE79|&amp;quot;Unable to load animation file &#039;$(FILE)&#039; (mesh has not been loaded correctly).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|81||[[Help:VE81|&amp;quot;The high-poly mesh &#039;$(FILE)&#039; should have LOD levels.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|82||[[Help:VE82|&amp;quot;High-detail .im files are not supported for traincar assets, as they are likely to perform poorly. It is recommended that you upgrade &#039;$(FILE)&#039; to a .lm file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|83||[[Help:VE83|&amp;quot;The file &#039;$(FILE)&#039; is provided in LM format despite having no attachment points and no animation support. This may have a negative impact on performance.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|84||[[Help:VE84|&amp;quot;The file &#039;$(FILE)&#039; is provided in LM format despite containing only a single mesh. This may have a negative impact on performance.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|85||[[Help:VE85|&amp;quot;The file &#039;$(FILE)&#039; is provided in LM format, however the high-detail mesh is comprised of less than 300 polygons. This may have a negative impact on performance.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|86||[[Help:VE86|&amp;quot;Legacy .pm files are no longer supported, and will perform poorly. It is recommended that you switch to using a .lm file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|87||[[Help:VE87|&amp;quot;Legacy .pm files are no longer supported, and will perform poorly. It is recommended that you switch to using a .lm file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|88||[[Help:VE88|&amp;quot;This asset has a trainz-build number which is not recognised by this tool.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|89||[[Help:VE89|&amp;quot;Tag &#039;$(TAG_NAME)&#039; in the container &#039;$(CONT_NAME)&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|90||[[Help:VE90|&amp;quot;This asset has an invalid KUID user id&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|91||[[Help:VE91|&amp;quot;The dependency $(KUID) has an invalid KUID User ID and cannot be used&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|92||[[Help:VE92|&amp;quot;Duplicate &#039;$(TAG_NAME)&#039; containers in &#039;$(CONT_NAME)&#039;. Containers must have a unique name.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|93||[[Help:VE93|&amp;quot;Duplicate &#039;$(TAG_NAME)&#039; tags in &#039;$(CONT_NAME)&#039;. Tags must have a unique name.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|94||[[Help:VE94|&amp;quot;This asset requires a shadow mesh, but the mesh table does not contain one.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|95||[[Help:VE95|&amp;quot;This asset does not have a mesh that is visible by default.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|96||[[Help:VE96|&amp;quot;Maximum of 5 running number fonts supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|97||[[Help:VE97|&amp;quot;The running number font directory &#039;$(DIR)&#039; could not be found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|98||[[Help:VE98|&amp;quot;The running number font file &#039;$(DIR)/$(FILE)&#039; could not be found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|99||[[Help:VE99|&amp;quot;The track-sound container &#039;$(NAME)&#039; has no bogey, track or track-parent tag.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|100||[[Help:VE100|&amp;quot;Required tag &#039;$(TAG_NAME)&#039; was missing and has been set to default.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|101||[[Help:VE101|&amp;quot;The file &#039;$(FILE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|102||[[Help:VE102|&amp;quot;Failed to load sound file &#039;$(FILE)&#039;, please ensure this is a valid wav file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|103||[[Help:VE103|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|104||[[Help:VE104|&amp;quot;Multiple template property bindings for rule property &#039;$(PROP)&#039; for rule &#039;$(RULE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|105||[[Help:VE105|&amp;quot;The template property &#039;$(NAME)&#039; specified in the rule-template-bindings container of rule &#039;$(RULE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|106||[[Help:VE106|&amp;quot;The high-detail meshes in season $(SEASON) total more than $(LIMIT) polygons. This may have a negative impact on performance: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|107||[[Help:VE107|&amp;quot;The high-detail meshes total more than $(LIMIT) polygons. This may have a negative impact on performance: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|108||[[Help:VE108|&amp;quot;The low-detail meshes in season $(SEASON) total more than 500 polygons. This may have a negative impact on performance: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|109||[[Help:VE109|&amp;quot;The low-detail meshes total more than 500 polygons. This may have a negative impact on performance: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|110||[[Help:VE110|&amp;quot;The meshes in LOD level $(LOD_LEVEL) in season $(SEASON) must total at least 20% fewer polygons than the next higher LOD in the same season: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|111||[[Help:VE111|&amp;quot;The meshes in LOD level $(LOD_LEVEL) must total at least 20% fewer polygons than the next higher LOD: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|112||[[Help:VE112|&amp;quot;Multiple track stretches between &#039;$(FROM_VERTEX)&#039; and &#039;$(TO_VERTEX)&#039; in container &#039;$(CONT_NAME)&#039;. Track stretches must be unique.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|113||[[Help:VE113|&amp;quot;An image file (&#039;$(FILE)&#039;) has been supplied where a texture file (&#039;*.texture.txt&#039;) is required.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|114||[[Help:VE114|&amp;quot;An image file (&#039;$(FILE)&#039;) has been supplied where a texture file (&#039;*.texture.txt&#039;) is required.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|115||[[Help:VE115|&amp;quot;The texture file &#039;$(FILE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|116||[[Help:VE116|&amp;quot;No texture file has been specified for this texture asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|117||[[Help:VE117|&amp;quot;&#039;$(TAG_0)&#039; must be set to a &#039;$(KIND)&#039; for &#039;$(TAG_1)&#039; to be allowed.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|118||[[Help:VE118|&amp;quot;Tag &#039;$(TAG_0)&#039; requires that &#039;$(TAG_1)&#039; be set to &#039;$(KIND)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|119||[[Help:VE119|&amp;quot;The tag &#039;$(TAG_NAME)&#039; is not valid for kind &#039;$(KIND)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|120||[[Help:VE120|&amp;quot;Tag &#039;$(TAG_0)&#039;, requires the tag &#039;$(TAG_1)&#039; to be present.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|121||[[Help:VE121|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|122||[[Help:VE122|&amp;quot;&#039;$(TAG_NAME)&#039; must have a positive value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|123||[[Help:VE123|&amp;quot;The script file &#039;$(FILE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|124||[[Help:VE124|&amp;quot;The file &#039;$(FILE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|125||[[Help:VE125|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|126||[[Help:VE126|&amp;quot;&#039;$(TAG_NAME)&#039; must not be zero.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|127||[[Help:VE127|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|128||[[Help:VE128|&amp;quot;The value for &#039;$(TAG_NAME)&#039; must be between &#039;$(MIN)&#039; and &#039;$(MAX)&#039; but was specified as &#039;$(VALUE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|129||[[Help:VE129|&amp;quot;Incorrect number of values for the tag &#039;$(TAG_NAME)&#039;, expected $(NUM_0) values, found $(NUM_1).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|130||[[Help:VE130|&amp;quot;Too many values for the tag &#039;$(TAG_NAME)&#039;, maximum is $(MAX) values, found $(FOUND).&amp;quot;]]]]&lt;br /&gt;
|-&lt;br /&gt;
|131||[[Help:VE131|&amp;quot;Value must be a mesh from the mesh-table (not a parent container).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|132||[[Help:VE132|&amp;quot;The attachment point &#039;$(ATT)&#039; must belong to the parent mesh of the effect (mesh=$(MESH)).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|133||[[Help:VE133|&amp;quot;A light container must be present to link the signals.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|134||[[Help:VE134|&amp;quot;&#039;$(NUM)&#039; must be a valid light number from the light container.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|135||[[Help:VE135|&amp;quot;&#039;$(TAG_0)&#039; requires that the tag &#039;$(TAG_1)&#039; be present.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|136||[[Help:VE136|&amp;quot;&#039;$(TAG_0)&#039; requires that the tag &#039;$(TAG_1)&#039; be present.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|137||[[Help:VE137|&amp;quot;Empty or invalid running number specified at character index $(INDEX)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|138||[[Help:VE138|&amp;quot;Running number specified at character index $(INDEX) is too large, must be less than 9 characters.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|139||[[Help:VE139|&amp;quot;Invalid running number range specified at character index $(INDEX), ($(FROM)-$(TO)).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|140||[[Help:VE140|&amp;quot;Running number range &#039;$(FROM)-$(TO)&#039; specified at character index $(INDEX) overlaps already in use numbers, running numbers must be unique.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|141||[[Help:VE141|&amp;quot;Running number &#039;$(NUMBER)&#039; specified at character index $(INDEX) is already in use.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|142||[[Help:VE142|&amp;quot;Invalid character &#039;$(CHAR)&#039; specified in running number list, only numbers, &#039;,&#039; and &#039;-&#039; are supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|143||[[Help:VE143|&amp;quot;Possible running number list is too large, the set must contain less than 20000 possibilities.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|144||[[Help:VE144|&amp;quot;Category code &#039;ZX - Paintshed template&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|145||[[Help:VE145|&amp;quot;Category code &#039;ZX - Paintshed template&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|146||[[Help:VE146|&amp;quot;An asset must be specified for tag &#039;$(TAG_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|147||[[Help:VE147|&amp;quot;The tag(s) $(MISPLACED_TAGS) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|148||[[Help:VE148|&amp;quot;The tag(s) $(MISPLACED_TAGS) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|149||[[Help:VE149|&amp;quot;The mesh(es) $(MISPLACED_MESHES) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|150||[[Help:VE150|&amp;quot;The mesh(es) $(MISPLACED_MESHES) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|151||[[Help:VE150|&amp;quot;The mesh(es) $(MISPLACED_MESHES) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|152||[[Help:VE152|&amp;quot;The tags $(MISSING_TAGS) are not all defined. The default values will be used and the positions of the elements may not fit your track.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|153||[[Help:VE153|&amp;quot;The mesh $(MESH) is present but the tag $(MISSING_TAG) is not defined.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|154||[[Help:VE154|&amp;quot;The mesh $(MESH) is present but the tag $(MISSING_TAG) is not defined.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|155||[[Help:VE155|&amp;quot;The mesh $(MESH) is present but the tags $(MISSING_TAGS) are not all defined.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|156||[[Help:VE156|&amp;quot;The tag $(MISSING_TAG) is not defined. The default value will be used and the positions of the elements may not fit your track.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|157||[[Help:VE157|&amp;quot;The mesh $(MESH) is present but the tag $(MISSING_TAG) is missing. The default value will be used and the positions of the elements may not fit your track.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|158||[[Help:VE158|&amp;quot;Unable to open .lm.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|159||[[Help:VE159|&amp;quot;Unable to parse .lm.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|160||[[Help:VE160|&amp;quot;No &#039;mesh&#039; keys found in .lm.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|161||[[Help:VE161|&amp;quot;$(LODCOUNT) LODs in .lm.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|162||[[Help:VE162|&amp;quot;One of the LOD reductions of &#039;$(FILE)&#039; introduces a new attachment point: $(ATT)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|163||[[Help:VE163|&amp;quot;Unable to parse .im file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|164||[[Help:VE164|&amp;quot;Invalid position data in .im file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|165||[[Help:VE165|&amp;quot;Texture &#039;$(TEXTURE)&#039; is missing or could not be loaded in mesh &#039;$(FILE)&#039;, material &#039;$(MATERIAL)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|166||[[Help:VE166|&amp;quot;$(COMBINEDCOUNT) combined chunks (of $(SOURCECOUNT) source) in .im file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|167||[[Help:VE167|&amp;quot;Source image texture file &#039;$(TEXTUREFILE)&#039; is too large for &#039;$(ASSETFILE)&#039; ($(WIDTH)x$(HEIGHT))&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|168||[[Help:VE168|&amp;quot;File &#039;$(TEXTUREFILE)&#039; is not a valid compiled texture file for &#039;$(ASSETFILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|169||[[Help:VE169|&amp;quot;Compiled texture file &#039;$(TEXTUREFILE)&#039; is unsupported version for &#039;$(ASSETFILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|170||[[Help:VE170|&amp;quot;Failed to open compiled texture &#039;$(TEXTUREFILE)&#039; for &#039;$(ASSETFILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|171||[[Help:VE171|&amp;quot;Expected texture file type but found &#039;$(TEXTUREFILE)&#039; for &#039;$(ASSETFILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|172||[[Help:VE172|&amp;quot;Script class does not match asset kind ($(KIND)).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|173||[[Help:VE173|&amp;quot;Material &#039;$(MATERIAL)&#039; in mesh &#039;$(FILE)&#039; is not of a recognised material type.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|174||[[Help:VE174|&amp;quot;MeshObjectSpec::LinkSpecs&amp;gt; Mesh-table element #$(MESH_INDEX) parent mesh is invalid.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|175||[[Help:VE175|&amp;quot;MeshObjectSpec::LinkSpecs&amp;gt; Mesh-table element #$(MESH_INDEX) is part of invalid hierarchy.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|176||[[Help:VE176|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must have a texture file extension.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|177||[[Help:VE177|&amp;quot;The kuid &#039;$(KUID)&#039; is not in the database, and could not be found in any known location. Ensure that this is a valid asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|178||[[Help:VE178|&amp;quot;The asset specified in &#039;$(KUID)&#039; is not installed locally but is available for download.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|179||[[Help:VE179|&amp;quot;The kuid &#039;$(KUID)&#039; specified in &#039;$(TAG_NAME)&#039; is not of the correct type.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|180||[[Help:VE180|&amp;quot;Integrity check failure on $(FILE). One or more route/session tiles may be missing.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|181||[[Help:VE181|&amp;quot;The tag &#039;$(TAG_NAME)&#039; requires a minimum asset version of $(MIN_VERSION)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|182||[[Help:VE182|&amp;quot;Material &#039;$(MATERIAL)&#039; in mesh &#039;$(FILE)&#039; is missing a texture for a mandatory texture slot.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|183||[[Help:VE183|&amp;quot;FBX file is in an unsupported older format.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|184||[[Help:VE184|&amp;quot;KIND &#039;$(KIND)&#039; requires trainz-build $(TRAINZBUILD).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|185||[[Help:VE185|&amp;quot;Material &#039;$(MATERIAL)&#039; in mesh &#039;$(FILE)&#039; has heightmap texture. Provide a normal map instead.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|186||[[Help:VE186|&amp;quot;Material &#039;$(MATERIAL)&#039; is shared between multiple chunks in this asset but the material parameters conflict.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|187||[[Help:VE187|&amp;quot;The value &#039;$(VALUE)&#039; in not a valid KUID.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|188||[[Help:VE188|&amp;quot;Custom render plugin failed to load mesh &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|189||[[Help:VE189|&amp;quot;Collision data exceeds $(LIMIT)KB. Please specify a different generation method or a simplified mesh.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|190||[[Help:VE190|&amp;quot;Tag &#039;$(NAME)&#039; is unable to be converted from $(TYPE1) to $(TYPE2)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|191||[[Help:VE191|&amp;quot;Tag &#039;$(NAME)&#039; does not contain a valid integer: $(VALUE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|192||[[Help:VE192|&amp;quot;Tag &#039;$(NAME)&#039; does not contain a valid float list: $(VALUE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|193||[[Help:VE193|&amp;quot;Tag &#039;$(NAME)&#039; does not contain a valid float&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|194||[[Help:VE194|&amp;quot;Tag &#039;$(NAME)&#039; does not contain a valid kuid: $(VALUE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|195||[[Help:VE195|&amp;quot;Unable to parse chunk $(CHUNK_INDEX) in mesh file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|196||[[Help:VE196|&amp;quot;Failed to load bogey $(KUID)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|197||[[Help:VE197|&amp;quot;Syntax error in script &#039;$(SCRIPT)&#039; for asset $(ASSET)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|198||[[Help:VE198|&amp;quot;Session failed to load route asset: $(KUID)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|199||[[Help:VE199|&amp;quot;Asset $(KUID) failed to load. Unloading resources.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|200||[[Help:VE200|&amp;quot;Unable to load mesh $(NAME) for $(ASSET_ID)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|201||[[Help:VE201|&amp;quot;Traincar is missing required attachment point: $(ATT_NAME)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|202||[[Help:VE202|&amp;quot;Parse error reading twinkles file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|203||[[Help:VE203|&amp;quot;Bad sequence order in $(TAG_NAME) list. Each element must be greater than the last.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|204||[[Help:VE204|&amp;quot;Invalid range in $(TAG_NAME) list. Elements must be greater than or equal to $(INC_MIN) and less than $(EXC_MAX).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|205||[[Help:VE205|&amp;quot;Invalid element count in $(TAG_NAME) list. This list must have at least $(COUNT) elements (to match the $(TAG_START) list).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|206||[[Help:VE206|&amp;quot;The season-selector references season &#039;$(SEASON)&#039;, but this does not exist in the texture-variants container.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|207||[[Help:VE207|&amp;quot;Attached track asset $(CHILD) failed to load.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|208||[[Help:VE208|&amp;quot;Attached track asset not specified for track $(INDEX).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|209||[[Help:VE209|&amp;quot;Asset is missing the required &#039;attached-track&#039; container.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|210||[[Help:VE210|&amp;quot;Asset is missing the required &#039;track&#039; tag.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|211||[[Help:VE211|&amp;quot;Asset is missing the required &#039;road&#039; tag.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|212||[[Help:VE212|&amp;quot;Traincar asset must have at least two bogeys.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|213||[[Help:VE213|&amp;quot;Traincar asset has invalid bogey placement.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|214||[[Help:VE214|&amp;quot;Traincar asset has invalid length.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|215||[[Help:VE215|&amp;quot;Asset has an invalid number of LODs: $(LOD_COUNT)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|216||[[Help:VE216|&amp;quot;Material $(MATERIAL) in mesh file $(MESH) has an inappropriate texture slot assigned: $(TEXTURE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|217||[[Help:VE217|&amp;quot;Material $(MATERIAL) in mesh file $(MESH) has no texture assigned to a required slot: $(TEXTURE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|218||[[Help:VE218|&amp;quot;Asset has duplicate attached track at track $(INDEX).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|219||[[Help:VE219|&amp;quot;Failed to load driver mesh $(ASSETID).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|220||[[Help:VE220|Generic script compilation error.]]&lt;br /&gt;
|-&lt;br /&gt;
|221||[[Help:VE221|&amp;quot;$(ASSETID) is faulty and will not be loaded.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|222||[[Help:VE222|&amp;quot;Failed to load mesh $(ASSETID)-$(MESHFILE) for TNI plugin renderer.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|223||[[Help:VE223|&amp;quot;Unable to create mesh index $(MESHINDEX) for asset $(ASSET).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|224||[[Help:VE224|&amp;quot;Corrupted data in mesh file &#039;$(FILENAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|225||[[Help:VE225|&amp;quot;Failed to query asset details for featured asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|226||[[Help:VE226|&amp;quot;Failed to upload asset details for featured asset: $(ERRORTEXT)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|227||[[Help:VE227|&amp;quot;Missing image for featured asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|228||[[Help:VE228|&amp;quot;Failed to read image file for featured asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|229||[[Help:VE229|&amp;quot;DLC marketing image is missing or incorrectly sized for featured asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|230||[[Help:VE230|&amp;quot;DLS thumbnail image is missing or incorrectly sized for featured asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|231||[[Help:VE231|&amp;quot;Failed to open image file for featured asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|232||[[Help:VE232|&amp;quot;Failed to upload image for featured asset: $(ERRORTEXT)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|233||[[Help:VE233|&amp;quot;One or more featured assets was not provided.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|234||[[Help:VE234|&amp;quot;Asset is not present in the featured assets list.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|235||[[Help:VE235|&amp;quot;Featured asset is not present in the input.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|236||[[Help:VE236|&amp;quot;Featured asset was not available.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|237||[[Help:VE237|&amp;quot;Featured asset failed validation.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|238||[[Help:VE238|&amp;quot;Featured asset has faulty or missing dependencies.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|239||[[Help:VE239|&amp;quot;Featured asset is Base content.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|240||[[Help:VE240|&amp;quot;Featured asset is missing an English name or description.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|241||[[Help:VE241|&amp;quot;Newly built package is not compatible with previously released version.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|242||[[Help:VE242|&amp;quot;Unable to load animation file &#039;$(FILE)&#039; (file not found, or is damaged).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|243||[[Help:VE243|&amp;quot;Failed to submit changes to asset $(ASSET_KUID) due to file access error&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|244||[[Help:VE244|&amp;quot;Files in base assets cannot use importers: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|245||[[Help:VE245|&amp;quot;Missing compiled texture: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|246||[[Help:VE246|&amp;quot;Missing source texture: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|247||[[Help:VE247|&amp;quot;Creating default texture.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|248||[[Help:VE248|&amp;quot;Failed to create *.texture.txt file for source image: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|249||[[Help:VE249|&amp;quot;Failed to compile *.texture.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|250||[[Help:VE250|&amp;quot;Material Metadata expected data for texture slot &#039;$(SLOT)&#039; of material &#039;$(MATERIAL)&#039; but none found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|251||[[Help:VE251|&amp;quot;Material Metadata expected *.texture resource for texture slot &#039;$(SLOT)&#039; of material &#039;$(MATERIAL)&#039; bout found: $(FOUND)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|252||[[Help:VE252|&amp;quot;Mesh material expected data for texture slot &#039;$(SLOT)&#039; of material &#039;$(MATERIAL)&#039; but none found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|253||[[Help:VE253|&amp;quot;WriteAnimationFileBoneChunk&amp;gt; excessive bone-chunk count.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|254||[[Help:VE254|&amp;quot;Unable to open mesh metadata file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|255||[[Help:VE255|&amp;quot;Mesh contains unsupported non-triangle primitives.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|256||[[Help:VE256|&amp;quot;Mesh contains invalid material index.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|257||[[Help:VE257|&amp;quot;Mesh contains no primitives.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|258||[[Help:VE258|&amp;quot;Unable to determine vertex format.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|259||[[Help:VE259|&amp;quot;Unsupported number of texture channels.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|260||[[Help:VE260|&amp;quot;Invalid index in primitive.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|261||[[Help:VE261|&amp;quot;Unable to create animation file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|262||[[Help:VE262|&amp;quot;Unable to open animation event file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|263||[[Help:VE263|&amp;quot;Unable to parse animation event file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|264||[[Help:VE264|&amp;quot;Parsed animation event file $(FILE) with $(COUNT) events.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|265||[[Help:VE265|&amp;quot;Unable to search path: &#039;$(FILE_PATH)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|266||[[Help:VE266|&amp;quot;Multiple values found for engine spec param &amp;lt;kuid:xxx:yyy&amp;gt;/tag-name (Value1 and Value2)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|267||[[Help:VE267|&amp;quot;member $(MEMBER) is obsolete in object $(CLASS).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|268||[[Help:VE268|&amp;quot;Mesh file is unused in this asset: &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|269||[[Help:VE269|&amp;quot;Texture table is incorrectly indexed, some textures may be unloadable.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|270||[[Help:VE270|&amp;quot;Density LOD multiplier in level $(LEVEL) is not in descending order.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|271||[[Help:VE271|&amp;quot;The specified TCB flags are invalid, please check the wiki for valid configurations.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|272||[[Help:VE272|&amp;quot;No overridden function found when calling inherited().&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|273||[[Help:VE273|&amp;quot;Variable &#039;&amp;lt;variable name&amp;gt;&#039; already declared in this scope.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|274||[[Help:VE274|&amp;quot;Variable &#039;&amp;lt;variable name&amp;gt;&#039; already declared in parent scope on class &#039;&amp;lt;class name&amp;gt;&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|275||[[Help:VE275|&amp;quot;Excessive chunk count $(CHUNK_COUNT) in mesh file: $(FILE)&amp;quot;]]&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=Category:Validation_Errors&amp;diff=42876</id>
		<title>Category:Validation Errors</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=Category:Validation_Errors&amp;diff=42876"/>
		<updated>2024-08-09T02:55:28Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Validation Error (VE) numbers are logged during content validation, to allow users to look up particular validation messages to better understand the source of the problem. Normal logs provide a substantial amount of technical detail about the error, but typically assume that the reader is familiar with the subject matter and will understand why the log is relevant. This wiki provides the necessary background information to understanding many of the logs, however a user who is unfamiliar with the area in question may not know where to start looking. VE numbers allow users to quickly find relevant pages in the wiki without any prior knowledge of the subject.&lt;br /&gt;
&lt;br /&gt;
This page serves as a master guide to all VE numbers currently logged by Trainz. This page does not provide detailed information on any given VE number- please refer to the individual VE number pages for specific details. The error text here is correct for the English localisation of Trainz at the time of writing, however the exact text may change from time to time. It is intended that the overall meaning of a VE number will never change- new VE numbers will be issued instead, and old VE numbers may be made obsolete.&lt;br /&gt;
&lt;br /&gt;
Logs which lack VE numbers do not belong on this page.&lt;br /&gt;
&lt;br /&gt;
The individual VE pages can be found at the links below, or can be accessed directly from [[Content Manager]] by right-clicking on the Validation Error in the results log, and selecting &amp;quot;View Help for This Message&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|1||[[Help:VE1|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Decimal value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|2||[[Help:VE2|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Integer value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|3||[[Help:VE3|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|4||[[Help:VE4|&amp;quot;&#039;$(TAG_NAME)&#039; must have a positive value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|5||[[Help:VE5|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|6||[[Help:VE6|&amp;quot;&#039;$(TAG_NAME)&#039; must not be zero.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|7||[[Help:VE7|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|8||[[Help:VE8|&amp;quot;The value for &#039;$(TAG_NAME)&#039; must be between &#039;$(MIN)&#039; and &#039;$(MAX)&#039; but was specified as &#039;$(VALUE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|9||[[Help:VE9|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|10||[[Help:VE10|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|11||[[Help:VE11|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|12||[[Help:VE12|&amp;quot;No string-table entry found with tag &#039;$(VALUE)&#039; for for string-token tag &#039;$(TAG)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|13||[[Help:VE13|&amp;quot;Missing or invalid selection for tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|14||[[Help:VE14|&amp;quot;Missing or invalid selection for tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|15||[[Help:VE15|&amp;quot;Attachment point &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must be found in mesh &#039;$(MESH_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|16||[[Help:VE16|&amp;quot;Container &#039;$(CONT_NAME)&#039; does not have an &#039;att-parent&#039; tag which is required to reference an attachment point.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|17||[[Help:VE17|&amp;quot;Attachment point &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must be found in mesh &#039;$(MESH_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|18||[[Help:VE18|&amp;quot;Attachment point &#039;$(TAG_VAL)&#039; referenced by tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; was not found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|19||[[Help:VE19|&amp;quot;Effect &#039;$(EFFECT_NAME)&#039; in &#039;$(CONT_NAME)&#039; was not found within the mesh table.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|20||[[Help:VE20|&amp;quot;Mesh &#039;$(MESH_NAME)&#039; referenced in &#039;$(CONT_NAME)&#039; was not found within the mesh table.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|21||[[Help:VE21|&amp;quot;Attachment point &#039;$(TAG_VAL)&#039; referenced by tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; was not found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|22||[[Help:VE22|&amp;quot;Missing or invalid selection for tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|23||[[Help:VE23|&amp;quot;Invalid tag name &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|24||[[Help:VE24|&amp;quot;Invalid tag name &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|25||[[Help:VE25|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|26||[[Help:VE26|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|27||[[Help:VE27|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must have a mesh file extension.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|28||[[Help:VE28|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must have an image file extension.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|29||[[Help:VE29|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must have an animation file extension.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|30||[[Help:VE30|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; refers to a nonexistent file: &#039;$(FILENAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|31||[[Help:VE31|&amp;quot;Invalid tag name &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|32||[[Help:VE32|&amp;quot;Alias mesh requires valid parent asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|33||[[Help:VE33|&amp;quot;Alias mesh &#039;$(FILE)&#039; not found in dependency $(KUID).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|34||[[Help:VE34|&amp;quot;Alias mesh &#039;$(FILE)&#039; not found in latest version ($(NEW_KUID)) of dependency $(OLD_KUID).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|35||[[Help:VE35|&amp;quot;Required alias mesh asset $(KUID) is missing and cannot be validated.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|36||[[Help:VE36|&amp;quot;The texture &#039;$(FILE)&#039; failed to load.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|37||[[Help:VE37|&amp;quot;The texture &#039;$(FILE)&#039; is not a power of 2, please resize it.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|38||[[Help:VE38|&amp;quot;The texture &#039;$(FILE)&#039; is not square. Cubemap textures need to have the same width and height.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|39||[[Help:VE39|&amp;quot;The texture &#039;$(FILE)&#039; is a uniform color.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|40||[[Help:VE40|&amp;quot;Unable to load $(TYPE) texture &#039;$(TEXTURE)&#039; for texture file &#039;$(FILE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|41||[[Help:VE41|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Integer value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|42||[[Help:VE42|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Decimal value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|43||[[Help:VE43|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Boolean value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|44||[[Help:VE44|&amp;quot;Tag &#039;$(TAG_NAME)&#039; in the container &#039;$(CONT_NAME)&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|45||[[Help:VE45|&amp;quot;The Tag &#039;$(TAG_NAME)&#039; is not permitted within a container of type &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|46||[[Help:VE46|&amp;quot;Internal Error: The template does not specify that a smoke container is valid in the container being parsed.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|47||[[Help:VE47|&amp;quot;Container &#039;$(CONT_NAME)&#039; is not permitted in this section.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|48||[[Help:VE48|&amp;quot;This asset uses an obsolete trainz-build number. Trainz-build numbers below $(LOWEST_TRAINZBUILD) are no longer supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|49||[[Help:VE49|&amp;quot;Required tag &#039;kind&#039; is not present. Ensure this is a valid config file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|50||[[Help:VE50|&amp;quot;Unsupported kind &#039;$(KIND)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|51||[[Help:VE51|&amp;quot;Tag &#039;$(TAG_NAME)&#039; in the container &#039;$(CONT_NAME)&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|52||[[Help:VE52|&amp;quot;The Tag &#039;$(TAG_NAME)&#039; is not permitted within a container of type &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|53||[[Help:VE53|&amp;quot;This container is no longer supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|54||[[Help:VE54|&amp;quot;The Tag &#039;$(TAG_NAME)&#039; is not permitted within a container of type &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|55||[[Help:VE55|&amp;quot;This container is no longer supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|56||[[Help:VE56|&amp;quot;Container &#039;$(CONT_NAME)&#039; is not permitted in this section.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|57||[[Help:VE57|&amp;quot;Container &#039;$(CONT_NAME)&#039; is not permitted in this section.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|58||[[Help:VE58|&amp;quot;The tag &#039;$(TAG_NAME)&#039; is not a valid container type (expected &#039;$(TYPE)&#039;).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|59||[[Help:VE59|&amp;quot;Internal error: unknown dataType - kind &#039;$(KIND)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|60||[[Help:VE60|&amp;quot;Required tag &#039;$(TAG_NAME)&#039; was missing and has been set to default.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|61||[[Help:VE61|&amp;quot;Required tag &#039;$(TAG_NAME)&#039; was missing and has been set to default.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|62||[[Help:VE62|&amp;quot;Required container &#039;$(CONT_NAME)&#039; is missing.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|63||[[Help:VE63|&amp;quot;The cubemap texture &#039;$(FILE)&#039; has missing images. Please verify the texture.txt file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|64||[[Help:VE64|&amp;quot;Cubemap texture &#039;$(FILE)&#039; contains images of different sizes.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|65||[[Help:VE65|&amp;quot;The *.texture.txt file is missing for texture resource &#039;$(FILE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|66||[[Help:VE66|&amp;quot;The texture file &#039;$(FILE)&#039; contains non-ANSI characters. Textures must be ANSI.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|67||[[Help:VE67|&amp;quot;The texture &#039;$(FILE)&#039; does not seem to have a primary texture set. Please verify the texture.txt file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|68||[[Help:VE68|&amp;quot;The primary and alpha texture are not the same size for &#039;$(FILE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|69||[[Help:VE69|&amp;quot;Binary conversion failed for texture resource &#039;$(FILE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|70||[[Help:VE70|&amp;quot;The KUID tag is not a valid KUID value: &#039;$(string)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|71||[[Help:VE71|&amp;quot;Unsupported SpeedTree version for mesh: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|72||[[Help:VE72|&amp;quot;Unable to load mesh file: &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|73||[[Help:VE73|&amp;quot;Image file &#039;$(FILE)&#039; is incorrectly used as both a texture.txt source file and a raw image file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|74||[[Help:VE74|&amp;quot;Image file &#039;$(FILE)&#039; is incorrectly used as both a texture.txt source file and a raw image file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|76||[[Help:VE76|&amp;quot;Unable to load mesh file: &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|77||[[Help:VE77|&amp;quot;Unable to load indexed mesh &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|79||[[Help:VE79|&amp;quot;Unable to load animation file &#039;$(FILE)&#039; (mesh has not been loaded correctly).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|81||[[Help:VE81|&amp;quot;The high-poly mesh &#039;$(FILE)&#039; should have LOD levels.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|82||[[Help:VE82|&amp;quot;High-detail .im files are not supported for traincar assets, as they are likely to perform poorly. It is recommended that you upgrade &#039;$(FILE)&#039; to a .lm file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|83||[[Help:VE83|&amp;quot;The file &#039;$(FILE)&#039; is provided in LM format despite having no attachment points and no animation support. This may have a negative impact on performance.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|84||[[Help:VE84|&amp;quot;The file &#039;$(FILE)&#039; is provided in LM format despite containing only a single mesh. This may have a negative impact on performance.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|85||[[Help:VE85|&amp;quot;The file &#039;$(FILE)&#039; is provided in LM format, however the high-detail mesh is comprised of less than 300 polygons. This may have a negative impact on performance.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|86||[[Help:VE86|&amp;quot;Legacy .pm files are no longer supported, and will perform poorly. It is recommended that you switch to using a .lm file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|87||[[Help:VE87|&amp;quot;Legacy .pm files are no longer supported, and will perform poorly. It is recommended that you switch to using a .lm file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|88||[[Help:VE88|&amp;quot;This asset has a trainz-build number which is not recognised by this tool.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|89||[[Help:VE89|&amp;quot;Tag &#039;$(TAG_NAME)&#039; in the container &#039;$(CONT_NAME)&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|90||[[Help:VE90|&amp;quot;This asset has an invalid KUID user id&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|91||[[Help:VE91|&amp;quot;The dependency $(KUID) has an invalid KUID User ID and cannot be used&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|92||[[Help:VE92|&amp;quot;Duplicate &#039;$(TAG_NAME)&#039; containers in &#039;$(CONT_NAME)&#039;. Containers must have a unique name.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|93||[[Help:VE93|&amp;quot;Duplicate &#039;$(TAG_NAME)&#039; tags in &#039;$(CONT_NAME)&#039;. Tags must have a unique name.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|94||[[Help:VE94|&amp;quot;This asset requires a shadow mesh, but the mesh table does not contain one.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|95||[[Help:VE95|&amp;quot;This asset does not have a mesh that is visible by default.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|96||[[Help:VE96|&amp;quot;Maximum of 5 running number fonts supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|97||[[Help:VE97|&amp;quot;The running number font directory &#039;$(DIR)&#039; could not be found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|98||[[Help:VE98|&amp;quot;The running number font file &#039;$(DIR)/$(FILE)&#039; could not be found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|99||[[Help:VE99|&amp;quot;The track-sound container &#039;$(NAME)&#039; has no bogey, track or track-parent tag.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|100||[[Help:VE100|&amp;quot;Required tag &#039;$(TAG_NAME)&#039; was missing and has been set to default.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|101||[[Help:VE101|&amp;quot;The file &#039;$(FILE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|102||[[Help:VE102|&amp;quot;Failed to load sound file &#039;$(FILE)&#039;, please ensure this is a valid wav file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|103||[[Help:VE103|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|104||[[Help:VE104|&amp;quot;Multiple template property bindings for rule property &#039;$(PROP)&#039; for rule &#039;$(RULE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|105||[[Help:VE105|&amp;quot;The template property &#039;$(NAME)&#039; specified in the rule-template-bindings container of rule &#039;$(RULE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|106||[[Help:VE106|&amp;quot;The high-detail meshes in season $(SEASON) total more than $(LIMIT) polygons. This may have a negative impact on performance: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|107||[[Help:VE107|&amp;quot;The high-detail meshes total more than $(LIMIT) polygons. This may have a negative impact on performance: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|108||[[Help:VE108|&amp;quot;The low-detail meshes in season $(SEASON) total more than 500 polygons. This may have a negative impact on performance: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|109||[[Help:VE109|&amp;quot;The low-detail meshes total more than 500 polygons. This may have a negative impact on performance: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|110||[[Help:VE110|&amp;quot;The meshes in LOD level $(LOD_LEVEL) in season $(SEASON) must total at least 20% fewer polygons than the next higher LOD in the same season: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|111||[[Help:VE111|&amp;quot;The meshes in LOD level $(LOD_LEVEL) must total at least 20% fewer polygons than the next higher LOD: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|112||[[Help:VE112|&amp;quot;Multiple track stretches between &#039;$(FROM_VERTEX)&#039; and &#039;$(TO_VERTEX)&#039; in container &#039;$(CONT_NAME)&#039;. Track stretches must be unique.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|113||[[Help:VE113|&amp;quot;An image file (&#039;$(FILE)&#039;) has been supplied where a texture file (&#039;*.texture.txt&#039;) is required.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|114||[[Help:VE114|&amp;quot;An image file (&#039;$(FILE)&#039;) has been supplied where a texture file (&#039;*.texture.txt&#039;) is required.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|115||[[Help:VE115|&amp;quot;The texture file &#039;$(FILE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|116||[[Help:VE116|&amp;quot;No texture file has been specified for this texture asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|117||[[Help:VE117|&amp;quot;&#039;$(TAG_0)&#039; must be set to a &#039;$(KIND)&#039; for &#039;$(TAG_1)&#039; to be allowed.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|118||[[Help:VE118|&amp;quot;Tag &#039;$(TAG_0)&#039; requires that &#039;$(TAG_1)&#039; be set to &#039;$(KIND)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|119||[[Help:VE119|&amp;quot;The tag &#039;$(TAG_NAME)&#039; is not valid for kind &#039;$(KIND)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|120||[[Help:VE120|&amp;quot;Tag &#039;$(TAG_0)&#039;, requires the tag &#039;$(TAG_1)&#039; to be present.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|121||[[Help:VE121|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|122||[[Help:VE122|&amp;quot;&#039;$(TAG_NAME)&#039; must have a positive value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|123||[[Help:VE123|&amp;quot;The script file &#039;$(FILE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|124||[[Help:VE124|&amp;quot;The file &#039;$(FILE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|125||[[Help:VE125|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|126||[[Help:VE126|&amp;quot;&#039;$(TAG_NAME)&#039; must not be zero.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|127||[[Help:VE127|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|128||[[Help:VE128|&amp;quot;The value for &#039;$(TAG_NAME)&#039; must be between &#039;$(MIN)&#039; and &#039;$(MAX)&#039; but was specified as &#039;$(VALUE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|129||[[Help:VE129|&amp;quot;Incorrect number of values for the tag &#039;$(TAG_NAME)&#039;, expected $(NUM_0) values, found $(NUM_1).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|130||[[Help:VE130|&amp;quot;Too many values for the tag &#039;$(TAG_NAME)&#039;, maximum is $(MAX) values, found $(FOUND).&amp;quot;]]]]&lt;br /&gt;
|-&lt;br /&gt;
|131||[[Help:VE131|&amp;quot;Value must be a mesh from the mesh-table (not a parent container).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|132||[[Help:VE132|&amp;quot;The attachment point &#039;$(ATT)&#039; must belong to the parent mesh of the effect (mesh=$(MESH)).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|133||[[Help:VE133|&amp;quot;A light container must be present to link the signals.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|134||[[Help:VE134|&amp;quot;&#039;$(NUM)&#039; must be a valid light number from the light container.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|135||[[Help:VE135|&amp;quot;&#039;$(TAG_0)&#039; requires that the tag &#039;$(TAG_1)&#039; be present.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|136||[[Help:VE136|&amp;quot;&#039;$(TAG_0)&#039; requires that the tag &#039;$(TAG_1)&#039; be present.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|137||[[Help:VE137|&amp;quot;Empty or invalid running number specified at character index $(INDEX)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|138||[[Help:VE138|&amp;quot;Running number specified at character index $(INDEX) is too large, must be less than 9 characters.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|139||[[Help:VE139|&amp;quot;Invalid running number range specified at character index $(INDEX), ($(FROM)-$(TO)).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|140||[[Help:VE140|&amp;quot;Running number range &#039;$(FROM)-$(TO)&#039; specified at character index $(INDEX) overlaps already in use numbers, running numbers must be unique.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|141||[[Help:VE141|&amp;quot;Running number &#039;$(NUMBER)&#039; specified at character index $(INDEX) is already in use.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|142||[[Help:VE142|&amp;quot;Invalid character &#039;$(CHAR)&#039; specified in running number list, only numbers, &#039;,&#039; and &#039;-&#039; are supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|143||[[Help:VE143|&amp;quot;Possible running number list is too large, the set must contain less than 20000 possibilities.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|144||[[Help:VE144|&amp;quot;Category code &#039;ZX - Paintshed template&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|145||[[Help:VE145|&amp;quot;Category code &#039;ZX - Paintshed template&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|146||[[Help:VE146|&amp;quot;An asset must be specified for tag &#039;$(TAG_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|147||[[Help:VE147|&amp;quot;The tag(s) $(MISPLACED_TAGS) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|148||[[Help:VE148|&amp;quot;The tag(s) $(MISPLACED_TAGS) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|149||[[Help:VE149|&amp;quot;The mesh(es) $(MISPLACED_MESHES) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|150||[[Help:VE150|&amp;quot;The mesh(es) $(MISPLACED_MESHES) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|151||[[Help:VE150|&amp;quot;The mesh(es) $(MISPLACED_MESHES) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|152||[[Help:VE152|&amp;quot;The tags $(MISSING_TAGS) are not all defined. The default values will be used and the positions of the elements may not fit your track.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|153||[[Help:VE153|&amp;quot;The mesh $(MESH) is present but the tag $(MISSING_TAG) is not defined.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|154||[[Help:VE154|&amp;quot;The mesh $(MESH) is present but the tag $(MISSING_TAG) is not defined.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|155||[[Help:VE155|&amp;quot;The mesh $(MESH) is present but the tags $(MISSING_TAGS) are not all defined.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|156||[[Help:VE156|&amp;quot;The tag $(MISSING_TAG) is not defined. The default value will be used and the positions of the elements may not fit your track.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|157||[[Help:VE157|&amp;quot;The mesh $(MESH) is present but the tag $(MISSING_TAG) is missing. The default value will be used and the positions of the elements may not fit your track.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|158||[[Help:VE158|&amp;quot;Unable to open .lm.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|159||[[Help:VE159|&amp;quot;Unable to parse .lm.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|160||[[Help:VE160|&amp;quot;No &#039;mesh&#039; keys found in .lm.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|161||[[Help:VE161|&amp;quot;$(LODCOUNT) LODs in .lm.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|162||[[Help:VE162|&amp;quot;One of the LOD reductions of &#039;$(FILE)&#039; introduces a new attachment point: $(ATT)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|163||[[Help:VE163|&amp;quot;Unable to parse .im file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|164||[[Help:VE164|&amp;quot;Invalid position data in .im file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|165||[[Help:VE165|&amp;quot;Texture &#039;$(TEXTURE)&#039; is missing or could not be loaded in mesh &#039;$(FILE)&#039;, material &#039;$(MATERIAL)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|166||[[Help:VE166|&amp;quot;$(COMBINEDCOUNT) combined chunks (of $(SOURCECOUNT) source) in .im file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|167||[[Help:VE167|&amp;quot;Source image texture file &#039;$(TEXTUREFILE)&#039; is too large for &#039;$(ASSETFILE)&#039; ($(WIDTH)x$(HEIGHT))&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|168||[[Help:VE168|&amp;quot;File &#039;$(TEXTUREFILE)&#039; is not a valid compiled texture file for &#039;$(ASSETFILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|169||[[Help:VE169|&amp;quot;Compiled texture file &#039;$(TEXTUREFILE)&#039; is unsupported version for &#039;$(ASSETFILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|170||[[Help:VE170|&amp;quot;Failed to open compiled texture &#039;$(TEXTUREFILE)&#039; for &#039;$(ASSETFILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|171||[[Help:VE171|&amp;quot;Expected texture file type but found &#039;$(TEXTUREFILE)&#039; for &#039;$(ASSETFILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|172||[[Help:VE172|&amp;quot;Script class does not match asset kind ($(KIND)).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|173||[[Help:VE173|&amp;quot;Material &#039;$(MATERIAL)&#039; in mesh &#039;$(FILE)&#039; is not of a recognised material type.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|174||[[Help:VE174|&amp;quot;MeshObjectSpec::LinkSpecs&amp;gt; Mesh-table element #$(MESH_INDEX) parent mesh is invalid.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|175||[[Help:VE175|&amp;quot;MeshObjectSpec::LinkSpecs&amp;gt; Mesh-table element #$(MESH_INDEX) is part of invalid hierarchy.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|176||[[Help:VE176|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must have a texture file extension.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|177||[[Help:VE177|&amp;quot;The kuid &#039;$(KUID)&#039; is not in the database, and could not be found in any known location. Ensure that this is a valid asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|178||[[Help:VE178|&amp;quot;The asset specified in &#039;$(KUID)&#039; is not installed locally but is available for download.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|179||[[Help:VE179|&amp;quot;The kuid &#039;$(KUID)&#039; specified in &#039;$(TAG_NAME)&#039; is not of the correct type.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|180||[[Help:VE180|&amp;quot;Integrity check failure on $(FILE). One or more route/session tiles may be missing.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|181||[[Help:VE181|&amp;quot;The tag &#039;$(TAG_NAME)&#039; requires a minimum asset version of $(MIN_VERSION)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|182||[[Help:VE182|&amp;quot;Material &#039;$(MATERIAL)&#039; in mesh &#039;$(FILE)&#039; is missing a texture for a mandatory texture slot.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|183||[[Help:VE183|&amp;quot;FBX file is in an unsupported older format.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|184||[[Help:VE184|&amp;quot;KIND &#039;$(KIND)&#039; requires trainz-build $(TRAINZBUILD).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|185||[[Help:VE185|&amp;quot;Material &#039;$(MATERIAL)&#039; in mesh &#039;$(FILE)&#039; has heightmap texture. Provide a normal map instead.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|186||[[Help:VE186|&amp;quot;Material &#039;$(MATERIAL)&#039; is shared between multiple chunks in this asset but the material parameters conflict.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|187||[[Help:VE187|&amp;quot;The value &#039;$(VALUE)&#039; in not a valid KUID.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|188||[[Help:VE188|&amp;quot;Custom render plugin failed to load mesh &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|189||[[Help:VE189|&amp;quot;Collision data exceeds $(LIMIT)KB. Please specify a different generation method or a simplified mesh.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|190||[[Help:VE190|&amp;quot;Tag &#039;$(NAME)&#039; is unable to be converted from $(TYPE1) to $(TYPE2)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|191||[[Help:VE191|&amp;quot;Tag &#039;$(NAME)&#039; does not contain a valid integer: $(VALUE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|192||[[Help:VE192|&amp;quot;Tag &#039;$(NAME)&#039; does not contain a valid float list: $(VALUE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|193||[[Help:VE193|&amp;quot;Tag &#039;$(NAME)&#039; does not contain a valid float&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|194||[[Help:VE194|&amp;quot;Tag &#039;$(NAME)&#039; does not contain a valid kuid: $(VALUE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|195||[[Help:VE195|&amp;quot;Unable to parse chunk $(CHUNK_INDEX) in mesh file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|196||[[Help:VE196|&amp;quot;Failed to load bogey $(KUID)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|197||[[Help:VE197|&amp;quot;Syntax error in script &#039;$(SCRIPT)&#039; for asset $(ASSET)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|198||[[Help:VE198|&amp;quot;Session failed to load route asset: $(KUID)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|199||[[Help:VE199|&amp;quot;Asset $(KUID) failed to load. Unloading resources.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|200||[[Help:VE200|&amp;quot;Unable to load mesh $(NAME) for $(ASSET_ID)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|201||[[Help:VE201|&amp;quot;Traincar is missing required attachment point: $(ATT_NAME)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|202||[[Help:VE202|&amp;quot;Parse error reading twinkles file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|203||[[Help:VE203|&amp;quot;Bad sequence order in $(TAG_NAME) list. Each element must be greater than the last.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|204||[[Help:VE204|&amp;quot;Invalid range in $(TAG_NAME) list. Elements must be greater than or equal to $(INC_MIN) and less than $(EXC_MAX).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|205||[[Help:VE205|&amp;quot;Invalid element count in $(TAG_NAME) list. This list must have at least $(COUNT) elements (to match the $(TAG_START) list).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|206||[[Help:VE206|&amp;quot;The season-selector references season &#039;$(SEASON)&#039;, but this does not exist in the texture-variants container.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|207||[[Help:VE207|&amp;quot;Attached track asset $(CHILD) failed to load.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|208||[[Help:VE208|&amp;quot;Attached track asset not specified for track $(INDEX).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|209||[[Help:VE209|&amp;quot;Asset is missing the required &#039;attached-track&#039; container.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|210||[[Help:VE210|&amp;quot;Asset is missing the required &#039;track&#039; tag.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|211||[[Help:VE211|&amp;quot;Asset is missing the required &#039;road&#039; tag.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|212||[[Help:VE212|&amp;quot;Traincar asset must have at least two bogeys.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|213||[[Help:VE213|&amp;quot;Traincar asset has invalid bogey placement.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|214||[[Help:VE214|&amp;quot;Traincar asset has invalid length.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|215||[[Help:VE215|&amp;quot;Asset has an invalid number of LODs: $(LOD_COUNT)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|216||[[Help:VE216|&amp;quot;Material $(MATERIAL) in mesh file $(MESH) has an inappropriate texture slot assigned: $(TEXTURE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|217||[[Help:VE217|&amp;quot;Material $(MATERIAL) in mesh file $(MESH) has no texture assigned to a required slot: $(TEXTURE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|218||[[Help:VE218|&amp;quot;Asset has duplicate attached track at track $(INDEX).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|219||[[Help:VE219|&amp;quot;Failed to load driver mesh $(ASSETID).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|220||[[Help:VE220|Generic script compilation error.]]&lt;br /&gt;
|-&lt;br /&gt;
|221||[[Help:VE221|&amp;quot;$(ASSETID) is faulty and will not be loaded.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|222||[[Help:VE222|&amp;quot;Failed to load mesh $(ASSETID)-$(MESHFILE) for TNI plugin renderer.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|223||[[Help:VE223|&amp;quot;Unable to create mesh index $(MESHINDEX) for asset $(ASSET).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|224||[[Help:VE224|&amp;quot;Corrupted data in mesh file &#039;$(FILENAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|225||[[Help:VE225|&amp;quot;Failed to query asset details for featured asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|226||[[Help:VE226|&amp;quot;Failed to upload asset details for featured asset: $(ERRORTEXT)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|227||[[Help:VE227|&amp;quot;Missing image for featured asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|228||[[Help:VE228|&amp;quot;Failed to read image file for featured asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|229||[[Help:VE229|&amp;quot;DLC marketing image is missing or incorrectly sized for featured asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|230||[[Help:VE230|&amp;quot;DLS thumbnail image is missing or incorrectly sized for featured asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|231||[[Help:VE231|&amp;quot;Failed to open image file for featured asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|232||[[Help:VE232|&amp;quot;Failed to upload image for featured asset: $(ERRORTEXT)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|233||[[Help:VE233|&amp;quot;One or more featured assets was not provided.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|234||[[Help:VE234|&amp;quot;Asset is not present in the featured assets list.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|235||[[Help:VE235|&amp;quot;Featured asset is not present in the input.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|236||[[Help:VE236|&amp;quot;Featured asset was not available.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|237||[[Help:VE237|&amp;quot;Featured asset failed validation.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|238||[[Help:VE238|&amp;quot;Featured asset has faulty or missing dependencies.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|239||[[Help:VE239|&amp;quot;Featured asset is Base content.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|240||[[Help:VE240|&amp;quot;Featured asset is missing an English name or description.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|241||[[Help:VE241|&amp;quot;Newly built package is not compatible with previously released version.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|242||[[Help:VE242|&amp;quot;Unable to load animation file &#039;$(FILE)&#039; (file not found, or is damaged).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|243||[[Help:VE243|&amp;quot;Failed to submit changes to asset $(ASSET_KUID) due to file access error&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|244||[[Help:VE244|&amp;quot;Files in base assets cannot use importers: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|245||[[Help:VE245|&amp;quot;Missing compiled texture: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|246||[[Help:VE246|&amp;quot;Missing source texture: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|247||[[Help:VE247|&amp;quot;Creating default texture.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|248||[[Help:VE248|&amp;quot;Failed to create *.texture.txt file for source image: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|249||[[Help:VE249|&amp;quot;Failed to compile *.texture.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|250||[[Help:VE250|&amp;quot;Material Metadata expected data for texture slot &#039;$(SLOT)&#039; of material &#039;$(MATERIAL)&#039; but none found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|251||[[Help:VE251|&amp;quot;Material Metadata expected *.texture resource for texture slot &#039;$(SLOT)&#039; of material &#039;$(MATERIAL)&#039; bout found: $(FOUND)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|252||[[Help:VE252|&amp;quot;Mesh material expected data for texture slot &#039;$(SLOT)&#039; of material &#039;$(MATERIAL)&#039; but none found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|253||[[Help:VE253|&amp;quot;WriteAnimationFileBoneChunk&amp;gt; excessive bone-chunk count.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|254||[[Help:VE254|&amp;quot;Unable to open mesh metadata file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|255||[[Help:VE255|&amp;quot;Mesh contains unsupported non-triangle primitives.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|256||[[Help:VE256|&amp;quot;Mesh contains invalid material index.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|257||[[Help:VE257|&amp;quot;Mesh contains no primitives.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|258||[[Help:VE258|&amp;quot;Unable to determine vertex format.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|259||[[Help:VE259|&amp;quot;Unsupported number of texture channels.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|260||[[Help:VE260|&amp;quot;Invalid index in primitive.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|261||[[Help:VE261|&amp;quot;Unable to create animation file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|262||[[Help:VE262|&amp;quot;Unable to open animation event file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|263||[[Help:VE263|&amp;quot;Unable to parse animation event file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|264||[[Help:VE264|&amp;quot;Parsed animation event file $(FILE) with $(COUNT) events.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|265||[[Help:VE265|&amp;quot;Unable to search path: &#039;$(FILE_PATH)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|266||[[Help:VE266|&amp;quot;Multiple values found for engine spec param &amp;lt;kuid:xxx:yyy&amp;gt;/tag-name (Value1 and Value2)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|267||[[Help:VE267|&amp;quot;member $(MEMBER) is obsolete in object $(CLASS).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|268||[[Help:VE268|&amp;quot;Mesh file is unused in this asset: &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|269||[[Help:VE269|&amp;quot;Texture table is incorrectly indexed, some textures may be unloadable.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|270||[[Help:VE270|&amp;quot;Density LOD multiplier in level $(LEVEL) is not in descending order.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|271||[[Help:VE271|&amp;quot;The specified TCB flags are invalid, please check the wiki for valid configurations.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|272||[[Help:VE272|&amp;quot;No overridden function found when calling inherited().&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|273||[[Help:VE273|&amp;quot;Excessive chunk count $(CHUNK_COUNT) in mesh file: $(FILE)&amp;quot;]]&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=M.leafcard&amp;diff=42191</id>
		<title>M.leafcard</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=M.leafcard&amp;diff=42191"/>
		<updated>2024-06-10T05:24:07Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[m.leafcard]] is a new material introduced as part of the &amp;quot;[[Treez]]&amp;quot; foliage system. It is used when creating leaves and minor branches for trees and plants, and is tuned to provide visual outcomes which are suitable for this usage. This may result in subtle rendering differences when compared to the standard materials such as [[m.pbrmetal]]. The exact nature of these differences may change in the future. These differences make [[m.leafcard]] unsuitable as a general-purpose material.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:m_leaf_card_tree_1.jpg|400px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This page describes [[&amp;quot;Trainz-build&amp;quot; number|Content Format v5.6]] and requires that the [[FBX file format]] is used as a data source for any meshes.&lt;br /&gt;
&lt;br /&gt;
We recommend using the free PlantFactory software to create trees with this material type. Detailed tutorials are available on the [[Treez]] page.&lt;br /&gt;
&lt;br /&gt;
=Texture Slots=&lt;br /&gt;
The following texture slots are used for this material. All textures should typically have the same dimensions unless they represent a uniform color, however this is not strictly enforced.&lt;br /&gt;
&lt;br /&gt;
==Albedo==&lt;br /&gt;
RGB: The [[albedo map]] defines the base color of each texel. The sRGB color space is used.&lt;br /&gt;
&lt;br /&gt;
A: The alpha channel provides an opacity channel. Black indicates full transparency, meaning that the [[fragment]] is discarded. White indicates full opacity. Shades of gray are supported, which represent partial transparency. The alpha channel may be heavily quantised.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Albedo Texture Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[File:m_leafcard_1.png|300px]]&lt;br /&gt;
&lt;br /&gt;
Color Channel Separated&lt;br /&gt;
&lt;br /&gt;
[[File:m_leafcard_2.jpg|300px]]&lt;br /&gt;
&lt;br /&gt;
Alpha Channel Separated&lt;br /&gt;
&lt;br /&gt;
[[File:m_leafcard_2b.jpg|300px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Normal==&lt;br /&gt;
RGB: Surface [[normal map]]. This defines which way the surface is facing, relative to the interpolated vertex normals. Since this is an XYZ format rather than color data, it should never be modified in Photoshop. Using Photoshop to add a fourth channel or copy/paste smaller textures into a [[texture atlas]] is acceptable. Per-pixel manipulation or use of filters on the &amp;quot;RGB&amp;quot; channels is not acceptable.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Normal Texture Example with no Alpha Channel (Parallax)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[File:m_leafcard_3.jpg|border|middle|x300px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Parameter==&lt;br /&gt;
This texture is comprised of four separate channels which each form a separate data element. Linear color space (not sRGB) is used for these channels.&lt;br /&gt;
&lt;br /&gt;
[[File:m_leafcard_4.jpg|border|middle|800px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
R: Emissive. This causes the texture to have an internal glow, even when no external light is present. Used for phosphors, permanently-lit markings, etc. The glow color is based on the albedo. Note that this glow does not cast light upon surrounding surfaces except via the Bloom post-processing effect.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parameters (Emissive - Red Channel) Texture Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[File:m_leafcard_5.jpg|border|middle|x300px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
G: Roughness. Defines whether the surface reflections are shiny (0.0) or matte (1.0). See the [[Physically Based Rendering|PBR metal workflow]] for details.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parameters (Roughness - Green Channel) Texture Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[File:m_leafcard_6.jpg|border|middle|x300px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
B: The blue channel of the parameters texture is used to modulate the strength of the directional lighting. This is intended to give the feel of individual leaves being deeper inside the tree and shadowed from all directions, even though the leaf card as a whole is not shadowed. (Note that this is the same channel used for Ambient Occlusion on m.pbrmetal; the leaf card materials do not support ambient occlusion.)&lt;br /&gt;
&lt;br /&gt;
Full brightness (100% blue channel) gives a standard lighting response, while darker values give a weaker response to directional lighting.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parameters (Directional Lighting Strength - Blue Channel) Texture Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[File:m_leafcard_7.jpg|border|middle|x300px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A: Metallicity. Defines whether the surface is metallic (1.0) with the albedo used to colorize reflected light, or dielectric (0.0) with the albedo used to colorize the surface. While intermediate values are not physically accurate, they may be used to emulate subsurfaces which are partially metallic. See the [[Physically Based Rendering|PBR metal workflow]] for details.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parameters (Metallic - Alpha Channel) Texture Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[File:m_leafcard_8.jpg|border|middle|x300px]]&lt;br /&gt;
&lt;br /&gt;
=Examples=&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Material types| ]]&lt;br /&gt;
[[Category:Modeling]]&lt;br /&gt;
[[Category:Content creation]]&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=M.leafcardbillboard&amp;diff=42190</id>
		<title>M.leafcardbillboard</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=M.leafcardbillboard&amp;diff=42190"/>
		<updated>2024-06-10T05:23:44Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[m.leafcardbillboard]] is a camera-facing variation of the [[m.leafcard]] material, introduced as part of the &amp;quot;[[Treez]]&amp;quot; foliage system. It is used when creating leaves and minor branches for trees and plants, and is tuned to provide visual outcomes which are suitable for this usage. This may result in subtle rendering differences when compared to the standard materials such as [[m.pbrmetal]]. The exact nature of these differences may change in the future. These differences make [[m.leafcardbillboard]] unsuitable as a general-purpose billboard material.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:m_leaf_card_billboard_tree_1.jpg|400px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This page describes [[&amp;quot;Trainz-build&amp;quot; number|Content Format v5.6]] and requires that the [[FBX file format]] is used as a data source for any meshes.&lt;br /&gt;
&lt;br /&gt;
We recommend using the free PlantFactory software to create trees with this material type. Detailed tutorials are available on the [[Treez]] page.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Camera Facing Leaf Cards=&lt;br /&gt;
&lt;br /&gt;
[[Image:m_leaf_card_billboard_cam_face_1.gif|500px]]&lt;br /&gt;
&lt;br /&gt;
If you are using a standard 3D modelling program to create your trees and wish to use camera facing leaf cards then you must point your leaf cards in the positive X direction. Each leaf card must be configured as a separate mesh within the FBX file so they can rotate separately.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:leaf_card_blender.jpg|400px]] [[Image:leaf_card_blender_2.jpg|384px]] [[Image:leaf_card_blender_3.jpg|350px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Texture Slots=&lt;br /&gt;
The following texture slots are used for this material. All textures should typically have the same dimensions unless they represent a uniform color, however this is not strictly enforced.&lt;br /&gt;
&lt;br /&gt;
==Albedo==&lt;br /&gt;
RGB: The [[albedo map]] defines the base color of each texel. The sRGB color space is used.&lt;br /&gt;
&lt;br /&gt;
A: The alpha channel provides an opacity channel. Black indicates full transparency, meaning that the [[fragment]] is discarded. White indicates full opacity. Shades of gray are supported, which represent partial transparency. The alpha channel may be heavily quantised.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Albedo Texture Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[File:m_leafcard_billboard_1.png|300px]]&lt;br /&gt;
&lt;br /&gt;
Color Channel Separated&lt;br /&gt;
&lt;br /&gt;
[[File:m_leafcard_billboard_2.jpg|300px]]&lt;br /&gt;
&lt;br /&gt;
Alpha Channel Separated&lt;br /&gt;
&lt;br /&gt;
[[File:m_leafcard_billboard_2b.jpg|300px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Normal==&lt;br /&gt;
RGB: Surface [[normal map]]. This defines which way the surface is facing, relative to the interpolated vertex normals. Since this is an XYZ format rather than color data, it should never be modified in Photoshop. Using Photoshop to add a fourth channel or copy/paste smaller textures into a [[texture atlas]] is acceptable. Per-pixel manipulation or use of filters on the &amp;quot;RGB&amp;quot; channels is not acceptable.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Normal Texture Example with no Alpha Channel (Parallax)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[File:m_leafcard_billboard_3.jpg|border|middle|x300px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Parameter==&lt;br /&gt;
This texture is comprised of four separate channels which each form a separate data element. Linear color space (not sRGB) is used for these channels.&lt;br /&gt;
&lt;br /&gt;
[[File:m_leafcard_billboard_4.jpg|border|middle|800px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
R: Emissive. This causes the texture to have an internal glow, even when no external light is present. Used for phosphors, permanently-lit markings, etc. The glow color is based on the albedo. Note that this glow does not cast light upon surrounding surfaces except via the Bloom post-processing effect.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parameters (Emissive - Red Channel) Texture Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[File:m_leafcard_5.jpg|border|middle|x300px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
G: Roughness. Defines whether the surface reflections are shiny (0.0) or matte (1.0). See the [[Physically Based Rendering|PBR metal workflow]] for details.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parameters (Roughness - Green Channel) Texture Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[File:m_leafcard_billboard_6.jpg|border|middle|x300px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
B: The blue channel of the parameters texture is used to modulate the strength of the directional lighting. This is intended to give the feel of individual leaves being deeper inside the tree and shadowed from all directions, even though the leaf card as a whole is not shadowed. (Note that this is the same channel used for Ambient Occlusion on m.pbrmetal; the leaf card materials do not support ambient occlusion.)&lt;br /&gt;
&lt;br /&gt;
Full brightness (100% blue channel) gives a standard lighting response, while darker values give a weaker response to directional lighting.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parameters (Directional Lighting Strength - Blue Channel) Texture Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[File:m_leafcard_billboard_7.jpg|border|middle|x300px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A: Metallicity. Defines whether the surface is metallic (1.0) with the albedo used to colorize reflected light, or dielectric (0.0) with the albedo used to colorize the surface. While intermediate values are not physically accurate, they may be used to emulate subsurfaces which are partially metallic. See the [[Physically Based Rendering|PBR metal workflow]] for details.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parameters (Metallic - Alpha Channel) Texture Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[File:m_leafcard_8.jpg|border|middle|x300px]]&lt;br /&gt;
&lt;br /&gt;
=Examples=&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Material types| ]]&lt;br /&gt;
[[Category:Modeling]]&lt;br /&gt;
[[Category:Content creation]]&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=M.leafcard&amp;diff=42189</id>
		<title>M.leafcard</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=M.leafcard&amp;diff=42189"/>
		<updated>2024-06-10T05:17:44Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[m.leafcard]] is a new material introduced as part of the &amp;quot;[[Treez]]&amp;quot; foliage system. It is used when creating leaves and minor branches for trees and plants, and is tuned to provide visual outcomes which are suitable for this usage. This may result in subtle rendering differences when compared to the standard materials such as [[m.pbrmetal]]. The exact nature of these differences may change in the future. These differences make [[m.leafcard]] unsuitable as a general-purpose material.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:m_leaf_card_tree_1.jpg|400px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This page describes  [[&amp;quot;Trainz-build&amp;quot; number|Content Format v5.6]] and requires that the FBX file format is used as a data source for any meshes.&lt;br /&gt;
&lt;br /&gt;
We recommend using the free PlantFactory software to create trees with this material type. Detailed tutorials are available on the [[Treez]] page.&lt;br /&gt;
&lt;br /&gt;
=Texture Slots=&lt;br /&gt;
The following texture slots are used for this material. All textures should typically have the same dimensions unless they represent a uniform color, however this is not strictly enforced.&lt;br /&gt;
&lt;br /&gt;
==Albedo==&lt;br /&gt;
RGB: The [[albedo map]] defines the base color of each texel. The sRGB color space is used.&lt;br /&gt;
&lt;br /&gt;
A: The alpha channel provides an opacity channel. Black indicates full transparency, meaning that the [[fragment]] is discarded. White indicates full opacity. Shades of gray are supported, which represent partial transparency. The alpha channel may be heavily quantised.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Albedo Texture Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[File:m_leafcard_1.png|300px]]&lt;br /&gt;
&lt;br /&gt;
Color Channel Separated&lt;br /&gt;
&lt;br /&gt;
[[File:m_leafcard_2.jpg|300px]]&lt;br /&gt;
&lt;br /&gt;
Alpha Channel Separated&lt;br /&gt;
&lt;br /&gt;
[[File:m_leafcard_2b.jpg|300px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Normal==&lt;br /&gt;
RGB: Surface [[normal map]]. This defines which way the surface is facing, relative to the interpolated vertex normals. Since this is an XYZ format rather than color data, it should never be modified in Photoshop. Using Photoshop to add a fourth channel or copy/paste smaller textures into a [[texture atlas]] is acceptable. Per-pixel manipulation or use of filters on the &amp;quot;RGB&amp;quot; channels is not acceptable.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Normal Texture Example with no Alpha Channel (Parallax)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[File:m_leafcard_3.jpg|border|middle|x300px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Parameter==&lt;br /&gt;
This texture is comprised of four separate channels which each form a separate data element. Linear color space (not sRGB) is used for these channels.&lt;br /&gt;
&lt;br /&gt;
[[File:m_leafcard_4.jpg|border|middle|800px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
R: Emissive. This causes the texture to have an internal glow, even when no external light is present. Used for phosphors, permanently-lit markings, etc. The glow color is based on the albedo. Note that this glow does not cast light upon surrounding surfaces except via the Bloom post-processing effect.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parameters (Emissive - Red Channel) Texture Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[File:m_leafcard_5.jpg|border|middle|x300px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
G: Roughness. Defines whether the surface reflections are shiny (0.0) or matte (1.0). See the [[Physically Based Rendering|PBR metal workflow]] for details.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parameters (Roughness - Green Channel) Texture Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[File:m_leafcard_6.jpg|border|middle|x300px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
B: The blue channel of the parameters texture is used to modulate the strength of the directional lighting. This is intended to give the feel of individual leaves being deeper inside the tree and shadowed from all directions, even though the leaf card as a whole is not shadowed. (Note that this is the same channel used for Ambient Occlusion on m.pbrmetal; the leaf card materials do not support ambient occlusion.)&lt;br /&gt;
&lt;br /&gt;
Full brightness (100% blue channel) gives a standard lighting response, while darker values give a weaker response to directional lighting.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parameters (Directional Lighting Strength - Blue Channel) Texture Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[File:m_leafcard_7.jpg|border|middle|x300px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A: Metallicity. Defines whether the surface is metallic (1.0) with the albedo used to colorize reflected light, or dielectric (0.0) with the albedo used to colorize the surface. While intermediate values are not physically accurate, they may be used to emulate subsurfaces which are partially metallic. See the [[Physically Based Rendering|PBR metal workflow]] for details.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parameters (Metallic - Alpha Channel) Texture Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[File:m_leafcard_8.jpg|border|middle|x300px]]&lt;br /&gt;
&lt;br /&gt;
=Examples=&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Material types| ]]&lt;br /&gt;
[[Category:Modeling]]&lt;br /&gt;
[[Category:Content creation]]&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=Treez&amp;diff=42180</id>
		<title>Treez</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=Treez&amp;diff=42180"/>
		<updated>2024-06-10T04:36:15Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Image:treez.png|250px|link=https://info.trainzsimulator.com/trainz-plus/#treez]]   [[Image:trainz_trees_join_the_beta.jpg|250px|link=https://forms.gle/cQTjZxixZeCT3DHS7]]   [[Image:discord_community_trees_foliage.jpg|250px|link=https://discord.gg/WgQ5VbUdar]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Software Requirements=&lt;br /&gt;
&lt;br /&gt;
This is a step by step tutorial that will teach you how to create a 3D TREE model for use in Trainz. This method uses PlantFactory (free software) to create the 3D tree model but you could use Blender or any other 3D modelling software in its place. The principles are the same.&lt;br /&gt;
&lt;br /&gt;
Before you start you will need:&lt;br /&gt;
&lt;br /&gt;
* A copy of [[&amp;quot;Trainz-build&amp;quot; number|Trainz version 5.6]] or newer. Currently this is in development so in order to test this new foliage system you must be part of the BETA - [https://forms.gle/cQTjZxixZeCT3DHS7 JOIN].&lt;br /&gt;
&lt;br /&gt;
* A copy of [https://www.bentley.com/software/e-on-software-free-downloads/ PlantFactory 2024]. Click the Download button on that page, agree to the EULA and the next page the software should show for download.&lt;br /&gt;
&lt;br /&gt;
* You need a set of textures (Bark and Leaves at a minimum) for your trees. These can be created from scratch using the likes of [https://www.adobe.com/au/products/photoshop.html Photoshop] (paid) or [https://www.gimp.org GIMP] (free). You can look to source them from many different websites including [https://substance3d.adobe.com/assets/allassets?q=leaf%20fir%20branch&amp;amp;sort=-searchScore Adobe Substance Library] or other stock places. There are many other places you can purchase tree stock as a base or to get ideas to build from including [https://www.cgtrader.com/search?keywords=tree CGTrader] and [https://www.turbosquid.com/Search/Index.cfm?keyword=tree&amp;amp;media_typeid=2 TurboSquid].&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
=PlantFactory Examples=&lt;br /&gt;
&lt;br /&gt;
A good place to start is with one of our PlantFactory templates. This can speed up your development a lot, especially if you are new to PlantFactory.&lt;br /&gt;
&lt;br /&gt;
[https://images.n3vgames.com/uploads/content_creation/trainz_pf_basic_tree_example_files.zip Download Youtube Video 1 Example Files]&lt;br /&gt;
&lt;br /&gt;
[https://images.n3vgames.com/uploads/content_creation/trainz_pf_tree_1_example_files.zip Download Youtube Video 2 Example Files]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Tree Asset Creation Overview=&lt;br /&gt;
&lt;br /&gt;
Trees are created as standard [[KIND Scenery|scenery]] assets.&lt;br /&gt;
&lt;br /&gt;
They use the [[FBX file format]] for their mesh files.&lt;br /&gt;
&lt;br /&gt;
.PNG or .TGA is recommended for the [[Texture file|textures]].&lt;br /&gt;
&lt;br /&gt;
Trees may use standard materials, but benefit heavily from the new foliage-specific materials are outlined below.&lt;br /&gt;
&lt;br /&gt;
The texture setup is outlined below.&lt;br /&gt;
&lt;br /&gt;
You should try and keep the highest LOD under 5000 polygons. Each additional LOD level should drop down by at least 25%. Your lowest LOD should be under 1000 polygons, ideally under 500 polygons. There is no need to create bottom-LOD billboards as Trainz will create this for you using a new [[Imposter system]] that will release alongside [[Treez]].&lt;br /&gt;
&lt;br /&gt;
If using PlantFactory you will want to get the example files above and look at the [[Mesh metadata file]]s to determine what additional tags are being used. You will also want to watch the PlantFactory video information below to understand how to use the program and also how to export from PlantFactory, setup your Trainz Asset and import into Trainz.&lt;br /&gt;
&lt;br /&gt;
If you are using another 3D modelling program to create your trees and want to use [[m.leafcardbillboard|camera facing leaf cards]] then you must point your leaf card geometry in the positive X direction. Each leaf card must be a separate mesh within the FBX so they can rotate separately.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:leaf_card_blender.jpg|400px]] [[Image:leaf_card_blender_2.jpg|384px]] [[Image:leaf_card_blender_3.jpg|350px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Materials=&lt;br /&gt;
&lt;br /&gt;
There are two new materials to use for trees.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;[[m.leafcard]]&#039;&#039;&#039; - Use this material for your transparent leaf cards that are not camera facing. This material structure is identical to [[m.pbrmetal]]. The only difference in setup is the name of your material.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;[[m.leafcardbillboard]]&#039;&#039;&#039; - Use this material for your transparent leaf cards that are to be camera facing. This material structure is identical to [[m.pbrmetalmasked]]. The only difference in setup is the name of your material.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Textures=&lt;br /&gt;
&lt;br /&gt;
The makeup of both [[m.leafcard]] and [[m.leafcardbillboard]] is similar to [[m.pbrmetalmasked]].&lt;br /&gt;
&lt;br /&gt;
The one exception is that the blue channel in the parameters texture is used to modulate the strength of the directional lighting. This is intended to give the feel of individual leaves being deeper inside the tree and shadowed from all directions, even though the leaf card as a whole is not shadowed. (Note that this is the same channel used for Ambient Occlusion on m.pbrmetal; the leaf card materials do not support ambient occlusion.)&lt;br /&gt;
&lt;br /&gt;
Full brightness (100% blue channel) gives a standard lighting response, while darker values give a weaker response to directional lighting.&lt;br /&gt;
&lt;br /&gt;
Here is an example of what the blue (AO) channel could look like in the parameters texture for both [[m.leafcard]] and [[m.leafcardbillboard]].&lt;br /&gt;
&lt;br /&gt;
[[Image:directional_light_Scattering.jpg|400px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=PlantFactory Tutorial=&lt;br /&gt;
&lt;br /&gt;
Once the software starts up and you&#039;ve either loaded one of the templates above or you&#039;ve started a new tree from scratch, if you are new to PlantFactory, you will want to read the &amp;quot;PlantFactory — Reference Manual&amp;quot; (specifically &#039;Section 5 - Modifying Plants: Using Parameters&#039;) which can be accessed by clicking on the Main Menu -&amp;gt; Help -&amp;gt; Reference Manual. This manual explains everything you need to know about the software. It is definitely worth the read.&lt;br /&gt;
&lt;br /&gt;
For those that want to come back to the manual later, here is a video breakdown on a very raw PlantFactory / Trainz explanation you can get started with.&lt;br /&gt;
&lt;br /&gt;
[[Image:plantfactory_trainz_1.jpg|750px|link=https://www.youtube.com/watch?v=pNY0kHEqsTQ]]&lt;br /&gt;
&lt;br /&gt;
[[Image:plantfactory_trainz_2.jpg|750px|link=https://www.youtube.com/watch?v=c-LA4VkZrvs]]&lt;br /&gt;
&lt;br /&gt;
===Work-in-Progress Test Trees===&lt;br /&gt;
&lt;br /&gt;
There isn&#039;t one way to create trees in PlantFactory but these trees were created using the procedural node method.&lt;br /&gt;
&lt;br /&gt;
[[Image:plantfactory_trainz_0_i.jpg|300px]]&lt;br /&gt;
[[Image:plantfactory_trainz_0_g.jpg|300px]]&lt;br /&gt;
&lt;br /&gt;
[[Image:plantfactory_trainz_2_i.jpg|300px]]&lt;br /&gt;
[[Image:plantfactory_trainz_2_g.jpg|300px]]&lt;br /&gt;
&lt;br /&gt;
[[Image:plantfactory_trainz_3_i.jpg|300px]]&lt;br /&gt;
[[Image:plantfactory_trainz_3_g.jpg|300px]]&lt;br /&gt;
&lt;br /&gt;
[[Image:plantfactory_trainz_4a_i.jpg|300px]]&lt;br /&gt;
[[Image:plantfactory_trainz_4b_i.jpg|300px]]&lt;br /&gt;
[[Image:plantfactory_trainz_4_g.jpg|300px]]&lt;br /&gt;
&lt;br /&gt;
[[Image:plantfactory_trainz_5a_i.jpg|300px]]&lt;br /&gt;
[[Image:plantfactory_trainz_5b_i.jpg|300px]]&lt;br /&gt;
[[Image:plantfactory_trainz_5_g.jpg|300px]]&lt;br /&gt;
&lt;br /&gt;
[[Image:plantfactory_trainz_6_i.jpg|300px]]&lt;br /&gt;
[[Image:plantfactory_trainz_6_g.jpg|300px]]&lt;br /&gt;
&lt;br /&gt;
[[Image:plantfactory_trainz_7_i.jpg|300px]]&lt;br /&gt;
[[Image:plantfactory_trainz_7_g.jpg|300px]]&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=Mesh_metadata_file&amp;diff=42176</id>
		<title>Mesh metadata file</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=Mesh_metadata_file&amp;diff=42176"/>
		<updated>2024-06-10T04:18:16Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The [[Mesh metadata file]] allows content creators to control various mesh and material attributes which may not be available in standard modelling packages, or are not exported to the [[FBX file format]].&lt;br /&gt;
&lt;br /&gt;
It exists as an optional &amp;quot;&amp;lt;mesh-file-name&amp;gt;.txt&amp;quot; file included alongside the &amp;quot;&amp;lt;mesh-file-name&amp;gt;.fbx&amp;quot; file. Where attributes are specified in this metadata file, they override any entries read from the FBX file itself. If an attribute is not specified, it is calculated from the FBX file.&lt;br /&gt;
&lt;br /&gt;
=Validation=&lt;br /&gt;
Mesh metadata files are in a simple text format similar to the [[config.txt]] format. They are not currently validated in any fashion beyond basic readability; if you mis-type a tag it will simply be ignored by the reader. Do not rely on this behaviour- we may add validation in the future and it may apply retroactively.&lt;br /&gt;
&lt;br /&gt;
=&#039;materials&#039; array=&lt;br /&gt;
&lt;br /&gt;
 materials&lt;br /&gt;
 {&lt;br /&gt;
   material_name_a&lt;br /&gt;
   {&lt;br /&gt;
     ..&lt;br /&gt;
   }&lt;br /&gt;
   material_name_b&lt;br /&gt;
   {&lt;br /&gt;
     ..&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;materials&amp;quot; array allows the creator to override attributes of the various materials present within the FBX file. Only the specified materials and attributes are overridden, all other materials and attributes are configured in the normal fashion. Each element in the array must be named exactly as per a single material in the FBX file, including any name suffixes.&lt;br /&gt;
&lt;br /&gt;
Each material may be configured with the following attributes:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==two-sided==&lt;br /&gt;
&lt;br /&gt;
 two-sided 0&lt;br /&gt;
&lt;br /&gt;
A boolean (0 / 1) value which indicates whether chunks which use this material should be rendered as two-sided (no backface culling) or one-sided (regular backface culling).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==blend-mode==&lt;br /&gt;
&lt;br /&gt;
 blend-mode opaque&lt;br /&gt;
&lt;br /&gt;
The &#039;blend-mode&#039; tag supports the following values:&lt;br /&gt;
** &#039;alpha-blend&#039; - Chunks which use this material are rendered using a true alpha blend. Due to technical limitations, render ordering of overlapping alpha-blend materials may be incorrect. This is not considered a bug; it is the creator&#039;s responsibility to avoid this becoming problematic.&lt;br /&gt;
** &#039;alpha-to-coverage&#039; - Chunks which use this material are rendered using alpha-to-coverage. This technique is a fast approximation of alpha which sacrifices some visual detail in favour of performance and depth-independance.&lt;br /&gt;
** &#039;alpha-masked&#039; - Chunks which use this material are rendered using alpha masking. This technique discards pixels with low diffuse alpha values, resulting in holes in the geometry.&lt;br /&gt;
** &#039;opaque&#039; - Chunks which use this material are rendered fully opaque.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==material-type==&lt;br /&gt;
&lt;br /&gt;
 material-type onetex&lt;br /&gt;
&lt;br /&gt;
A string which specifies the [[Material_Types|material type]] to use. This causes the game to ignore any material type suffix on the material name. Be careful when overriding material types in this manner, as other requirements (such as texture slot bindings) may vary between material types. The material type string does not include a leading &amp;quot;m.&amp;quot; - so &amp;quot;notex&amp;quot; is a valid entry here, but &amp;quot;m.notex&amp;quot; is not.&lt;br /&gt;
&lt;br /&gt;
==textures==&lt;br /&gt;
&lt;br /&gt;
 textures&lt;br /&gt;
 {&lt;br /&gt;
   albedo&lt;br /&gt;
   {&lt;br /&gt;
     texture-resource &amp;quot;my-albedo.texture&amp;quot;&lt;br /&gt;
   }&lt;br /&gt;
   normal&lt;br /&gt;
   {&lt;br /&gt;
     texture-resource &amp;quot;my-normal.texture&amp;quot;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
A subcontainer list with zero or more texture containers. Each texture container is named for the material texture slot to which the texture is to be assigned (&amp;quot;albedo&amp;quot;, &amp;quot;normal&amp;quot;, &amp;quot;parameter&amp;quot;, &amp;quot;detail-albedo&amp;quot; or &amp;quot;detail-normal&amp;quot;). If this list is present at all, it overrides ALL automatic texture assignment from the FBX file for the parent material; a partial override is not supported. The following subtags are accepted within each texture container:&lt;br /&gt;
&lt;br /&gt;
===texture-resource===&lt;br /&gt;
A string which provides the texture resource name (eg. &amp;quot;foo.texture&amp;quot;). As always, texture resource names are equivalent to [[Texture.txt file]] names without the trailing &amp;quot;.txt&amp;quot;. The texture files must be present within the same asset as the mesh. The resource name may include sub-folder or parent-folder path prefixes, which are resolved relative to the folder containing the metadata file.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==bend-normals-upward-ratio==&lt;br /&gt;
&lt;br /&gt;
 bend-normals-upward-ratio 0.0&lt;br /&gt;
&lt;br /&gt;
The &#039;bend-normals-upward-ratio&#039; tag allows the input normals to be reoriented towards the sky.&lt;br /&gt;
&lt;br /&gt;
The default value (0.0) will not modify the mesh normals imported from FBX. The maximal value (1.0) will force the normals to point directly upward. Mid-range values may be used, although care should be taken with normals which are pointing straight downward to start with. As Trainz is Z-up, &amp;quot;directly upward&amp;quot; means (0.0, 0.0, 1.0).&lt;br /&gt;
&lt;br /&gt;
Supported in [[&amp;quot;Trainz-build&amp;quot; number|content format v4.8]] and later.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==clutter-wind-type==&lt;br /&gt;
&lt;br /&gt;
 clutter-wind-type none&lt;br /&gt;
&lt;br /&gt;
This tag only applies to materials of type [[m.foliage]]. Supported values are &amp;quot;none&amp;quot; (default), &amp;quot;vertex-color&amp;quot;, and &amp;quot;position-z&amp;quot;. The details of this attribute can be found [[m.foliage|here]].&lt;br /&gt;
&lt;br /&gt;
Supported in [[&amp;quot;Trainz-build&amp;quot; number|content format v5.4]] and later. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==clutter-sample-method==&lt;br /&gt;
&lt;br /&gt;
 clutter-sample-method origin&lt;br /&gt;
&lt;br /&gt;
This only applies pertains to materials of type [[m.foliage]]. Supported values are &amp;quot;origin&amp;quot; (default), &amp;quot;node-origin&amp;quot;, &amp;quot;per-vertex&amp;quot;, and &amp;quot;contiguous-geometry&amp;quot;. The details of this attribute can be found [[m.foliage|here]].&lt;br /&gt;
&lt;br /&gt;
Supported in [[&amp;quot;Trainz-build&amp;quot; number|content format v5.4]] and later.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==clutter-geometry-root==&lt;br /&gt;
&lt;br /&gt;
 clutter-geometry-root bottom&lt;br /&gt;
&lt;br /&gt;
This only applies pertains to materials of type [[m.foliage]]. Supported values are &amp;quot;bottom&amp;quot; (default), &amp;quot;top&amp;quot;, and &amp;quot;center&amp;quot;. The details of this attribute can be found [[m.foliage|here]].&lt;br /&gt;
&lt;br /&gt;
Supported in [[&amp;quot;Trainz-build&amp;quot; number|content format v5.4]] and later.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==fadeInEndDistance==&lt;br /&gt;
&lt;br /&gt;
 fadeInEndDistance 0.0&lt;br /&gt;
&lt;br /&gt;
This only applies pertains to materials of type [[m.foliage]] and [[m.clutter]]. This defines the fade-in distance for materials of this chunk. Below this distance, chunks of this material are fully transparent and thus invisible (but still rendered; this is not a performance optimisation). Beyond this distance, the chunks start to become opaque.&lt;br /&gt;
&lt;br /&gt;
This is typically used in conjunction with [[Mesh-table LOD]] to allow cross-fading between clutter LODs. The LOD transitions offer performance gains, while the cross-fading pays a small performance penalty but reduces potentially jarring visuals.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==fadeOutEndDistance==&lt;br /&gt;
&lt;br /&gt;
 fadeOutEndDistance 200.0&lt;br /&gt;
&lt;br /&gt;
This only applies pertains to materials of type [[m.foliage]] and [[m.clutter]]. This defines the fade-out distance for materials of this chunk. Beyond this distance, chunks of this material are fully transparent and thus invisible (but still rendered; this is not a performance optimisation). Below this distance, the chunks start to become opaque.&lt;br /&gt;
&lt;br /&gt;
This is typically used in conjunction with [[Mesh-table LOD]] to allow cross-fading between clutter LODs. The LOD transitions offer performance gains, while the cross-fading pays a small performance penalty but reduces potentially jarring visuals.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==detail-scale==&lt;br /&gt;
&lt;br /&gt;
 detail-scale 0.09&lt;br /&gt;
&lt;br /&gt;
This only applies pertains to materials of type [[m.pbrmetaldetail]]. This controls the scaling ratio between the regular texture and the detail texture. The tag has a minimum value of 0.001.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==diffuse-color==&lt;br /&gt;
&lt;br /&gt;
 diffuse-color 1.0, 1.0, 1.0, 1.0&lt;br /&gt;
&lt;br /&gt;
The &#039;diffuse-color&#039; tag allows the RGBA diffuse color of the material to be overridden. The standard RGB color range is between 0.0 and 1.0, but higher (HDR) numbers are permitted. This does not add a new capability to the material; it is ignored where the material does not support a diffuse color input.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==emissive-color==&lt;br /&gt;
&lt;br /&gt;
 emissive-color 0.0, 0.0, 0.0, 0.0&lt;br /&gt;
&lt;br /&gt;
The &#039;emissive-color&#039; tag allows the RGBA emissive color of the material to be overridden. The standard RGB color range is between 0.0 and 1.0, but higher (HDR) numbers are permitted. This does not add a new capability to the material; it is ignored where the material does not support an emissive color input.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==specular-color==&lt;br /&gt;
&lt;br /&gt;
 specular-color 1.0, 1.0, 1.0, 1.0&lt;br /&gt;
&lt;br /&gt;
The &#039;specular-color&#039; tag allows the RGBA specular color of the material to be overridden. The standard RGB color range is between 0.0 and 1.0, but higher (HDR) numbers are permitted. This does not add a new capability to the material; it is ignored where the material does not support a specular color input.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==specular-power==&lt;br /&gt;
&lt;br /&gt;
 specular-power 10.0&lt;br /&gt;
&lt;br /&gt;
The &#039;specular-power&#039; tag allows the specular power of the material to be overridden. The value must be between 10.0 and 128.0 inclusive. This does not add a new capability to the material; it is ignored where the material does not support a specular power input.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=rotate-mesh=&lt;br /&gt;
&lt;br /&gt;
  rotate-mesh 90, 0, 0&lt;br /&gt;
&lt;br /&gt;
The &#039;rotate-mesh&#039; tag allows the entire input mesh to be rotated on import. This is useful in cases where the orientation of the mesh is incorrect, but the FBX file cannot be regenerated or cannot easily be rotated in the modeller application. The three parameters describe an Euler rotation (roll, pitch, yaw) expressed in degrees.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Mesh Metadata File Example =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;materials&lt;br /&gt;
{&lt;br /&gt;
  example0&lt;br /&gt;
  {&lt;br /&gt;
    two-sided 1&lt;br /&gt;
    material-type &amp;quot;pbrmetal&amp;quot;&lt;br /&gt;
    bend-normals-upward-ratio 0.0&lt;br /&gt;
    textures&lt;br /&gt;
    {&lt;br /&gt;
      albedo&lt;br /&gt;
      {&lt;br /&gt;
        texture-resource &amp;quot;albedo.texture&amp;quot;&lt;br /&gt;
      }&lt;br /&gt;
      normal&lt;br /&gt;
      {&lt;br /&gt;
        texture-resource &amp;quot;normal.texture&amp;quot;&lt;br /&gt;
      }&lt;br /&gt;
      parameter&lt;br /&gt;
      {&lt;br /&gt;
        texture-resource &amp;quot;parameter.texture&amp;quot;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  example1.m.onetex&lt;br /&gt;
  {&lt;br /&gt;
    two-sided 1&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=HowTo/Upgrade_obsolete_script_functions&amp;diff=32804</id>
		<title>HowTo/Upgrade obsolete script functions</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=HowTo/Upgrade_obsolete_script_functions&amp;diff=32804"/>
		<updated>2022-06-21T05:38:07Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page serves as a hub for how to upgrade/replace uses of various obsolete script functions.&lt;br /&gt;
&lt;br /&gt;
Note that this is not a comprehensive list. Trainz has existed for more than two decades and there are dozens of obsolete script functions as a result. This guide aims to cover only the more complex upgrade cases, where the replacement functions may not be immediately obvious, or may be considerably more difficult to use.&lt;br /&gt;
&lt;br /&gt;
__NOEDITSECTION__&lt;br /&gt;
==GameObject.GetId==&lt;br /&gt;
&#039;&#039;&#039;Previous Usage&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Returns a numeric ID used to identify a GameObject within the script context. This ID is not consistent between Route/Session loads and cannot be used for long term storage.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Reason for Obsoletion&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
With the advent of [[Asynchronous_Route_Streaming|Route streaming]] world objects may now be unloaded/reloaded during gameplay, and these IDs can be reused by different objects. This makes the ID itself unreliable, and uses of it are better served by more modern functions.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Replacement Function&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Standard uses of the integer ID can be swapped to using the objects GameObjectID instead. Call GameObject.GetGameObject() to get the ID.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Further Reading&#039;&#039;&#039;&lt;br /&gt;
* See GameObjectID.gs in your Trainz installations resources/script folder for more information on the GameObjectID class.&lt;br /&gt;
* See [[HowTo/Upgrade_GameObject.GetId()]] for a practical example of how to replace some common integer ID uses with GameObjectID.&lt;br /&gt;
&lt;br /&gt;
==GameObject.GetName==&lt;br /&gt;
&#039;&#039;&#039;Previous Usage&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Returns a string ID used to identify a GameObject within the script context. This ID is automatically generated by Trainz code, using the object type or asset name as a prefix. It can generally be considered constant between runs of the game, and was therefore suitable for long term storage.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Reason for Obsoletion&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
This script name was often confused for the objects localised (translatable) name, and (despite script comments to the contrary) was never truly guaranteed unique.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Replacement Function&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Cases which use of the script name as an ID can be swapped to using the objects GameObjectID instead. Cases which use it for display to the player should instead use the localised name.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Further Reading&#039;&#039;&#039;&lt;br /&gt;
* See GameObjectID.gs in your Trainz installations resources/script folder for more information on the GameObjectID class.&lt;br /&gt;
* See [[HowTo/Upgrade_GameObject.GetName()]] for a practical example of how to replace some common script name uses with GameObjectID or localised name.&lt;br /&gt;
&lt;br /&gt;
==Router.GetGameObject==&lt;br /&gt;
&#039;&#039;&#039;Previous Usage&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Returns a GameObject instance from either it&#039;s script name or integer ID.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Reason for Obsoletion&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
As both GetId() and GetName() are obsolete, both the string and int variants of this function are also obsolete. See GameObject.GetId and GameObject.GetName above for more information.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Replacement Function&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
All uses of the integer ID and script name identifiers should be replaced with GameObjectID. To retrieve an GameObject which is currently loaded into memory, a script may then call Router.GetGameObject(GameObjectID) or World.GetGameObjectByIDIfLoaded(GameObjectID).&lt;br /&gt;
&lt;br /&gt;
If a script requires access to an object which may not be loaded, it may call World.GetGameObjectByID(GameObjectID) to request that native code loads the object. Note that this requires native code to load the entire tile/section that the object is in, which may impact performance, and may take some time. As the call may take a while, it behaves asynchronously, returning a [[Class_AsyncObjectSearchResult|AsyncObjectSearchResult]] to the caller.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Further Reading&#039;&#039;&#039;&lt;br /&gt;
* See GameObjectID.gs in your Trainz installations resources/script folder for more information on the GameObjectID class.&lt;br /&gt;
* See [[HowTo/Upgrade_GameObject.GetName()]] for a practical example of how to upgrade uses of Router.GetGameObject(string).&lt;br /&gt;
&lt;br /&gt;
==World.Get*List==&lt;br /&gt;
&#039;&#039;&#039;Previous Usage&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
These functions (e.g. World.GetJunctionList()) were used to return a list of a particular type of items within the World.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Reason for Obsoletion&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
The functions represented a considerable performance hit, especially on large Routes. With the advent of [[Asynchronous_Route_Streaming|Route streaming]] they are also only able to return objects which are currently loaded, limiting their usefulness.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Replacement Function&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Due to the inherent performance concerns it is no longer possible to synchronously query for a list of objects within the world. Instead, an asynchronous interface now exists to run searches for objects of a particular type or name, World.GetNamedObjectList(). This function takes a category string and partial name, and returns a list of matching objects. Both parameters are optional, but at least one must be provided. The function returns a [[Class_AsyncObjectSearchResult|AsyncObjectSearchResult]] to the caller.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Further Reading&#039;&#039;&#039;&lt;br /&gt;
* See [[HowTo/Search_for_objects_in_the_world]] for a practical example of how to list objects using category codes.&lt;br /&gt;
&lt;br /&gt;
==Asset.GetConfigSoup==&lt;br /&gt;
&#039;&#039;&#039;Previous Usage&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
This function returns the config.txt file for an asset, as a Soup object.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Reason for Obsoletion&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Calls to this function may require loading an asset config file from disk, which can be very slow (in computational terms). For this reason, the function has been marked obsolete to avoid performance issues in script.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Replacement Function&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
A new async query interface exists on Asset which will cache the config file on a background thread. To use this feature script must first call Asset.CacheConfigSoup(), and then wait on the returned AsyncQueryHelper. When the caching is complete, the caller may call Asset.GetConfigSoupCached() to get the config file Soup.&lt;br /&gt;
&lt;br /&gt;
==Asset.GetStringTable==&lt;br /&gt;
&#039;&#039;&#039;Previous Usage&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
This function returns the localised string-table from the config.txt file for an asset.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Reason for Obsoletion&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Calls to this function may require loading an asset config file from disk, which can be very slow (in computational terms). For this reason, the function has been marked obsolete to avoid performance issues in script.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Replacement Function&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
A new async query interface exists on Asset which will cache the config file on a background thread. To use this feature script must first call Asset.CacheConfigSoup(), and then wait on the returned AsyncQueryHelper. When the caching is complete, the caller may call Asset.GetStringTable() to get the StringTable.&lt;br /&gt;
&lt;br /&gt;
==TrainzScript.GetAssetList==&lt;br /&gt;
&#039;&#039;&#039;Previous Usage&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
This function is used to return a list of installed assets of a given kind (e.g. &amp;quot;signal&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Reason for Obsoletion&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Asset searches can be very slow, and this function was marked obsolete for performance reasons.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Replacement Function&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
A much more powerful asset search system exists in [[Class_TrainzAssetSearch|TrainzAssetSearch]]. This class allows script to asynchronously search on any criteria, eliminating the performance concerns.&lt;br /&gt;
&lt;br /&gt;
==TrainzScript.SearchAssets==&lt;br /&gt;
&#039;&#039;&#039;Previous Usage&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
This function is used to return a list of assets of a given asset category filter.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Reason for Obsoletion&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Asset searches can be very slow, and this function was marked obsolete for performance reasons.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Replacement Function&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
A much more powerful asset search system exists in [[Class_TrainzAssetSearch|TrainzAssetSearch]]. This class allows script to asynchronously search on any criteria, eliminating the performance concerns.&lt;br /&gt;
&lt;br /&gt;
==Router.MESSAGE_BROADCAST==&lt;br /&gt;
&#039;&#039;&#039;Previous Usage&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
This pseudo router ID was used to post a message to ALL game objects.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Reason for Obsoletion&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Broadcasting is inefficient by nature, and the same effects can be achieved by having scripts listen (via Sniff() or AddHandler()) to the specific objects and messages that they&#039;re interested in. Additionally, game objects have a limited message queue capacity, so with large numbers of objects broadcasting it was common to overflow the message queues and permanently lose messages, leading to unexpected and unpredictable outcomes. Finally, with [[Asynchronous Route Streaming]], broadcasts do not actually reach all objects in the route. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Replacement Function&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
No replacement functionality is required. Scripts should use the existing PostMessage(), Sniff, AddHandler() and similar functionality instead of broadcasting. This should be kept to the minimum necessary to achieve the desired goal.&lt;br /&gt;
In order to support interoperability with legacy scripts that expect message broadcasts, the LegacyBroadcastMessage() function can be used in parallel with any updated mechanisms.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==See Also==&lt;br /&gt;
* [[TrainzScript_Language_Reference|TrainzScript Language Reference]]&lt;br /&gt;
* [[Compatibility_mode|Compatibility Mode Setting]]&lt;br /&gt;
* [[Asynchronous_Route_Streaming| Asynchronous Route Streaming]]&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=Compatibility_mode&amp;diff=32803</id>
		<title>Compatibility mode</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=Compatibility_mode&amp;diff=32803"/>
		<updated>2022-06-21T05:25:01Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &amp;quot;Compatibility mode&amp;quot; setting in Trainz is used to disable various optimisations in order to support legacy content (Routes, Sessions, and their dependencies).&lt;br /&gt;
&lt;br /&gt;
This page details the various compatibility mode options available in TRS19 and later, and how they each affect gameplay and performance.&lt;br /&gt;
&lt;br /&gt;
==Maximise compatibility==&lt;br /&gt;
In &amp;quot;maximise compatibility&amp;quot; mode, Trainz will disable all [[Asynchronous_Route_Streaming|Route streaming]], and maintain the maximum level of [[TrainzScript|script]] support possible. While running in this mode Trainz will keep the entire Route loaded into system memory, which can massively degrade performance.&lt;br /&gt;
&lt;br /&gt;
This mode should only be used to run legacy content which fails to operate correctly with streaming enabled.&lt;br /&gt;
&lt;br /&gt;
In both [[TRS19]] and [[TRS22]], this mode is the default for the game due to the large number of legacy scripts in circulation. Users may override this default in the (out-of-game) Trainz Settings, and are encouraged to do so in order to achieve better game performance and/or test content to ensure that it functions correctly.&lt;br /&gt;
&lt;br /&gt;
==Stream objects==&lt;br /&gt;
This mode enables [[Asynchronous_Route_Streaming|Route streaming]], but keeps the maximum level of [[TrainzScript|script]] support possible. With streaming enabled, Trainz avoids loading portions of the Route which are inactive and far away from the player, increasing performance, reducing loading times, and reducing overall system resource consumption. This is especially evident on very large Routes. However, older scripted assets (especially session rules) can experience issues, as they may attempt to query Route data which is not currently loaded.&lt;br /&gt;
&lt;br /&gt;
This mode is most appropriate for running most content from older versions of Trainz.&lt;br /&gt;
&lt;br /&gt;
Packaged routes which are bundled with the [[TRS19]] and [[TRS22]] products use this mode even if &amp;quot;Maximise Compatibility&amp;quot; is selected, because they have been tested internally at N3V to confirm correct operation.&lt;br /&gt;
&lt;br /&gt;
==Maximise performance==&lt;br /&gt;
In maximise performance mode Trainz enables [[Asynchronous_Route_Streaming|Route streaming]], and also prevents many [[HowTo/Upgrade obsolete script functions|legacy script functions]] from running. This can hugely improve performance but older scripted content is likely to function incorrectly, or not at all. Specifically, script functions which are tagged with the [[TrainzScript Keywords#obsolete|&#039;obsolete&#039; keyword]] are likely not to function, and may return empty, null, or incomplete results. &lt;br /&gt;
&lt;br /&gt;
It is expected that future Trainz products will enable this mode by default, so script authors should run in this mode or beyond when developing and testing their creations.&lt;br /&gt;
&lt;br /&gt;
==Show errors on legacy calls==&lt;br /&gt;
This mode is useful for finding/debugging content which attempts to use legacy script features. While in &#039;Show errors on legacy calls&#039; mode, Trainz will operate identically to &#039;Maximise performance&#039; mode, but script calls to obsolete/legacy functions will also generate script exceptions. This allows content creators to determine which assets require fixing/replacing in order to support &#039;Maximise performance&#039; mode, but due to the extra processing game performance will be slightly worse than when running in &#039;Maximise performance&#039;.&lt;br /&gt;
&lt;br /&gt;
This mode should only be used for testing and debugging during content creation.&lt;br /&gt;
&lt;br /&gt;
==See Also==&lt;br /&gt;
* [[Asynchronous_Route_Streaming| Asynchronous Route Streaming]]&lt;br /&gt;
* [[HowTo/Search_for_objects_in_the_world| How to Search for objects in the world]]&lt;br /&gt;
* [[HowTo/Upgrade obsolete script functions]]&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=Help:VE268&amp;diff=31954</id>
		<title>Help:VE268</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=Help:VE268&amp;diff=31954"/>
		<updated>2022-02-21T05:49:24Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: Created page with &amp;quot;=Mesh file is unused in this asset: &amp;#039;$(FILE)&amp;#039;=  This warning (trainz-build &amp;lt;= 500) or error (trainz-build &amp;gt; 500) is logged when an asset contains a mesh file which is not refe...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Mesh file is unused in this asset: &#039;$(FILE)&#039;=&lt;br /&gt;
&lt;br /&gt;
This warning (trainz-build &amp;lt;= 500) or error (trainz-build &amp;gt; 500) is logged when an asset contains a mesh file which is not referenced in the asset&#039;s config.txt file.&lt;br /&gt;
&lt;br /&gt;
This results either because the mesh file is entirely redundant, meaning that it should not be included in the asset, or because the mesh file is referenced indirectly from the config.txt of some other asset (eg. as a mesh library) without also being referenced in the config.txt file. In the latter case, the correct solution is to configure an appropriate mesh-table entry in the asset to reference the mesh, in the same manner that you expect other assets to reference the mesh.&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=Category:Validation_Errors&amp;diff=31953</id>
		<title>Category:Validation Errors</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=Category:Validation_Errors&amp;diff=31953"/>
		<updated>2022-02-21T05:44:39Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Validation Error (VE) numbers are logged during content validation, to allow users to look up particular validation messages to better understand the source of the problem. Normal logs provide a substantial amount of technical detail about the error, but typically assume that the reader is familiar with the subject matter and will understand why the log is relevant. This wiki provides the necessary background information to understanding many of the logs, however a user who is unfamiliar with the area in question may not know where to start looking. VE numbers allow users to quickly find relevant pages in the wiki without any prior knowledge of the subject.&lt;br /&gt;
&lt;br /&gt;
This page serves as a master guide to all VE numbers currently logged by Trainz. This page does not provide detailed information on any given VE number- please refer to the individual VE number pages for specific details. The error text here is correct for the English localisation of Trainz at the time of writing, however the exact text may change from time to time. It is intended that the overall meaning of a VE number will never change- new VE numbers will be issued instead, and old VE numbers may be made obsolete.&lt;br /&gt;
&lt;br /&gt;
Logs which lack VE numbers do not belong on this page.&lt;br /&gt;
&lt;br /&gt;
The individual VE pages can be found at the links below, or can be accessed directly from [[Content Manager]] by right-clicking on the Validation Error in the results log, and selecting &amp;quot;View Help for This Message&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|1||[[Help:VE1|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Decimal value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|2||[[Help:VE2|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Integer value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|3||[[Help:VE3|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|4||[[Help:VE4|&amp;quot;&#039;$(TAG_NAME)&#039; must have a positive value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|5||[[Help:VE5|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|6||[[Help:VE6|&amp;quot;&#039;$(TAG_NAME)&#039; must not be zero.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|7||[[Help:VE7|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|8||[[Help:VE8|&amp;quot;The value for &#039;$(TAG_NAME)&#039; must be between &#039;$(MIN)&#039; and &#039;$(MAX)&#039; but was specified as &#039;$(VALUE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|9||[[Help:VE9|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|10||[[Help:VE10|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|11||[[Help:VE11|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|12||[[Help:VE12|&amp;quot;No string-table entry found with tag &#039;$(VALUE)&#039; for for string-token tag &#039;$(TAG)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|13||[[Help:VE13|&amp;quot;Missing or invalid selection for tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|14||[[Help:VE14|&amp;quot;Missing or invalid selection for tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|15||[[Help:VE15|&amp;quot;Attachment point &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must be found in mesh &#039;$(MESH_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|16||[[Help:VE16|&amp;quot;Container &#039;$(CONT_NAME)&#039; does not have an &#039;att-parent&#039; tag which is required to reference an attachment point.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|17||[[Help:VE17|&amp;quot;Attachment point &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must be found in mesh &#039;$(MESH_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|18||[[Help:VE18|&amp;quot;Attachment point &#039;$(TAG_VAL)&#039; referenced by tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; was not found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|19||[[Help:VE19|&amp;quot;Effect &#039;$(EFFECT_NAME)&#039; in &#039;$(CONT_NAME)&#039; was not found within the mesh table.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|20||[[Help:VE20|&amp;quot;Mesh &#039;$(MESH_NAME)&#039; referenced in &#039;$(CONT_NAME)&#039; was not found within the mesh table.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|21||[[Help:VE21|&amp;quot;Attachment point &#039;$(TAG_VAL)&#039; referenced by tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; was not found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|22||[[Help:VE22|&amp;quot;Missing or invalid selection for tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|23||[[Help:VE23|&amp;quot;Invalid tag name &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|24||[[Help:VE24|&amp;quot;Invalid tag name &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|25||[[Help:VE25|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|26||[[Help:VE26|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|27||[[Help:VE27|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must have a mesh file extension.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|28||[[Help:VE28|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must have an image file extension.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|29||[[Help:VE29|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must have an animation file extension.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|30||[[Help:VE30|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; refers to a nonexistent file: &#039;$(FILENAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|31||[[Help:VE31|&amp;quot;Invalid tag name &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|32||[[Help:VE32|&amp;quot;Alias mesh requires valid parent asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|33||[[Help:VE33|&amp;quot;Alias mesh &#039;$(FILE)&#039; not found in dependency $(KUID).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|34||[[Help:VE34|&amp;quot;Alias mesh &#039;$(FILE)&#039; not found in latest version ($(NEW_KUID)) of dependency $(OLD_KUID).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|35||[[Help:VE35|&amp;quot;Required alias mesh asset $(KUID) is missing and cannot be validated.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|36||[[Help:VE36|&amp;quot;The texture &#039;$(FILE)&#039; failed to load.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|37||[[Help:VE37|&amp;quot;The texture &#039;$(FILE)&#039; is not a power of 2, please resize it.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|38||[[Help:VE38|&amp;quot;The texture &#039;$(FILE)&#039; is not square. Cubemap textures need to have the same width and height.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|39||[[Help:VE39|&amp;quot;The texture &#039;$(FILE)&#039; is a uniform color.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|40||[[Help:VE40|&amp;quot;Unable to load $(TYPE) texture &#039;$(TEXTURE)&#039; for texture file &#039;$(FILE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|41||[[Help:VE41|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Integer value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|42||[[Help:VE42|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Decimal value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|43||[[Help:VE43|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Boolean value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|44||[[Help:VE44|&amp;quot;Tag &#039;$(TAG_NAME)&#039; in the container &#039;$(CONT_NAME)&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|45||[[Help:VE45|&amp;quot;The Tag &#039;$(TAG_NAME)&#039; is not permitted within a container of type &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|46||[[Help:VE46|&amp;quot;Internal Error: The template does not specify that a smoke container is valid in the container being parsed.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|47||[[Help:VE47|&amp;quot;Container &#039;$(CONT_NAME)&#039; is not permitted in this section.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|48||[[Help:VE48|&amp;quot;This asset uses an obsolete trainz-build number. Trainz-build numbers below $(LOWEST_TRAINZBUILD) are no longer supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|49||[[Help:VE49|&amp;quot;Required tag &#039;kind&#039; is not present. Ensure this is a valid config file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|50||[[Help:VE50|&amp;quot;Unsupported kind &#039;$(KIND)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|51||[[Help:VE51|&amp;quot;Tag &#039;$(TAG_NAME)&#039; in the container &#039;$(CONT_NAME)&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|52||[[Help:VE52|&amp;quot;The Tag &#039;$(TAG_NAME)&#039; is not permitted within a container of type &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|53||[[Help:VE53|&amp;quot;This container is no longer supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|54||[[Help:VE54|&amp;quot;The Tag &#039;$(TAG_NAME)&#039; is not permitted within a container of type &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|55||[[Help:VE55|&amp;quot;This container is no longer supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|56||[[Help:VE56|&amp;quot;Container &#039;$(CONT_NAME)&#039; is not permitted in this section.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|57||[[Help:VE57|&amp;quot;Container &#039;$(CONT_NAME)&#039; is not permitted in this section.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|58||[[Help:VE58|&amp;quot;The tag &#039;$(TAG_NAME)&#039; is not a valid container type (expected &#039;$(TYPE)&#039;).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|59||[[Help:VE59|&amp;quot;Internal error: unknown dataType - kind &#039;$(KIND)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|60||[[Help:VE60|&amp;quot;Required tag &#039;$(TAG_NAME)&#039; was missing and has been set to default.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|61||[[Help:VE61|&amp;quot;Required tag &#039;$(TAG_NAME)&#039; was missing and has been set to default.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|62||[[Help:VE62|&amp;quot;Required container &#039;$(CONT_NAME)&#039; is missing.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|63||[[Help:VE63|&amp;quot;The cubemap texture &#039;$(FILE)&#039; has missing images. Please verify the texture.txt file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|64||[[Help:VE64|&amp;quot;Cubemap texture &#039;$(FILE)&#039; contains images of different sizes.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|65||[[Help:VE65|&amp;quot;The *.texture.txt file is missing for texture resource &#039;$(FILE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|66||[[Help:VE66|&amp;quot;The texture file &#039;$(FILE)&#039; contains non-ANSI characters. Textures must be ANSI.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|67||[[Help:VE67|&amp;quot;The texture &#039;$(FILE)&#039; does not seem to have a primary texture set. Please verify the texture.txt file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|68||[[Help:VE68|&amp;quot;The primary and alpha texture are not the same size for &#039;$(FILE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|69||[[Help:VE69|&amp;quot;Binary conversion failed for texture resource &#039;$(FILE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|70||[[Help:VE70|&amp;quot;The KUID tag is not a valid KUID value: &#039;$(string)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|71||[[Help:VE71|&amp;quot;Unsupported SpeedTree version for mesh: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|72||[[Help:VE72|&amp;quot;Unable to load mesh file: &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|73||[[Help:VE73|&amp;quot;Image file &#039;$(FILE)&#039; is incorrectly used as both a texture.txt source file and a raw image file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|74||[[Help:VE74|&amp;quot;Image file &#039;$(FILE)&#039; is incorrectly used as both a texture.txt source file and a raw image file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|76||[[Help:VE76|&amp;quot;Unable to load mesh file: &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|77||[[Help:VE77|&amp;quot;Unable to load indexed mesh &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|79||[[Help:VE79|&amp;quot;Unable to load animation file &#039;$(FILE)&#039; (mesh has not been loaded correctly).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|81||[[Help:VE81|&amp;quot;The high-poly mesh &#039;$(FILE)&#039; should have LOD levels.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|82||[[Help:VE82|&amp;quot;High-detail .im files are not supported for traincar assets, as they are likely to perform poorly. It is recommended that you upgrade &#039;$(FILE)&#039; to a .lm file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|83||[[Help:VE83|&amp;quot;The file &#039;$(FILE)&#039; is provided in LM format despite having no attachment points and no animation support. This may have a negative impact on performance.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|84||[[Help:VE84|&amp;quot;The file &#039;$(FILE)&#039; is provided in LM format despite containing only a single mesh. This may have a negative impact on performance.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|85||[[Help:VE85|&amp;quot;The file &#039;$(FILE)&#039; is provided in LM format, however the high-detail mesh is comprised of less than 300 polygons. This may have a negative impact on performance.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|86||[[Help:VE86|&amp;quot;Legacy .pm files are no longer supported, and will perform poorly. It is recommended that you switch to using a .lm file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|87||[[Help:VE87|&amp;quot;Legacy .pm files are no longer supported, and will perform poorly. It is recommended that you switch to using a .lm file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|88||[[Help:VE88|&amp;quot;This asset has a trainz-build number which is not recognised by this tool.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|89||[[Help:VE89|&amp;quot;Tag &#039;$(TAG_NAME)&#039; in the container &#039;$(CONT_NAME)&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|90||[[Help:VE90|&amp;quot;This asset has an invalid KUID user id&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|91||[[Help:VE91|&amp;quot;The dependency $(KUID) has an invalid KUID User ID and cannot be used&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|92||[[Help:VE92|&amp;quot;Duplicate &#039;$(TAG_NAME)&#039; containers in &#039;$(CONT_NAME)&#039;. Containers must have a unique name.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|93||[[Help:VE93|&amp;quot;Duplicate &#039;$(TAG_NAME)&#039; tags in &#039;$(CONT_NAME)&#039;. Tags must have a unique name.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|94||[[Help:VE94|&amp;quot;This asset requires a shadow mesh, but the mesh table does not contain one.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|95||[[Help:VE95|&amp;quot;This asset does not have a mesh that is visible by default.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|96||[[Help:VE96|&amp;quot;Maximum of 5 running number fonts supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|97||[[Help:VE97|&amp;quot;The running number font directory &#039;$(DIR)&#039; could not be found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|98||[[Help:VE98|&amp;quot;The running number font file &#039;$(DIR)/$(FILE)&#039; could not be found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|99||[[Help:VE99|&amp;quot;The track-sound container &#039;$(NAME)&#039; has no bogey, track or track-parent tag.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|100||[[Help:VE100|&amp;quot;Required tag &#039;$(TAG_NAME)&#039; was missing and has been set to default.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|101||[[Help:VE101|&amp;quot;The file &#039;$(FILE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|102||[[Help:VE102|&amp;quot;Failed to load sound file &#039;$(FILE)&#039;, please ensure this is a valid wav file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|103||[[Help:VE103|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|104||[[Help:VE104|&amp;quot;Multiple template property bindings for rule property &#039;$(PROP)&#039; for rule &#039;$(RULE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|105||[[Help:VE105|&amp;quot;The template property &#039;$(NAME)&#039; specified in the rule-template-bindings container of rule &#039;$(RULE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|106||[[Help:VE106|&amp;quot;The high-detail meshes in season $(SEASON) total more than $(LIMIT) polygons. This may have a negative impact on performance: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|107||[[Help:VE107|&amp;quot;The high-detail meshes total more than $(LIMIT) polygons. This may have a negative impact on performance: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|108||[[Help:VE108|&amp;quot;The low-detail meshes in season $(SEASON) total more than 500 polygons. This may have a negative impact on performance: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|109||[[Help:VE109|&amp;quot;The low-detail meshes total more than 500 polygons. This may have a negative impact on performance: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|110||[[Help:VE110|&amp;quot;The meshes in LOD level $(LOD_LEVEL) in season $(SEASON) must total at least 20% fewer polygons than the next higher LOD in the same season: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|111||[[Help:VE111|&amp;quot;The meshes in LOD level $(LOD_LEVEL) must total at least 20% fewer polygons than the next higher LOD: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|112||[[Help:VE112|&amp;quot;Multiple track stretches between &#039;$(FROM_VERTEX)&#039; and &#039;$(TO_VERTEX)&#039; in container &#039;$(CONT_NAME)&#039;. Track stretches must be unique.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|113||[[Help:VE113|&amp;quot;An image file (&#039;$(FILE)&#039;) has been supplied where a texture file (&#039;*.texture.txt&#039;) is required.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|114||[[Help:VE114|&amp;quot;An image file (&#039;$(FILE)&#039;) has been supplied where a texture file (&#039;*.texture.txt&#039;) is required.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|115||[[Help:VE115|&amp;quot;The texture file &#039;$(FILE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|116||[[Help:VE116|&amp;quot;No texture file has been specified for this texture asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|117||[[Help:VE117|&amp;quot;&#039;$(TAG_0)&#039; must be set to a &#039;$(KIND)&#039; for &#039;$(TAG_1)&#039; to be allowed.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|118||[[Help:VE118|&amp;quot;Tag &#039;$(TAG_0)&#039; requires that &#039;$(TAG_1)&#039; be set to &#039;$(KIND)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|119||[[Help:VE119|&amp;quot;The tag &#039;$(TAG_NAME)&#039; is not valid for kind &#039;$(KIND)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|120||[[Help:VE120|&amp;quot;Tag &#039;$(TAG_0)&#039;, requires the tag &#039;$(TAG_1)&#039; to be present.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|121||[[Help:VE121|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|122||[[Help:VE122|&amp;quot;&#039;$(TAG_NAME)&#039; must have a positive value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|123||[[Help:VE123|&amp;quot;The script file &#039;$(FILE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|124||[[Help:VE124|&amp;quot;The file &#039;$(FILE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|125||[[Help:VE125|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|126||[[Help:VE126|&amp;quot;&#039;$(TAG_NAME)&#039; must not be zero.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|127||[[Help:VE127|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|128||[[Help:VE128|&amp;quot;The value for &#039;$(TAG_NAME)&#039; must be between &#039;$(MIN)&#039; and &#039;$(MAX)&#039; but was specified as &#039;$(VALUE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|129||[[Help:VE129|&amp;quot;Incorrect number of values for the tag &#039;$(TAG_NAME)&#039;, expected $(NUM_0) values, found $(NUM_1).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|130||[[Help:VE130|&amp;quot;Too many values for the tag &#039;$(TAG_NAME)&#039;, maximum is $(MAX) values, found $(FOUND).&amp;quot;]]]]&lt;br /&gt;
|-&lt;br /&gt;
|131||[[Help:VE131|&amp;quot;Value must be a mesh from the mesh-table (not a parent container).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|132||[[Help:VE132|&amp;quot;The attachment point &#039;$(ATT)&#039; must belong to the parent mesh of the effect (mesh=$(MESH)).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|133||[[Help:VE133|&amp;quot;A light container must be present to link the signals.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|134||[[Help:VE134|&amp;quot;&#039;$(NUM)&#039; must be a valid light number from the light container.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|135||[[Help:VE135|&amp;quot;&#039;$(TAG_0)&#039; requires that the tag &#039;$(TAG_1)&#039; be present.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|136||[[Help:VE136|&amp;quot;&#039;$(TAG_0)&#039; requires that the tag &#039;$(TAG_1)&#039; be present.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|137||[[Help:VE137|&amp;quot;Empty or invalid running number specified at character index $(INDEX)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|138||[[Help:VE138|&amp;quot;Running number specified at character index $(INDEX) is too large, must be less than 9 characters.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|139||[[Help:VE139|&amp;quot;Invalid running number range specified at character index $(INDEX), ($(FROM)-$(TO)).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|140||[[Help:VE140|&amp;quot;Running number range &#039;$(FROM)-$(TO)&#039; specified at character index $(INDEX) overlaps already in use numbers, running numbers must be unique.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|141||[[Help:VE141|&amp;quot;Running number &#039;$(NUMBER)&#039; specified at character index $(INDEX) is already in use.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|142||[[Help:VE142|&amp;quot;Invalid character &#039;$(CHAR)&#039; specified in running number list, only numbers, &#039;,&#039; and &#039;-&#039; are supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|143||[[Help:VE143|&amp;quot;Possible running number list is too large, the set must contain less than 20000 possibilities.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|144||[[Help:VE144|&amp;quot;Category code &#039;ZX - Paintshed template&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|145||[[Help:VE145|&amp;quot;Category code &#039;ZX - Paintshed template&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|146||[[Help:VE146|&amp;quot;An asset must be specified for tag &#039;$(TAG_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|147||[[Help:VE147|&amp;quot;The tag(s) $(MISPLACED_TAGS) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|148||[[Help:VE148|&amp;quot;The tag(s) $(MISPLACED_TAGS) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|149||[[Help:VE149|&amp;quot;The mesh(es) $(MISPLACED_MESHES) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|150||[[Help:VE150|&amp;quot;The mesh(es) $(MISPLACED_MESHES) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|151||[[Help:VE150|&amp;quot;The mesh(es) $(MISPLACED_MESHES) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|152||[[Help:VE152|&amp;quot;The tags $(MISSING_TAGS) are not all defined. The default values will be used and the positions of the elements may not fit your track.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|153||[[Help:VE153|&amp;quot;The mesh $(MESH) is present but the tag $(MISSING_TAG) is not defined.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|154||[[Help:VE154|&amp;quot;The mesh $(MESH) is present but the tag $(MISSING_TAG) is not defined.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|155||[[Help:VE155|&amp;quot;The mesh $(MESH) is present but the tags $(MISSING_TAGS) are not all defined.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|156||[[Help:VE156|&amp;quot;The tag $(MISSING_TAG) is not defined. The default value will be used and the positions of the elements may not fit your track.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|157||[[Help:VE157|&amp;quot;The mesh $(MESH) is present but the tag $(MISSING_TAG) is missing. The default value will be used and the positions of the elements may not fit your track.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|158||[[Help:VE158|&amp;quot;Unable to open .lm.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|159||[[Help:VE159|&amp;quot;Unable to parse .lm.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|160||[[Help:VE160|&amp;quot;No &#039;mesh&#039; keys found in .lm.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|161||[[Help:VE161|&amp;quot;$(LODCOUNT) LODs in .lm.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|162||[[Help:VE162|&amp;quot;One of the LOD reductions of &#039;$(FILE)&#039; introduces a new attachment point: $(ATT)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|163||[[Help:VE163|&amp;quot;Unable to parse .im file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|164||[[Help:VE164|&amp;quot;Invalid position data in .im file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|165||[[Help:VE165|&amp;quot;Texture &#039;$(TEXTURE)&#039; is missing or could not be loaded in mesh &#039;$(FILE)&#039;, material &#039;$(MATERIAL)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|166||[[Help:VE166|&amp;quot;$(COMBINEDCOUNT) combined chunks (of $(SOURCECOUNT) source) in .im file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|167||[[Help:VE167|&amp;quot;Source image texture file &#039;$(TEXTUREFILE)&#039; is too large for &#039;$(ASSETFILE)&#039; ($(WIDTH)x$(HEIGHT))&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|168||[[Help:VE168|&amp;quot;File &#039;$(TEXTUREFILE)&#039; is not a valid compiled texture file for &#039;$(ASSETFILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|169||[[Help:VE169|&amp;quot;Compiled texture file &#039;$(TEXTUREFILE)&#039; is unsupported version for &#039;$(ASSETFILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|170||[[Help:VE170|&amp;quot;Failed to open compiled texture &#039;$(TEXTUREFILE)&#039; for &#039;$(ASSETFILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|171||[[Help:VE171|&amp;quot;Expected texture file type but found &#039;$(TEXTUREFILE)&#039; for &#039;$(ASSETFILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|172||[[Help:VE172|&amp;quot;Script class does not match asset kind ($(KIND)).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|173||[[Help:VE173|&amp;quot;Material &#039;$(MATERIAL)&#039; in mesh &#039;$(FILE)&#039; is not of a recognised material type.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|174||[[Help:VE174|&amp;quot;MeshObjectSpec::LinkSpecs&amp;gt; Mesh-table element #$(MESH_INDEX) parent mesh is invalid.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|175||[[Help:VE175|&amp;quot;MeshObjectSpec::LinkSpecs&amp;gt; Mesh-table element #$(MESH_INDEX) is part of invalid hierarchy.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|176||[[Help:VE176|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must have a texture file extension.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|177||[[Help:VE177|&amp;quot;The kuid &#039;$(KUID)&#039; is not in the database, and could not be found in any known location. Ensure that this is a valid asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|178||[[Help:VE178|&amp;quot;The asset specified in &#039;$(KUID)&#039; is not installed locally but is available for download.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|179||[[Help:VE179|&amp;quot;The kuid &#039;$(KUID)&#039; specified in &#039;$(TAG_NAME)&#039; is not of the correct type.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|180||[[Help:VE180|&amp;quot;Integrity check failure on $(FILE). One or more route/session tiles may be missing.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|181||[[Help:VE181|&amp;quot;The tag &#039;$(TAG_NAME)&#039; requires a minimum asset version of $(MIN_VERSION)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|182||[[Help:VE182|&amp;quot;Material &#039;$(MATERIAL)&#039; in mesh &#039;$(FILE)&#039; is missing a texture for a mandatory texture slot.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|183||[[Help:VE183|&amp;quot;FBX file is in an unsupported older format.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|184||[[Help:VE184|&amp;quot;KIND &#039;$(KIND)&#039; requires trainz-build $(TRAINZBUILD).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|185||[[Help:VE185|&amp;quot;Material &#039;$(MATERIAL)&#039; in mesh &#039;$(FILE)&#039; has heightmap texture. Provide a normal map instead.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|186||[[Help:VE186|&amp;quot;Material &#039;$(MATERIAL)&#039; is shared between multiple chunks in this asset but the material parameters conflict.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|187||[[Help:VE187|&amp;quot;The value &#039;$(VALUE)&#039; in not a valid KUID.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|188||[[Help:VE188|&amp;quot;Custom render plugin failed to load mesh &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|189||[[Help:VE189|&amp;quot;Collision data exceeds $(LIMIT)KB. Please specify a different generation method or a simplified mesh.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|190||[[Help:VE190|&amp;quot;Tag &#039;$(NAME)&#039; is unable to be converted from $(TYPE1) to $(TYPE2)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|191||[[Help:VE191|&amp;quot;Tag &#039;$(NAME)&#039; does not contain a valid integer: $(VALUE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|192||[[Help:VE192|&amp;quot;Tag &#039;$(NAME)&#039; does not contain a valid float list: $(VALUE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|193||[[Help:VE193|&amp;quot;Tag &#039;$(NAME)&#039; does not contain a valid float&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|194||[[Help:VE194|&amp;quot;Tag &#039;$(NAME)&#039; does not contain a valid kuid: $(VALUE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|195||[[Help:VE195|&amp;quot;Unable to parse chunk $(CHUNK_INDEX) in mesh file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|196||[[Help:VE196|&amp;quot;Failed to load bogey $(KUID)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|197||[[Help:VE197|&amp;quot;Syntax error in script &#039;$(SCRIPT)&#039; for asset $(ASSET)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|198||[[Help:VE198|&amp;quot;Session failed to load route asset: $(KUID)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|199||[[Help:VE199|&amp;quot;Asset $(KUID) failed to load. Unloading resources.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|200||[[Help:VE200|&amp;quot;Unable to load mesh $(NAME) for $(ASSET_ID)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|201||[[Help:VE201|&amp;quot;Traincar is missing required attachment point: $(ATT_NAME)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|202||[[Help:VE202|&amp;quot;Parse error reading twinkles file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|203||[[Help:VE203|&amp;quot;Bad sequence order in $(TAG_NAME) list. Each element must be greater than the last.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|204||[[Help:VE204|&amp;quot;Invalid range in $(TAG_NAME) list. Elements must be greater than or equal to $(INC_MIN) and less than $(EXC_MAX).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|205||[[Help:VE205|&amp;quot;Invalid element count in $(TAG_NAME) list. This list must have at least $(COUNT) elements (to match the $(TAG_START) list).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|206||[[Help:VE206|&amp;quot;The season-selector references season &#039;$(SEASON)&#039;, but this does not exist in the texture-variants container.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|207||[[Help:VE207|&amp;quot;Attached track asset $(CHILD) failed to load.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|208||[[Help:VE208|&amp;quot;Attached track asset not specified for track $(INDEX).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|209||[[Help:VE209|&amp;quot;Asset is missing the required &#039;attached-track&#039; container.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|210||[[Help:VE210|&amp;quot;Asset is missing the required &#039;track&#039; tag.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|211||[[Help:VE211|&amp;quot;Asset is missing the required &#039;road&#039; tag.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|212||[[Help:VE212|&amp;quot;Traincar asset must have at least two bogeys.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|213||[[Help:VE213|&amp;quot;Traincar asset has invalid bogey placement.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|214||[[Help:VE214|&amp;quot;Traincar asset has invalid length.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|215||[[Help:VE215|&amp;quot;Asset has an invalid number of LODs: $(LOD_COUNT)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|216||[[Help:VE216|&amp;quot;Material $(MATERIAL) in mesh file $(MESH) has an inappropriate texture slot assigned: $(TEXTURE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|217||[[Help:VE217|&amp;quot;Material $(MATERIAL) in mesh file $(MESH) has no texture assigned to a required slot: $(TEXTURE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|218||[[Help:VE218|&amp;quot;Asset has duplicate attached track at track $(INDEX).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|219||[[Help:VE219|&amp;quot;Failed to load driver mesh $(ASSETID).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|220||[[Help:VE220|Miscellaneous script compiler output.]]&lt;br /&gt;
|-&lt;br /&gt;
|221||[[Help:VE221|&amp;quot;$(ASSETID) is faulty and will not be loaded.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|222||[[Help:VE222|&amp;quot;Failed to load mesh $(ASSETID)-$(MESHFILE) for TNI plugin renderer.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|223||[[Help:VE223|&amp;quot;Unable to create mesh index $(MESHINDEX) for asset $(ASSET).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|224||[[Help:VE224|&amp;quot;Corrupted data in mesh file &#039;$(FILENAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|225||[[Help:VE225|&amp;quot;Failed to query asset details for featured asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|226||[[Help:VE226|&amp;quot;Failed to upload asset details for featured asset: $(ERRORTEXT)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|227||[[Help:VE227|&amp;quot;Missing image for featured asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|228||[[Help:VE228|&amp;quot;Failed to read image file for featured asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|229||[[Help:VE229|&amp;quot;DLC marketing image is missing or incorrectly sized for featured asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|230||[[Help:VE230|&amp;quot;DLS thumbnail image is missing or incorrectly sized for featured asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|231||[[Help:VE231|&amp;quot;Failed to open image file for featured asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|232||[[Help:VE232|&amp;quot;Failed to upload image for featured asset: $(ERRORTEXT)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|233||[[Help:VE233|&amp;quot;One or more featured assets was not provided.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|234||[[Help:VE234|&amp;quot;Asset is not present in the featured assets list.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|235||[[Help:VE235|&amp;quot;Featured asset is not present in the input.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|236||[[Help:VE236|&amp;quot;Featured asset was not available.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|237||[[Help:VE237|&amp;quot;Featured asset failed validation.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|238||[[Help:VE238|&amp;quot;Featured asset has faulty or missing dependencies.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|239||[[Help:VE239|&amp;quot;Featured asset is Base content.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|240||[[Help:VE240|&amp;quot;Featured asset is missing an English name or description.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|241||[[Help:VE241|&amp;quot;Newly built package is not compatible with previously released version.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|242||[[Help:VE242|&amp;quot;Unable to load animation file &#039;$(FILE)&#039; (file not found, or is damaged).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|243||[[Help:VE243|&amp;quot;Failed to submit changes to asset $(ASSET_KUID) due to file access error&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|244||[[Help:VE244|&amp;quot;Files in base assets cannot use importers: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|245||[[Help:VE245|&amp;quot;Missing compiled texture: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|246||[[Help:VE246|&amp;quot;Missing source texture: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|247||[[Help:VE247|&amp;quot;Creating default texture.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|248||[[Help:VE248|&amp;quot;Failed to create *.texture.txt file for source image: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|249||[[Help:VE249|&amp;quot;Failed to compile *.texture.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|250||[[Help:VE250|&amp;quot;Material Metadata expected data for texture slot &#039;$(SLOT)&#039; of material &#039;$(MATERIAL)&#039; but none found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|251||[[Help:VE251|&amp;quot;Material Metadata expected *.texture resource for texture slot &#039;$(SLOT)&#039; of material &#039;$(MATERIAL)&#039; bout found: $(FOUND)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|252||[[Help:VE252|&amp;quot;Mesh material expected data for texture slot &#039;$(SLOT)&#039; of material &#039;$(MATERIAL)&#039; but none found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|253||[[Help:VE253|&amp;quot;WriteAnimationFileBoneChunk&amp;gt; excessive bone-chunk count.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|254||[[Help:VE254|&amp;quot;Unable to open mesh metadata file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|255||[[Help:VE255|&amp;quot;Mesh contains unsupported non-triangle primitives.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|256||[[Help:VE256|&amp;quot;Mesh contains invalid material index.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|257||[[Help:VE257|&amp;quot;Mesh contains no primitives.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|258||[[Help:VE258|&amp;quot;Unable to determine vertex format.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|259||[[Help:VE259|&amp;quot;Unsupported number of texture channels.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|260||[[Help:VE260|&amp;quot;Invalid index in primitive.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|261||[[Help:VE261|&amp;quot;Unable to create animation file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|262||[[Help:VE262|&amp;quot;Unable to open animation event file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|263||[[Help:VE263|&amp;quot;Unable to parse animation event file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|264||[[Help:VE264|&amp;quot;Parsed animation event file $(FILE) with $(COUNT) events.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|265||[[Help:VE265|&amp;quot;Unable to search path: &#039;$(FILE_PATH)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|266||[[Help:VE266|&amp;quot;Multiple values found for engine spec param &amp;lt;kuid:xxx:yyy&amp;gt;/tag-name (Value1 and Value2)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|267||[[Help:VE267|&amp;quot;member $(MEMBER) is obsolete in object $(CLASS).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|268||[[Help:VE268|&amp;quot;Mesh file is unused in this asset: &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=Help:VE267&amp;diff=30828</id>
		<title>Help:VE267</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=Help:VE267&amp;diff=30828"/>
		<updated>2021-11-16T03:51:28Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: Created page with &amp;quot;=member $(MEMBER) is obsolete in object $(CLASS).=  This error is reported by the TrainzScript compiler when script code is attempting to call an obsolete function or acce...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=member $(MEMBER) is obsolete in object $(CLASS).=&lt;br /&gt;
&lt;br /&gt;
This error is reported by the [[TrainzScript]] compiler when script code is attempting to call an obsolete function or access an obsolete member. This error indicates that the script is not fully compatible with newer versions of the game (eg. TRS19 onward) and may not work correctly or may induce runtime performance problems. Depending on the version of Trainz in use, and the [[trainz-build]] version of the asset in question, this error may be considered a warning only. Script authors should be careful attention to this message even in cases where it is &amp;quot;just&amp;quot; a warning; it indicates a problem that needs fixing to ensure correct behaviour.&lt;br /&gt;
&lt;br /&gt;
==Legacy Scripts==&lt;br /&gt;
Assets scripts developed at a time when the function/member in question was not flagged as obsolete may trigger this error. This means that the asset is reliant on obsolete functionality and will need to be updated or replaced. Route and session developers should avoid using such content in their routes. Any such content uploaded to the [[Download Station]] may be considered faulty and may be automatically submitted to the [[Content Repair Group]].&lt;br /&gt;
&lt;br /&gt;
==Legacy Session Support==&lt;br /&gt;
There is also a scenario where an update to a legacy asset may correctly use modern functionality, but also offer a fallback mode where legacy script APIs are used if the asset version originally placed used the legacy APIs. Scripts should be written such that this should be a one-off scenario with an in-place upgrade to new data formats. This should not result in the scripts continuing to use the fallback mode in place of the modern APIs.&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=Category:Validation_Errors&amp;diff=30827</id>
		<title>Category:Validation Errors</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=Category:Validation_Errors&amp;diff=30827"/>
		<updated>2021-11-16T02:07:16Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Validation Error (VE) numbers are logged during content validation, to allow users to look up particular validation messages to better understand the source of the problem. Normal logs provide a substantial amount of technical detail about the error, but typically assume that the reader is familiar with the subject matter and will understand why the log is relevant. This wiki provides the necessary background information to understanding many of the logs, however a user who is unfamiliar with the area in question may not know where to start looking. VE numbers allow users to quickly find relevant pages in the wiki without any prior knowledge of the subject.&lt;br /&gt;
&lt;br /&gt;
This page serves as a master guide to all VE numbers currently logged by Trainz. This page does not provide detailed information on any given VE number- please refer to the individual VE number pages for specific details. The error text here is correct for the English localisation of Trainz at the time of writing, however the exact text may change from time to time. It is intended that the overall meaning of a VE number will never change- new VE numbers will be issued instead, and old VE numbers may be made obsolete.&lt;br /&gt;
&lt;br /&gt;
Logs which lack VE numbers do not belong on this page.&lt;br /&gt;
&lt;br /&gt;
The individual VE pages can be found at the links below, or can be accessed directly from [[Content Manager]] by right-clicking on the Validation Error in the results log, and selecting &amp;quot;View Help for This Message&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|1||[[Help:VE1|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Decimal value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|2||[[Help:VE2|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Integer value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|3||[[Help:VE3|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|4||[[Help:VE4|&amp;quot;&#039;$(TAG_NAME)&#039; must have a positive value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|5||[[Help:VE5|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|6||[[Help:VE6|&amp;quot;&#039;$(TAG_NAME)&#039; must not be zero.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|7||[[Help:VE7|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|8||[[Help:VE8|&amp;quot;The value for &#039;$(TAG_NAME)&#039; must be between &#039;$(MIN)&#039; and &#039;$(MAX)&#039; but was specified as &#039;$(VALUE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|9||[[Help:VE9|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|10||[[Help:VE10|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|11||[[Help:VE11|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|12||[[Help:VE12|&amp;quot;No string-table entry found with tag &#039;$(VALUE)&#039; for for string-token tag &#039;$(TAG)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|13||[[Help:VE13|&amp;quot;Missing or invalid selection for tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|14||[[Help:VE14|&amp;quot;Missing or invalid selection for tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|15||[[Help:VE15|&amp;quot;Attachment point &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must be found in mesh &#039;$(MESH_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|16||[[Help:VE16|&amp;quot;Container &#039;$(CONT_NAME)&#039; does not have an &#039;att-parent&#039; tag which is required to reference an attachment point.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|17||[[Help:VE17|&amp;quot;Attachment point &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must be found in mesh &#039;$(MESH_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|18||[[Help:VE18|&amp;quot;Attachment point &#039;$(TAG_VAL)&#039; referenced by tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; was not found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|19||[[Help:VE19|&amp;quot;Effect &#039;$(EFFECT_NAME)&#039; in &#039;$(CONT_NAME)&#039; was not found within the mesh table.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|20||[[Help:VE20|&amp;quot;Mesh &#039;$(MESH_NAME)&#039; referenced in &#039;$(CONT_NAME)&#039; was not found within the mesh table.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|21||[[Help:VE21|&amp;quot;Attachment point &#039;$(TAG_VAL)&#039; referenced by tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; was not found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|22||[[Help:VE22|&amp;quot;Missing or invalid selection for tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|23||[[Help:VE23|&amp;quot;Invalid tag name &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|24||[[Help:VE24|&amp;quot;Invalid tag name &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|25||[[Help:VE25|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|26||[[Help:VE26|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|27||[[Help:VE27|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must have a mesh file extension.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|28||[[Help:VE28|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must have an image file extension.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|29||[[Help:VE29|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must have an animation file extension.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|30||[[Help:VE30|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; refers to a nonexistent file: &#039;$(FILENAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|31||[[Help:VE31|&amp;quot;Invalid tag name &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|32||[[Help:VE32|&amp;quot;Alias mesh requires valid parent asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|33||[[Help:VE33|&amp;quot;Alias mesh &#039;$(FILE)&#039; not found in dependency $(KUID).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|34||[[Help:VE34|&amp;quot;Alias mesh &#039;$(FILE)&#039; not found in latest version ($(NEW_KUID)) of dependency $(OLD_KUID).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|35||[[Help:VE35|&amp;quot;Required alias mesh asset $(KUID) is missing and cannot be validated.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|36||[[Help:VE36|&amp;quot;The texture &#039;$(FILE)&#039; failed to load.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|37||[[Help:VE37|&amp;quot;The texture &#039;$(FILE)&#039; is not a power of 2, please resize it.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|38||[[Help:VE38|&amp;quot;The texture &#039;$(FILE)&#039; is not square. Cubemap textures need to have the same width and height.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|39||[[Help:VE39|&amp;quot;The texture &#039;$(FILE)&#039; is a uniform color.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|40||[[Help:VE40|&amp;quot;Unable to load $(TYPE) texture &#039;$(TEXTURE)&#039; for texture file &#039;$(FILE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|41||[[Help:VE41|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Integer value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|42||[[Help:VE42|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Decimal value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|43||[[Help:VE43|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Boolean value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|44||[[Help:VE44|&amp;quot;Tag &#039;$(TAG_NAME)&#039; in the container &#039;$(CONT_NAME)&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|45||[[Help:VE45|&amp;quot;The Tag &#039;$(TAG_NAME)&#039; is not permitted within a container of type &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|46||[[Help:VE46|&amp;quot;Internal Error: The template does not specify that a smoke container is valid in the container being parsed.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|47||[[Help:VE47|&amp;quot;Container &#039;$(CONT_NAME)&#039; is not permitted in this section.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|48||[[Help:VE48|&amp;quot;This asset uses an obsolete trainz-build number. Trainz-build numbers below $(LOWEST_TRAINZBUILD) are no longer supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|49||[[Help:VE49|&amp;quot;Required tag &#039;kind&#039; is not present. Ensure this is a valid config file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|50||[[Help:VE50|&amp;quot;Unsupported kind &#039;$(KIND)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|51||[[Help:VE51|&amp;quot;Tag &#039;$(TAG_NAME)&#039; in the container &#039;$(CONT_NAME)&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|52||[[Help:VE52|&amp;quot;The Tag &#039;$(TAG_NAME)&#039; is not permitted within a container of type &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|53||[[Help:VE53|&amp;quot;This container is no longer supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|54||[[Help:VE54|&amp;quot;The Tag &#039;$(TAG_NAME)&#039; is not permitted within a container of type &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|55||[[Help:VE55|&amp;quot;This container is no longer supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|56||[[Help:VE56|&amp;quot;Container &#039;$(CONT_NAME)&#039; is not permitted in this section.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|57||[[Help:VE57|&amp;quot;Container &#039;$(CONT_NAME)&#039; is not permitted in this section.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|58||[[Help:VE58|&amp;quot;The tag &#039;$(TAG_NAME)&#039; is not a valid container type (expected &#039;$(TYPE)&#039;).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|59||[[Help:VE59|&amp;quot;Internal error: unknown dataType - kind &#039;$(KIND)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|60||[[Help:VE60|&amp;quot;Required tag &#039;$(TAG_NAME)&#039; was missing and has been set to default.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|61||[[Help:VE61|&amp;quot;Required tag &#039;$(TAG_NAME)&#039; was missing and has been set to default.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|62||[[Help:VE62|&amp;quot;Required container &#039;$(CONT_NAME)&#039; is missing.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|63||[[Help:VE63|&amp;quot;The cubemap texture &#039;$(FILE)&#039; has missing images. Please verify the texture.txt file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|64||[[Help:VE64|&amp;quot;Cubemap texture &#039;$(FILE)&#039; contains images of different sizes.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|65||[[Help:VE65|&amp;quot;The *.texture.txt file is missing for texture resource &#039;$(FILE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|66||[[Help:VE66|&amp;quot;The texture file &#039;$(FILE)&#039; contains non-ANSI characters. Textures must be ANSI.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|67||[[Help:VE67|&amp;quot;The texture &#039;$(FILE)&#039; does not seem to have a primary texture set. Please verify the texture.txt file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|68||[[Help:VE68|&amp;quot;The primary and alpha texture are not the same size for &#039;$(FILE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|69||[[Help:VE69|&amp;quot;Binary conversion failed for texture resource &#039;$(FILE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|70||[[Help:VE70|&amp;quot;The KUID tag is not a valid KUID value: &#039;$(string)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|71||[[Help:VE71|&amp;quot;Unsupported SpeedTree version for mesh: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|72||[[Help:VE72|&amp;quot;Unable to load mesh file: &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|73||[[Help:VE73|&amp;quot;Image file &#039;$(FILE)&#039; is incorrectly used as both a texture.txt source file and a raw image file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|74||[[Help:VE74|&amp;quot;Image file &#039;$(FILE)&#039; is incorrectly used as both a texture.txt source file and a raw image file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|76||[[Help:VE76|&amp;quot;Unable to load mesh file: &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|77||[[Help:VE77|&amp;quot;Unable to load indexed mesh &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|79||[[Help:VE79|&amp;quot;Unable to load animation file &#039;$(FILE)&#039; (mesh has not been loaded correctly).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|81||[[Help:VE81|&amp;quot;The high-poly mesh &#039;$(FILE)&#039; should have LOD levels.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|82||[[Help:VE82|&amp;quot;High-detail .im files are not supported for traincar assets, as they are likely to perform poorly. It is recommended that you upgrade &#039;$(FILE)&#039; to a .lm file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|83||[[Help:VE83|&amp;quot;The file &#039;$(FILE)&#039; is provided in LM format despite having no attachment points and no animation support. This may have a negative impact on performance.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|84||[[Help:VE84|&amp;quot;The file &#039;$(FILE)&#039; is provided in LM format despite containing only a single mesh. This may have a negative impact on performance.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|85||[[Help:VE85|&amp;quot;The file &#039;$(FILE)&#039; is provided in LM format, however the high-detail mesh is comprised of less than 300 polygons. This may have a negative impact on performance.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|86||[[Help:VE86|&amp;quot;Legacy .pm files are no longer supported, and will perform poorly. It is recommended that you switch to using a .lm file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|87||[[Help:VE87|&amp;quot;Legacy .pm files are no longer supported, and will perform poorly. It is recommended that you switch to using a .lm file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|88||[[Help:VE88|&amp;quot;This asset has a trainz-build number which is not recognised by this tool.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|89||[[Help:VE89|&amp;quot;Tag &#039;$(TAG_NAME)&#039; in the container &#039;$(CONT_NAME)&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|90||[[Help:VE90|&amp;quot;This asset has an invalid KUID user id&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|91||[[Help:VE91|&amp;quot;The dependency $(KUID) has an invalid KUID User ID and cannot be used&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|92||[[Help:VE92|&amp;quot;Duplicate &#039;$(TAG_NAME)&#039; containers in &#039;$(CONT_NAME)&#039;. Containers must have a unique name.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|93||[[Help:VE93|&amp;quot;Duplicate &#039;$(TAG_NAME)&#039; tags in &#039;$(CONT_NAME)&#039;. Tags must have a unique name.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|94||[[Help:VE94|&amp;quot;This asset requires a shadow mesh, but the mesh table does not contain one.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|95||[[Help:VE95|&amp;quot;This asset does not have a mesh that is visible by default.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|96||[[Help:VE96|&amp;quot;Maximum of 5 running number fonts supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|97||[[Help:VE97|&amp;quot;The running number font directory &#039;$(DIR)&#039; could not be found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|98||[[Help:VE98|&amp;quot;The running number font file &#039;$(DIR)/$(FILE)&#039; could not be found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|99||[[Help:VE99|&amp;quot;The track-sound container &#039;$(NAME)&#039; has no bogey, track or track-parent tag.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|100||[[Help:VE100|&amp;quot;Required tag &#039;$(TAG_NAME)&#039; was missing and has been set to default.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|101||[[Help:VE101|&amp;quot;The file &#039;$(FILE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|102||[[Help:VE102|&amp;quot;Failed to load sound file &#039;$(FILE)&#039;, please ensure this is a valid wav file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|103||[[Help:VE103|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|104||[[Help:VE104|&amp;quot;Multiple template property bindings for rule property &#039;$(PROP)&#039; for rule &#039;$(RULE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|105||[[Help:VE105|&amp;quot;The template property &#039;$(NAME)&#039; specified in the rule-template-bindings container of rule &#039;$(RULE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|106||[[Help:VE106|&amp;quot;The high-detail meshes in season $(SEASON) total more than $(LIMIT) polygons. This may have a negative impact on performance: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|107||[[Help:VE107|&amp;quot;The high-detail meshes total more than $(LIMIT) polygons. This may have a negative impact on performance: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|108||[[Help:VE108|&amp;quot;The low-detail meshes in season $(SEASON) total more than 500 polygons. This may have a negative impact on performance: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|109||[[Help:VE109|&amp;quot;The low-detail meshes total more than 500 polygons. This may have a negative impact on performance: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|110||[[Help:VE110|&amp;quot;The meshes in LOD level $(LOD_LEVEL) in season $(SEASON) must total at least 20% fewer polygons than the next higher LOD in the same season: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|111||[[Help:VE111|&amp;quot;The meshes in LOD level $(LOD_LEVEL) must total at least 20% fewer polygons than the next higher LOD: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|112||[[Help:VE112|&amp;quot;Multiple track stretches between &#039;$(FROM_VERTEX)&#039; and &#039;$(TO_VERTEX)&#039; in container &#039;$(CONT_NAME)&#039;. Track stretches must be unique.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|113||[[Help:VE113|&amp;quot;An image file (&#039;$(FILE)&#039;) has been supplied where a texture file (&#039;*.texture.txt&#039;) is required.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|114||[[Help:VE114|&amp;quot;An image file (&#039;$(FILE)&#039;) has been supplied where a texture file (&#039;*.texture.txt&#039;) is required.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|115||[[Help:VE115|&amp;quot;The texture file &#039;$(FILE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|116||[[Help:VE116|&amp;quot;No texture file has been specified for this texture asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|117||[[Help:VE117|&amp;quot;&#039;$(TAG_0)&#039; must be set to a &#039;$(KIND)&#039; for &#039;$(TAG_1)&#039; to be allowed.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|118||[[Help:VE118|&amp;quot;Tag &#039;$(TAG_0)&#039; requires that &#039;$(TAG_1)&#039; be set to &#039;$(KIND)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|119||[[Help:VE119|&amp;quot;The tag &#039;$(TAG_NAME)&#039; is not valid for kind &#039;$(KIND)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|120||[[Help:VE120|&amp;quot;Tag &#039;$(TAG_0)&#039;, requires the tag &#039;$(TAG_1)&#039; to be present.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|121||[[Help:VE121|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|122||[[Help:VE122|&amp;quot;&#039;$(TAG_NAME)&#039; must have a positive value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|123||[[Help:VE123|&amp;quot;The script file &#039;$(FILE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|124||[[Help:VE124|&amp;quot;The file &#039;$(FILE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|125||[[Help:VE125|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|126||[[Help:VE126|&amp;quot;&#039;$(TAG_NAME)&#039; must not be zero.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|127||[[Help:VE127|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|128||[[Help:VE128|&amp;quot;The value for &#039;$(TAG_NAME)&#039; must be between &#039;$(MIN)&#039; and &#039;$(MAX)&#039; but was specified as &#039;$(VALUE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|129||[[Help:VE129|&amp;quot;Incorrect number of values for the tag &#039;$(TAG_NAME)&#039;, expected $(NUM_0) values, found $(NUM_1).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|130||[[Help:VE130|&amp;quot;Too many values for the tag &#039;$(TAG_NAME)&#039;, maximum is $(MAX) values, found $(FOUND).&amp;quot;]]]]&lt;br /&gt;
|-&lt;br /&gt;
|131||[[Help:VE131|&amp;quot;Value must be a mesh from the mesh-table (not a parent container).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|132||[[Help:VE132|&amp;quot;The attachment point &#039;$(ATT)&#039; must belong to the parent mesh of the effect (mesh=$(MESH)).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|133||[[Help:VE133|&amp;quot;A light container must be present to link the signals.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|134||[[Help:VE134|&amp;quot;&#039;$(NUM)&#039; must be a valid light number from the light container.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|135||[[Help:VE135|&amp;quot;&#039;$(TAG_0)&#039; requires that the tag &#039;$(TAG_1)&#039; be present.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|136||[[Help:VE136|&amp;quot;&#039;$(TAG_0)&#039; requires that the tag &#039;$(TAG_1)&#039; be present.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|137||[[Help:VE137|&amp;quot;Empty or invalid running number specified at character index $(INDEX)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|138||[[Help:VE138|&amp;quot;Running number specified at character index $(INDEX) is too large, must be less than 9 characters.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|139||[[Help:VE139|&amp;quot;Invalid running number range specified at character index $(INDEX), ($(FROM)-$(TO)).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|140||[[Help:VE140|&amp;quot;Running number range &#039;$(FROM)-$(TO)&#039; specified at character index $(INDEX) overlaps already in use numbers, running numbers must be unique.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|141||[[Help:VE141|&amp;quot;Running number &#039;$(NUMBER)&#039; specified at character index $(INDEX) is already in use.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|142||[[Help:VE142|&amp;quot;Invalid character &#039;$(CHAR)&#039; specified in running number list, only numbers, &#039;,&#039; and &#039;-&#039; are supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|143||[[Help:VE143|&amp;quot;Possible running number list is too large, the set must contain less than 20000 possibilities.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|144||[[Help:VE144|&amp;quot;Category code &#039;ZX - Paintshed template&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|145||[[Help:VE145|&amp;quot;Category code &#039;ZX - Paintshed template&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|146||[[Help:VE146|&amp;quot;An asset must be specified for tag &#039;$(TAG_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|147||[[Help:VE147|&amp;quot;The tag(s) $(MISPLACED_TAGS) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|148||[[Help:VE148|&amp;quot;The tag(s) $(MISPLACED_TAGS) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|149||[[Help:VE149|&amp;quot;The mesh(es) $(MISPLACED_MESHES) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|150||[[Help:VE150|&amp;quot;The mesh(es) $(MISPLACED_MESHES) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|151||[[Help:VE150|&amp;quot;The mesh(es) $(MISPLACED_MESHES) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|152||[[Help:VE152|&amp;quot;The tags $(MISSING_TAGS) are not all defined. The default values will be used and the positions of the elements may not fit your track.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|153||[[Help:VE153|&amp;quot;The mesh $(MESH) is present but the tag $(MISSING_TAG) is not defined.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|154||[[Help:VE154|&amp;quot;The mesh $(MESH) is present but the tag $(MISSING_TAG) is not defined.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|155||[[Help:VE155|&amp;quot;The mesh $(MESH) is present but the tags $(MISSING_TAGS) are not all defined.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|156||[[Help:VE156|&amp;quot;The tag $(MISSING_TAG) is not defined. The default value will be used and the positions of the elements may not fit your track.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|157||[[Help:VE157|&amp;quot;The mesh $(MESH) is present but the tag $(MISSING_TAG) is missing. The default value will be used and the positions of the elements may not fit your track.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|158||[[Help:VE158|&amp;quot;Unable to open .lm.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|159||[[Help:VE159|&amp;quot;Unable to parse .lm.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|160||[[Help:VE160|&amp;quot;No &#039;mesh&#039; keys found in .lm.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|161||[[Help:VE161|&amp;quot;$(LODCOUNT) LODs in .lm.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|162||[[Help:VE162|&amp;quot;One of the LOD reductions of &#039;$(FILE)&#039; introduces a new attachment point: $(ATT)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|163||[[Help:VE163|&amp;quot;Unable to parse .im file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|164||[[Help:VE164|&amp;quot;Invalid position data in .im file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|165||[[Help:VE165|&amp;quot;Texture &#039;$(TEXTURE)&#039; is missing or could not be loaded in mesh &#039;$(FILE)&#039;, material &#039;$(MATERIAL)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|166||[[Help:VE166|&amp;quot;$(COMBINEDCOUNT) combined chunks (of $(SOURCECOUNT) source) in .im file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|167||[[Help:VE167|&amp;quot;Source image texture file &#039;$(TEXTUREFILE)&#039; is too large for &#039;$(ASSETFILE)&#039; ($(WIDTH)x$(HEIGHT))&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|168||[[Help:VE168|&amp;quot;File &#039;$(TEXTUREFILE)&#039; is not a valid compiled texture file for &#039;$(ASSETFILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|169||[[Help:VE169|&amp;quot;Compiled texture file &#039;$(TEXTUREFILE)&#039; is unsupported version for &#039;$(ASSETFILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|170||[[Help:VE170|&amp;quot;Failed to open compiled texture &#039;$(TEXTUREFILE)&#039; for &#039;$(ASSETFILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|171||[[Help:VE171|&amp;quot;Expected texture file type but found &#039;$(TEXTUREFILE)&#039; for &#039;$(ASSETFILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|172||[[Help:VE172|&amp;quot;Script class does not match asset kind ($(KIND)).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|173||[[Help:VE173|&amp;quot;Material &#039;$(MATERIAL)&#039; in mesh &#039;$(FILE)&#039; is not of a recognised material type.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|174||[[Help:VE174|&amp;quot;MeshObjectSpec::LinkSpecs&amp;gt; Mesh-table element #$(MESH_INDEX) parent mesh is invalid.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|175||[[Help:VE175|&amp;quot;MeshObjectSpec::LinkSpecs&amp;gt; Mesh-table element #$(MESH_INDEX) is part of invalid hierarchy.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|176||[[Help:VE176|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must have a texture file extension.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|177||[[Help:VE177|&amp;quot;The kuid &#039;$(KUID)&#039; is not in the database, and could not be found in any known location. Ensure that this is a valid asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|178||[[Help:VE178|&amp;quot;The asset specified in &#039;$(KUID)&#039; is not installed locally but is available for download.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|179||[[Help:VE179|&amp;quot;The kuid &#039;$(KUID)&#039; specified in &#039;$(TAG_NAME)&#039; is not of the correct type.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|180||[[Help:VE180|&amp;quot;Integrity check failure on $(FILE). One or more route/session tiles may be missing.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|181||[[Help:VE181|&amp;quot;The tag &#039;$(TAG_NAME)&#039; requires a minimum asset version of $(MIN_VERSION)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|182||[[Help:VE182|&amp;quot;Material &#039;$(MATERIAL)&#039; in mesh &#039;$(FILE)&#039; is missing a texture for a mandatory texture slot.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|183||[[Help:VE183|&amp;quot;FBX file is in an unsupported older format.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|184||[[Help:VE184|&amp;quot;KIND &#039;$(KIND)&#039; requires trainz-build $(TRAINZBUILD).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|185||[[Help:VE185|&amp;quot;Material &#039;$(MATERIAL)&#039; in mesh &#039;$(FILE)&#039; has heightmap texture. Provide a normal map instead.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|186||[[Help:VE186|&amp;quot;Material &#039;$(MATERIAL)&#039; is shared between multiple chunks in this asset but the material parameters conflict.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|187||[[Help:VE187|&amp;quot;The value &#039;$(VALUE)&#039; in not a valid KUID.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|188||[[Help:VE188|&amp;quot;Custom render plugin failed to load mesh &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|189||[[Help:VE189|&amp;quot;Collision data exceeds $(LIMIT)KB. Please specify a different generation method or a simplified mesh.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|190||[[Help:VE190|&amp;quot;Tag &#039;$(NAME)&#039; is unable to be converted from $(TYPE1) to $(TYPE2)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|191||[[Help:VE191|&amp;quot;Tag &#039;$(NAME)&#039; does not contain a valid integer: $(VALUE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|192||[[Help:VE192|&amp;quot;Tag &#039;$(NAME)&#039; does not contain a valid float list: $(VALUE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|193||[[Help:VE193|&amp;quot;Tag &#039;$(NAME)&#039; does not contain a valid float&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|194||[[Help:VE194|&amp;quot;Tag &#039;$(NAME)&#039; does not contain a valid kuid: $(VALUE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|195||[[Help:VE195|&amp;quot;Unable to parse chunk $(CHUNK_INDEX) in mesh file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|196||[[Help:VE196|&amp;quot;Failed to load bogey $(KUID)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|197||[[Help:VE197|&amp;quot;Syntax error in script &#039;$(SCRIPT)&#039; for asset $(ASSET)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|198||[[Help:VE198|&amp;quot;Session failed to load route asset: $(KUID)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|199||[[Help:VE199|&amp;quot;Asset $(KUID) failed to load. Unloading resources.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|200||[[Help:VE200|&amp;quot;Unable to load mesh $(NAME) for $(ASSET_ID)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|201||[[Help:VE201|&amp;quot;Traincar is missing required attachment point: $(ATT_NAME)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|202||[[Help:VE202|&amp;quot;Parse error reading twinkles file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|203||[[Help:VE203|&amp;quot;Bad sequence order in $(TAG_NAME) list. Each element must be greater than the last.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|204||[[Help:VE204|&amp;quot;Invalid range in $(TAG_NAME) list. Elements must be greater than or equal to $(INC_MIN) and less than $(EXC_MAX).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|205||[[Help:VE205|&amp;quot;Invalid element count in $(TAG_NAME) list. This list must have at least $(COUNT) elements (to match the $(TAG_START) list).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|206||[[Help:VE206|&amp;quot;The season-selector references season &#039;$(SEASON)&#039;, but this does not exist in the texture-variants container.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|207||[[Help:VE207|&amp;quot;Attached track asset $(CHILD) failed to load.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|208||[[Help:VE208|&amp;quot;Attached track asset not specified for track $(INDEX).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|209||[[Help:VE209|&amp;quot;Asset is missing the required &#039;attached-track&#039; container.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|210||[[Help:VE210|&amp;quot;Asset is missing the required &#039;track&#039; tag.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|211||[[Help:VE211|&amp;quot;Asset is missing the required &#039;road&#039; tag.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|212||[[Help:VE212|&amp;quot;Traincar asset must have at least two bogeys.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|213||[[Help:VE213|&amp;quot;Traincar asset has invalid bogey placement.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|214||[[Help:VE214|&amp;quot;Traincar asset has invalid length.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|215||[[Help:VE215|&amp;quot;Asset has an invalid number of LODs: $(LOD_COUNT)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|216||[[Help:VE216|&amp;quot;Material $(MATERIAL) in mesh file $(MESH) has an inappropriate texture slot assigned: $(TEXTURE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|217||[[Help:VE217|&amp;quot;Material $(MATERIAL) in mesh file $(MESH) has no texture assigned to a required slot: $(TEXTURE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|218||[[Help:VE218|&amp;quot;Asset has duplicate attached track at track $(INDEX).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|219||[[Help:VE219|&amp;quot;Failed to load driver mesh $(ASSETID).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|220||[[Help:VE220|Miscellaneous script compiler output.]]&lt;br /&gt;
|-&lt;br /&gt;
|221||[[Help:VE221|&amp;quot;$(ASSETID) is faulty and will not be loaded.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|222||[[Help:VE222|&amp;quot;Failed to load mesh $(ASSETID)-$(MESHFILE) for TNI plugin renderer.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|223||[[Help:VE223|&amp;quot;Unable to create mesh index $(MESHINDEX) for asset $(ASSET).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|224||[[Help:VE224|&amp;quot;Corrupted data in mesh file &#039;$(FILENAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|225||[[Help:VE225|&amp;quot;Failed to query asset details for featured asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|226||[[Help:VE226|&amp;quot;Failed to upload asset details for featured asset: $(ERRORTEXT)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|227||[[Help:VE227|&amp;quot;Missing image for featured asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|228||[[Help:VE228|&amp;quot;Failed to read image file for featured asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|229||[[Help:VE229|&amp;quot;DLC marketing image is missing or incorrectly sized for featured asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|230||[[Help:VE230|&amp;quot;DLS thumbnail image is missing or incorrectly sized for featured asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|231||[[Help:VE231|&amp;quot;Failed to open image file for featured asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|232||[[Help:VE232|&amp;quot;Failed to upload image for featured asset: $(ERRORTEXT)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|233||[[Help:VE233|&amp;quot;One or more featured assets was not provided.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|234||[[Help:VE234|&amp;quot;Asset is not present in the featured assets list.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|235||[[Help:VE235|&amp;quot;Featured asset is not present in the input.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|236||[[Help:VE236|&amp;quot;Featured asset was not available.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|237||[[Help:VE237|&amp;quot;Featured asset failed validation.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|238||[[Help:VE238|&amp;quot;Featured asset has faulty or missing dependencies.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|239||[[Help:VE239|&amp;quot;Featured asset is Base content.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|240||[[Help:VE240|&amp;quot;Featured asset is missing an English name or description.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|241||[[Help:VE241|&amp;quot;Newly built package is not compatible with previously released version.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|242||[[Help:VE242|&amp;quot;Unable to load animation file &#039;$(FILE)&#039; (file not found, or is damaged).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|243||[[Help:VE243|&amp;quot;Failed to submit changes to asset $(ASSET_KUID) due to file access error&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|244||[[Help:VE244|&amp;quot;Files in base assets cannot use importers: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|245||[[Help:VE245|&amp;quot;Missing compiled texture: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|246||[[Help:VE246|&amp;quot;Missing source texture: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|247||[[Help:VE247|&amp;quot;Creating default texture.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|248||[[Help:VE248|&amp;quot;Failed to create *.texture.txt file for source image: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|249||[[Help:VE249|&amp;quot;Failed to compile *.texture.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|250||[[Help:VE250|&amp;quot;Material Metadata expected data for texture slot &#039;$(SLOT)&#039; of material &#039;$(MATERIAL)&#039; but none found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|251||[[Help:VE251|&amp;quot;Material Metadata expected *.texture resource for texture slot &#039;$(SLOT)&#039; of material &#039;$(MATERIAL)&#039; bout found: $(FOUND)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|252||[[Help:VE252|&amp;quot;Mesh material expected data for texture slot &#039;$(SLOT)&#039; of material &#039;$(MATERIAL)&#039; but none found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|253||[[Help:VE253|&amp;quot;WriteAnimationFileBoneChunk&amp;gt; excessive bone-chunk count.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|254||[[Help:VE254|&amp;quot;Unable to open mesh metadata file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|255||[[Help:VE255|&amp;quot;Mesh contains unsupported non-triangle primitives.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|256||[[Help:VE256|&amp;quot;Mesh contains invalid material index.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|257||[[Help:VE257|&amp;quot;Mesh contains no primitives.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|258||[[Help:VE258|&amp;quot;Unable to determine vertex format.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|259||[[Help:VE259|&amp;quot;Unsupported number of texture channels.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|260||[[Help:VE260|&amp;quot;Invalid index in primitive.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|261||[[Help:VE261|&amp;quot;Unable to create animation file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|262||[[Help:VE262|&amp;quot;Unable to open animation event file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|263||[[Help:VE263|&amp;quot;Unable to parse animation event file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|264||[[Help:VE264|&amp;quot;Parsed animation event file $(FILE) with $(COUNT) events.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|265||[[Help:VE265|&amp;quot;Unable to search path: &#039;$(FILE_PATH)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|266||[[Help:VE266|&amp;quot;Multiple values found for engine spec param &amp;lt;kuid:xxx:yyy&amp;gt;/tag-name (Value1 and Value2)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|267||[[Help:VE267|&amp;quot;member $(MEMBER) is obsolete in object $(CLASS).&amp;quot;]]&lt;br /&gt;
&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=Vehicle-running-numbers_container&amp;diff=29855</id>
		<title>Vehicle-running-numbers container</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=Vehicle-running-numbers_container&amp;diff=29855"/>
		<updated>2021-08-04T23:48:26Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The vehicle-running-numbers container is an optional subcontainer used by [[KIND Traincar]] assets to define the behaviour of automatic random running-number generation. Support for this subcontainer was added in [[Trainz A New Era]] as a faster alternative to various custom scripts which attempt to do the same thing.&lt;br /&gt;
&lt;br /&gt;
==vehicle-running-numbers Container==&lt;br /&gt;
&lt;br /&gt;
Example running numbers container:&lt;br /&gt;
&lt;br /&gt;
 vehicle-running-numbers&lt;br /&gt;
 {&lt;br /&gt;
   running-numbers                       &amp;quot;35050-35150&amp;quot;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
==Supported Tags==&lt;br /&gt;
The vehicle-running-numbers container supports the following tags. Each tag is shown here with its default value. &lt;br /&gt;
&lt;br /&gt;
  running-numbers                   &amp;quot;&amp;quot;&lt;br /&gt;
  multiple-unit-increment-front&lt;br /&gt;
  multiple-unit-increment-rear&lt;br /&gt;
&lt;br /&gt;
====running-numbers====&lt;br /&gt;
:Type: Text&lt;br /&gt;
:Desc: Specifies the valid running-number range(s) to randomly select from. This can be a list, a range, or any combination of both. For example:&lt;br /&gt;
  running-numbers                   &amp;quot;12345,67890,30000-31000&amp;quot;&lt;br /&gt;
This example will cause the traincar to be randomly assigned the running number 12345, 67890, or any number in between 30000 (inclusive) and 31000 (exclusive). Running numbers are assigned on train placement, and can be overridden using the traincar properties dialog.&lt;br /&gt;
&lt;br /&gt;
====multiple-unit-increment-front====&lt;br /&gt;
:Type: Integer&lt;br /&gt;
:Desc: Optional tag used for assigning sequential/identical running numbers to multiple-unit trains. See the following section for more information about multiple units.&lt;br /&gt;
&lt;br /&gt;
====multiple-unit-increment-rear====&lt;br /&gt;
:Type: Integer&lt;br /&gt;
:Desc: Optional tag used for assigning sequential/identical running numbers to multiple-unit trains. See the following section for more information about multiple units.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Multiple unit trains==&lt;br /&gt;
The multiple-unit-increment-* tags allow you to define sets of traincars which are automatically numbered identically or sequentially. This is useful for prototypical situations where multiple locomotives may be considered one unit, and thus numbered in some patterned way.&lt;br /&gt;
&lt;br /&gt;
Each of these tags specifies whether the front/rear coupler of the traincar continues the multiple unit set. For example if you have a traincar asset which species only multiple-unit-increment-front, then two of those traincars coupled nose-to-nose will create a &#039;set&#039;. Without the multiple-unit-increment-rear tag any traincar coupled to the rear will *not* be considered part of the set (regardless of any multiple-unit tag on that other traincar). This means that these tags effectively have no default value, as there presence alone will change the behaviour of the automatic numbering. If you do not want set numbering at all, do not add these tags.&lt;br /&gt;
&lt;br /&gt;
Once a set of compatible traincars exists in a consist the frontmost traincar will be chosen as the &#039;seed&#039; and given a random running number as normal. The coupled traincar will then be assigned a running-number based on the value of the relevant tag (e.g. multiple-unit-increment-front if the &#039;seed&#039; traincar is coupled to the front). If this number is 0, the running-number will be identical. A value of 100 will result in adding 100 to the running-number of the seed. Negative values are allowed. This process continues until the end of the set, or until an invalid running-number is generated. Generation of an invalid running-number will result in a new set being created (with the current traincar becoming the new seed).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Asset Creation / Trouble Shooting==&lt;br /&gt;
&lt;br /&gt;
There is more information [[Alpha_Numbers|HERE]] to find out how to put running numbers on your Trainz content.&lt;br /&gt;
&lt;br /&gt;
You can find a How To guide for adding the vehicle-running-numbers container to your asset [[Adding_the_Native_Automatic_Running_Numbers_system_to_a_traincar|Here]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Return To&lt;br /&gt;
*[[Content_Creation]]&lt;br /&gt;
*[[KIND_Traincar|Kind Traincar]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Config Container|V]]&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=Adding_the_Native_Automatic_Running_Numbers_system_to_a_traincar&amp;diff=29853</id>
		<title>Adding the Native Automatic Running Numbers system to a traincar</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=Adding_the_Native_Automatic_Running_Numbers_system_to_a_traincar&amp;diff=29853"/>
		<updated>2021-08-04T23:44:20Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Introduced with Trainz: A New Era, the Native Vehicle Running Numbers system provides a built-in method of automatic running numbers for traincars (locomotives and rolling stock) in Trainz, using a range of numbers specified in the config.txt file to assign running numbers to the traincar when placed. The system also supports multiple-unit numbering (ie where each vehicle in a multiple-unit set will either have the same number, or can increase the number by an amount set in the relevant tags; see [[#Adding the Native Vehicle Running Numbers system to an asset|Adding to an asset.]]&lt;br /&gt;
&lt;br /&gt;
The numbers can still be changed in-game via the Properties window as per any other traincar in Trainz.&lt;br /&gt;
&lt;br /&gt;
The visible numbers on the traincar will still use the existing [[Alpha_Numbers|Alpha-Numbers]] system.&lt;br /&gt;
&lt;br /&gt;
==Scripted assets==&lt;br /&gt;
Prior to Trainz: A New Era, many assets used scripts such as &#039;NumberIt&#039;, &#039;ARN&#039; (Automatic Running Numbers), and other custom scripts to assign the running numbers to the traincar when placed. The script is the &#039;.gs&#039; file found in some Trainz assets; a single script file is normally used in Trainz, and as such may do multiple different things.&lt;br /&gt;
&lt;br /&gt;
In many cases, these scripts allowed effectively unlimited number ranges, which caused the script to take a long time to load or process the running numbers. This could cause issues with Trainz loading the asset. Trainz: A New Era will limit how long the script can take to load, and hence if it takes too long it will time out and not load.&lt;br /&gt;
&lt;br /&gt;
For Trainz: A New Era and onwards, it is recommended to use the Native Vehicle Running Numbers system to assign numbers to your traincars. This will help avoid script errors (causing numbers to not load, and possibly other functions on the traincar to not operate), and reduce the script load on Trainz itself.&lt;br /&gt;
&lt;br /&gt;
==The Vehicle Running Numbers Container==&lt;br /&gt;
The Native Vehicle Running Numbers system is configured with some very simple tags, specifically the Vehicle Running Numbers container.&lt;br /&gt;
&lt;br /&gt;
For detailed information on the tags in this container, see [[Vehicle-running-numbers_container|Vehicle Running Numbers container]], including information on multiple unit train setup.&lt;br /&gt;
&lt;br /&gt;
The container, when entered into the config.txt file will appear as&lt;br /&gt;
&lt;br /&gt;
 vehicle-running-numbers&lt;br /&gt;
 {&lt;br /&gt;
 running-numbers          &amp;quot;1-5,7,9-11&amp;quot;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The container allows you to enter individual numbers, as well as number ranges. Number ranges are specified with the lower end of the range first (inclusive), then a hyphen, then the higher end of the range (exclusive). Individual numbers, or multiple ranges, are separated by a comma (,). The above example will give the numbers 1, 2, 3, 4, 7, 9, 10.&lt;br /&gt;
&lt;br /&gt;
==Adding the Native Vehicle Running Numbers system to an asset==&lt;br /&gt;
It is very simple to add the Native Vehicle Running Numbers system to an asset by following these steps. Please note, these steps do not cover updating assets to Trainz-Build 4.2, or adding alpha-numbers to an asset.&lt;br /&gt;
&lt;br /&gt;
1) Open the asset for edit in Content Manager (Trainz Content), and open in explorer/finder (right click on the asset, go to &#039;open&#039;, then click on &#039;in explorer&#039; or &#039;in finder&#039;)&lt;br /&gt;
&lt;br /&gt;
2) Double click on the &#039;config.txt&#039; file&lt;br /&gt;
&lt;br /&gt;
3) Now that the config file is open, the first step is to ensure that your asset&#039;s Trainz-Build number is set to 4.2 (TANE release) or higher. You should always use the minimum Trainz-Build number that you can test the asset in (ie if you only have access to TANE SP2 or SP3 for testing, then you should use build 4.5).&lt;br /&gt;
&lt;br /&gt;
3-A) Changing the Trainz-Build number on an existing asset will enforce the TANE level error checking on the assets, placing stricter [[Level_of_Detail|Level Of Detail]] requirements on assets, and correct material configuration (in particular where a material with the same name is shared between different meshes) and naming.&lt;br /&gt;
&lt;br /&gt;
4) The next step is to enter the vehicle-running-numbers container into your asset. This is placed at the &#039;root level&#039; of the config.txt (ie not inside any other containers). Copy and paste the following into your config.txt:&lt;br /&gt;
 vehicle-running-numbers&lt;br /&gt;
 {&lt;br /&gt;
 running-numbers          &amp;quot;&amp;quot;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
5) You will now need to enter the number range for your traincar between the quote marks. For example:&lt;br /&gt;
 running-numbers &amp;quot;1,5,20-50,75-100&amp;quot;&lt;br /&gt;
&lt;br /&gt;
6) Save your config.txt file, and close the text editor.&lt;br /&gt;
&lt;br /&gt;
7) Go back to Content Manager, right click on your asset, then click on submit.&lt;br /&gt;
&lt;br /&gt;
8) Now try placing your traincar within Surveyor (do not place in Driver in TANE, as the running numbers may not automatically load due to a known bug in TANE). When placed it should automatically receive a number within the specified number range.&lt;br /&gt;
&lt;br /&gt;
==Updating an asset with scripted running numbers==&lt;br /&gt;
If you are updating an existing asset with scripted running numbers, then there are a few things to be mindful of. The following steps are a general guide, as different script methods used may function differently, and require different steps.&lt;br /&gt;
&lt;br /&gt;
1) Open the asset for edit in Content Manager, and open in explorer/finder (right click on the asset, go to &#039;open&#039;, then click on &#039;in explorer&#039; or &#039;in finder&#039;)&lt;br /&gt;
&lt;br /&gt;
2) Double click on the &#039;config.txt&#039; file&lt;br /&gt;
&lt;br /&gt;
3) Now that the config file is open, the first step is to ensure that your asset&#039;s Trainz-Build number is set to 4.2 (TANE release) or higher. You should always use the minimum Trainz-Build number that you can test the asset in (ie if you only have access to TANE SP2 or SP3 for testing, then you should use build 4.5).&lt;br /&gt;
&lt;br /&gt;
3-A)Changing the Trainz-Build number on an existing asset will enforce the TANE level error checking on the assets, placing stricter [[Level_of_Detail|Level Of Detail]] requirements on assets, and correct material configuration (in particular where a material with the same name is shared between different meshes) and naming.&lt;br /&gt;
&lt;br /&gt;
4) The next step is to remove the old config tags for the scripted running numbers. These will vary, but will generally mention &#039;numbers&#039; or similar. For example, the &#039;NumbertIt&#039; script has the following tags:&lt;br /&gt;
 numberit-75134&lt;br /&gt;
 {&lt;br /&gt;
 numberit_prefix                     &amp;quot;94&amp;quot;&lt;br /&gt;
 numberit_min                        &amp;quot;0000&amp;quot;&lt;br /&gt;
 numberit_max                        &amp;quot;9999&amp;quot;&lt;br /&gt;
 }&lt;br /&gt;
This entire container must be removed.&lt;br /&gt;
&lt;br /&gt;
5)Once removed, the next step is to enter the vehicle-running-numbers container into your asset. This is placed at the &#039;root level&#039; of the config.txt (ie not inside any other containers). Copy and paste the following into your config.txt:&lt;br /&gt;
 vehicle-running-numbers&lt;br /&gt;
 {&lt;br /&gt;
 running-numbers          &amp;quot;&amp;quot;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
5) You will now need to enter the number range for your traincar between the quote marks. For example:&lt;br /&gt;
 running-numbers &amp;quot;1,5,20-50,75-100&amp;quot;&lt;br /&gt;
&lt;br /&gt;
6) Save your config.txt file, and close the text editor.&lt;br /&gt;
&lt;br /&gt;
7) Go back to Content Manager, right click on your asset, then click on submit.&lt;br /&gt;
&lt;br /&gt;
8) Now try placing your traincar within Surveyor (do not place in Driver in TANE, as the running numbers may not automatically load due to a known bug in TANE). When placed it should automatically receive a number within the specified number range.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;background-color: #ddf5eb; border-style: dotted;&amp;quot;&amp;gt;&lt;br /&gt;
TIP: Most scripts should not need the script edited after doing this, although if you know how to it is recommended that the running number code be removed from your asset&#039;s script, so as to reduce the resources used.&lt;br /&gt;
&lt;br /&gt;
If the script only provides automatic running numbers, then the entire script (gs file) and the &#039;script&#039; and &#039;class&#039; config tags can be removed.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==In-game use==&lt;br /&gt;
When used in-game, the numbers will be automatically assigned. You can change the number on a traincar in Surveyor (or Driver) by following these steps:&lt;br /&gt;
#Open the Trains Tab&lt;br /&gt;
#Select the &#039;Properties&#039; tool (the ? icon)&lt;br /&gt;
#Click on the traincar you wish to change; this will open that traincar&#039;s Properties window&lt;br /&gt;
#Click on the running number shown&lt;br /&gt;
#Enter the number you want the traincar to have&lt;br /&gt;
#Click the checkmark in the running number window&lt;br /&gt;
#Click the checkmark in the &#039;Properties&#039; window&lt;br /&gt;
#You should now see the new number shown on the traincar&lt;br /&gt;
&lt;br /&gt;
Alternatively, you can assign a new random number by following these steps:&lt;br /&gt;
#Open the Trains Tab&lt;br /&gt;
#Select the &#039;Properties&#039; tool (the ? icon)&lt;br /&gt;
#Click on the traincar you wish to change; this will open that traincar&#039;s Properties window&lt;br /&gt;
#Click on the ( Automatic ) or ( Manual ) text to the right of the running number; this will cause a new number to be automatically generated.&lt;br /&gt;
#Click the checkmark in the &#039;Properties&#039; window&lt;br /&gt;
#You should now see the new number shown on the traincar&lt;br /&gt;
&lt;br /&gt;
Return To&lt;br /&gt;
*[[HowTo|How To Guides]]&lt;br /&gt;
*[[KIND_Traincar|Kind Traincar]]&lt;br /&gt;
*[[Vehicle-running-numbers_container|Vehicle-Running-Numbers Container]]&lt;br /&gt;
&lt;br /&gt;
[[Category:How-to_guides|HowTo Guides]]&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=KIND_Map&amp;diff=29180</id>
		<title>KIND Map</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=KIND_Map&amp;diff=29180"/>
		<updated>2021-04-06T23:58:16Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: remove incorrect mention of carrate&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{FUN-beg}}&lt;br /&gt;
{{ORP-top}}&lt;br /&gt;
[[KIND Map]] is the trainz [[KIND|kind]] (Base {{wp|data type}}) used for organizing and storing a Map. The Maps data types are created in surveyor and stored under the \User data subfolder of the Trainz installation (versions after TS2009 SP2), so for the most part, hand-editing of a map [[Config.txt_file|config file]] should not be required.&lt;br /&gt;
{{user-tip|width=66%&lt;br /&gt;
|Maps, are called in ContentManager a Route (Set the search pane for &#039;&#039;&#039;category [[Route]]s&#039;&#039;&#039; to list all) and often called in the model railroading community as a &#039;&#039;&#039;Layout&#039;&#039;&#039;.&lt;br /&gt;
}}&lt;br /&gt;
=KIND Hierarchy=&lt;br /&gt;
Short of considering ContentManager a container, or speaking of the data base, the Map data type (in it&#039;s folder) is the highest organized data type in the software system data heirarchy. It holds the [[kuid-table|kuid]] and [[string-table|string]] tables defining the virtual world the player will interact with and links to all other assets applicable to a routes navigation in Surveyor, as well as specifying most of the &#039;world&#039; data needed in the Driver Module. &lt;br /&gt;
&lt;br /&gt;
==Parent Classes==&lt;br /&gt;
* [[KIND TrainzBaseSpec]]&lt;br /&gt;
==Child Classes==&lt;br /&gt;
* &#039;&#039;All non-map assets might be referenced in a map asset.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=Supported Tags=&lt;br /&gt;
Each map asset supports the following tags. Each tag is shown here with its default value.&lt;br /&gt;
&lt;br /&gt;
 holdcarz      1&lt;br /&gt;
 info-page     &amp;quot;filename.htm&amp;quot;&lt;br /&gt;
 region        &amp;lt;NULLKUID&amp;gt;&lt;br /&gt;
 workingscale  0&lt;br /&gt;
 workingunits  0&lt;br /&gt;
 water         &amp;lt;KUID:-1:8009&amp;gt;&lt;br /&gt;
 car0          &amp;lt;NULLKUID&amp;gt;&lt;br /&gt;
 soundscript&lt;br /&gt;
 {&lt;br /&gt;
 }&lt;br /&gt;
 world-origin&lt;br /&gt;
 {&lt;br /&gt;
 }&lt;br /&gt;
 autosave      0&lt;br /&gt;
&lt;br /&gt;
====holdcarz====&lt;br /&gt;
:Type: Boolean&lt;br /&gt;
:Desc: True if road traffic should be disabled.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====info-page====&lt;br /&gt;
:Type: Filename&lt;br /&gt;
:Desc: &lt;br /&gt;
::Original use: File reference to (usually) an HTML file (so called &#039;Tech Manuals&#039;) describing use of an asset, or in the case of a complex session or route, providing details in the form of text explanations, lists, tables, schedules and many many maps. &lt;br /&gt;
::Today:&lt;br /&gt;
::: a) In the vision of N3V game software engineers, obsolescent, so should be &amp;quot;No longer used.&amp;quot;&lt;br /&gt;
::: b) In practice, some game asset developers are linking pages here on the TrainzOnline Wiki to serve as the tech manual for assets, a highly important need in complex routes.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====region====&lt;br /&gt;
:Type: [[KUID]]&lt;br /&gt;
:Desc: KUID of [[KIND_Region|Region]] asset that this map is set in. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====workingscale====&lt;br /&gt;
:Type: Number&lt;br /&gt;
:Desc: Index of the option picked for the world &#039;scale&#039; in surveyor.&lt;br /&gt;
&lt;br /&gt;
 0  - 1:1    (Real Scale)&lt;br /&gt;
 1  - 1:22.5 (G Scale)&lt;br /&gt;
 2  - 1:24   (Half Inch scale)&lt;br /&gt;
 3  - 1:32   (1 scale)&lt;br /&gt;
 4  - 1:48   (0 scale)&lt;br /&gt;
 5  - 1:64.5 (S scale)&lt;br /&gt;
 6  - 1:76.2 (00 scale)&lt;br /&gt;
 7  - 1:87.1 (HO scale)&lt;br /&gt;
 8  - 1:120  (TT scale)&lt;br /&gt;
 9  - 1:160  (N scale)&lt;br /&gt;
 10 - 1:220  (Z scale)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====workingunits====&lt;br /&gt;
:Type: Number&lt;br /&gt;
:Desc: 0 for metric (speed in km/h, distances in metres), 1 for imperial (speed in mph, distances in feet).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====water====&lt;br /&gt;
:Type: [[KUID]]&lt;br /&gt;
:Desc: KUID of [[KIND_Water2|water]] asset that this map uses.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====soundscript====&lt;br /&gt;
:Type: Container&lt;br /&gt;
:Desc: [[%22soundscript%22_Container|SoundScript Container]] to specify ambient sound in this map.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====[[&amp;quot;World-origin&amp;quot;_container|world-origin]]====&lt;br /&gt;
:Type: Container&lt;br /&gt;
:Desc: World origin container&lt;br /&gt;
&lt;br /&gt;
====car0====&lt;br /&gt;
:Type: [[KUID]]&lt;br /&gt;
:Desc: KUID of car to add to the pool of available road traffic provided by the region.&lt;br /&gt;
&lt;br /&gt;
This is a sequence - increment the number to add more cars.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====autosave====&lt;br /&gt;
:Type: boolean&lt;br /&gt;
:Desc: True if this map was generated by the surveyor auto-save process.&lt;br /&gt;
&lt;br /&gt;
=Categories=&lt;br /&gt;
[[Category:Asset KIND|map]]&lt;br /&gt;
{{FUN-bot|map}}&lt;br /&gt;
{{ORP-bot|map}}&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=Category:Validation_Errors&amp;diff=23823</id>
		<title>Category:Validation Errors</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=Category:Validation_Errors&amp;diff=23823"/>
		<updated>2020-07-30T08:36:11Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Validation Error (VE) numbers are logged during content validation, to allow users to look up particular validation messages to better understand the source of the problem. Normal logs provide a substantial amount of technical detail about the error, but typically assume that the reader is familiar with the subject matter and will understand why the log is relevant. This wiki provides the necessary background information to understanding many of the logs, however a user who is unfamiliar with the area in question may not know where to start looking. VE numbers allow users to quickly find relevant pages in the wiki without any prior knowledge of the subject.&lt;br /&gt;
&lt;br /&gt;
This page serves as a master guide to all VE numbers currently logged by Trainz. This page does not provide detailed information on any given VE number- please refer to the individual VE number pages for specific details. The error text here is correct for the English localisation of Trainz at the time of writing, however the exact text may change from time to time. It is intended that the overall meaning of a VE number will never change- new VE numbers will be issued instead, and old VE numbers may be made obsolete.&lt;br /&gt;
&lt;br /&gt;
Logs which lack VE numbers do not belong on this page.&lt;br /&gt;
&lt;br /&gt;
The individual VE pages can be found at the links below, or can be accessed directly from [[Content Manager]] by right-clicking on the Validation Error in the results log, and selecting &amp;quot;View Help for This Message&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|1||[[Help:VE1|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Decimal value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|2||[[Help:VE2|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Integer value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|3||[[Help:VE3|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|4||[[Help:VE4|&amp;quot;&#039;$(TAG_NAME)&#039; must have a positive value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|5||[[Help:VE5|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|6||[[Help:VE6|&amp;quot;&#039;$(TAG_NAME)&#039; must not be zero.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|7||[[Help:VE7|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|8||[[Help:VE8|&amp;quot;The value for &#039;$(TAG_NAME)&#039; must be between &#039;$(MIN)&#039; and &#039;$(MAX)&#039; but was specified as &#039;$(VALUE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|9||[[Help:VE9|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|10||[[Help:VE10|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|11||[[Help:VE11|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|12||[[Help:VE12|&amp;quot;No string-table entry found with tag &#039;$(VALUE)&#039; for for string-token tag &#039;$(TAG)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|13||[[Help:VE13|&amp;quot;Missing or invalid selection for tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|14||[[Help:VE14|&amp;quot;Missing or invalid selection for tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|15||[[Help:VE15|&amp;quot;Attachment point &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must be found in mesh &#039;$(MESH_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|16||[[Help:VE16|&amp;quot;Container &#039;$(CONT_NAME)&#039; does not have an &#039;att-parent&#039; tag which is required to reference an attachment point.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|17||[[Help:VE17|&amp;quot;Attachment point &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must be found in mesh &#039;$(MESH_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|18||[[Help:VE18|&amp;quot;Attachment point &#039;$(TAG_VAL)&#039; referenced by tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; was not found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|19||[[Help:VE19|&amp;quot;Effect &#039;$(EFFECT_NAME)&#039; in &#039;$(CONT_NAME)&#039; was not found within the mesh table.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|20||[[Help:VE20|&amp;quot;Mesh &#039;$(MESH_NAME)&#039; referenced in &#039;$(CONT_NAME)&#039; was not found within the mesh table.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|21||[[Help:VE21|&amp;quot;Attachment point &#039;$(TAG_VAL)&#039; referenced by tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; was not found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|22||[[Help:VE22|&amp;quot;Missing or invalid selection for tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|23||[[Help:VE23|&amp;quot;Invalid tag name &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|24||[[Help:VE24|&amp;quot;Invalid tag name &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|25||[[Help:VE25|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|26||[[Help:VE26|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|27||[[Help:VE27|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must have a mesh file extension.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|28||[[Help:VE28|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must have an image file extension.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|29||[[Help:VE29|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must have an animation file extension.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|30||[[Help:VE30|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; refers to a nonexistent file: &#039;$(FILENAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|31||[[Help:VE31|&amp;quot;Invalid tag name &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|32||[[Help:VE32|&amp;quot;Alias mesh requires valid parent asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|33||[[Help:VE33|&amp;quot;Alias mesh &#039;$(FILE)&#039; not found in dependency $(KUID).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|34||[[Help:VE34|&amp;quot;Alias mesh &#039;$(FILE)&#039; not found in latest version ($(NEW_KUID)) of dependency $(OLD_KUID).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|35||[[Help:VE35|&amp;quot;Required alias mesh asset $(KUID) is missing and cannot be validated.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|36||[[Help:VE36|&amp;quot;The texture &#039;$(FILE)&#039; failed to load.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|37||[[Help:VE37|&amp;quot;The texture &#039;$(FILE)&#039; is not a power of 2, please resize it.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|38||[[Help:VE38|&amp;quot;The texture &#039;$(FILE)&#039; is not square. Cubemap textures need to have the same width and height.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|39||[[Help:VE39|&amp;quot;The texture &#039;$(FILE)&#039; is a uniform color.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|40||[[Help:VE40|&amp;quot;Unable to load $(TYPE) texture &#039;$(TEXTURE)&#039; for texture file &#039;$(FILE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|41||[[Help:VE41|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Integer value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|42||[[Help:VE42|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Decimal value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|43||[[Help:VE43|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Boolean value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|44||[[Help:VE44|&amp;quot;Tag &#039;$(TAG_NAME)&#039; in the container &#039;$(CONT_NAME)&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|45||[[Help:VE45|&amp;quot;The Tag &#039;$(TAG_NAME)&#039; is not permitted within a container of type &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|46||[[Help:VE46|&amp;quot;Internal Error: The template does not specify that a smoke container is valid in the container being parsed.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|47||[[Help:VE47|&amp;quot;Container &#039;$(CONT_NAME)&#039; is not permitted in this section.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|48||[[Help:VE48|&amp;quot;This asset uses an obsolete trainz-build number. Trainz-build numbers below $(LOWEST_TRAINZBUILD) are no longer supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|49||[[Help:VE49|&amp;quot;Required tag &#039;kind&#039; is not present. Ensure this is a valid config file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|50||[[Help:VE50|&amp;quot;Unsupported kind &#039;$(KIND)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|51||[[Help:VE51|&amp;quot;Tag &#039;$(TAG_NAME)&#039; in the container &#039;$(CONT_NAME)&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|52||[[Help:VE52|&amp;quot;The Tag &#039;$(TAG_NAME)&#039; is not permitted within a container of type &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|53||[[Help:VE53|&amp;quot;This container is no longer supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|54||[[Help:VE54|&amp;quot;The Tag &#039;$(TAG_NAME)&#039; is not permitted within a container of type &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|55||[[Help:VE55|&amp;quot;This container is no longer supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|56||[[Help:VE56|&amp;quot;Container &#039;$(CONT_NAME)&#039; is not permitted in this section.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|57||[[Help:VE57|&amp;quot;Container &#039;$(CONT_NAME)&#039; is not permitted in this section.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|58||[[Help:VE58|&amp;quot;The tag &#039;$(TAG_NAME)&#039; is not a valid container type (expected &#039;$(TYPE)&#039;).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|59||[[Help:VE59|&amp;quot;Internal error: unknown dataType - kind &#039;$(KIND)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|60||[[Help:VE60|&amp;quot;Required tag &#039;$(TAG_NAME)&#039; was missing and has been set to default.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|61||[[Help:VE61|&amp;quot;Required tag &#039;$(TAG_NAME)&#039; was missing and has been set to default.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|62||[[Help:VE62|&amp;quot;Required container &#039;$(CONT_NAME)&#039; is missing.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|63||[[Help:VE63|&amp;quot;The cubemap texture &#039;$(FILE)&#039; has missing images. Please verify the texture.txt file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|64||[[Help:VE64|&amp;quot;Cubemap texture &#039;$(FILE)&#039; contains images of different sizes.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|65||[[Help:VE65|&amp;quot;The *.texture.txt file is missing for texture resource &#039;$(FILE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|66||[[Help:VE66|&amp;quot;The texture file &#039;$(FILE)&#039; contains non-ANSI characters. Textures must be ANSI.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|67||[[Help:VE67|&amp;quot;The texture &#039;$(FILE)&#039; does not seem to have a primary texture set. Please verify the texture.txt file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|68||[[Help:VE68|&amp;quot;The primary and alpha texture are not the same size for &#039;$(FILE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|69||[[Help:VE69|&amp;quot;Binary conversion failed for texture resource &#039;$(FILE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|70||[[Help:VE70|&amp;quot;The KUID tag is not a valid KUID value: &#039;$(string)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|71||[[Help:VE71|&amp;quot;Unsupported SpeedTree version for mesh: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|72||[[Help:VE72|&amp;quot;Unable to load mesh file: &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|73||[[Help:VE73|&amp;quot;Image file &#039;$(FILE)&#039; is incorrectly used as both a texture.txt source file and a raw image file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|74||[[Help:VE74|&amp;quot;Image file &#039;$(FILE)&#039; is incorrectly used as both a texture.txt source file and a raw image file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|76||[[Help:VE76|&amp;quot;Unable to load mesh file: &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|77||[[Help:VE77|&amp;quot;Unable to load indexed mesh &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|79||[[Help:VE79|&amp;quot;Unable to load animation file &#039;$(FILE)&#039; (mesh has not been loaded correctly).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|81||[[Help:VE81|&amp;quot;The high-poly mesh &#039;$(FILE)&#039; should have LOD levels.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|82||[[Help:VE82|&amp;quot;High-detail .im files are not supported for traincar assets, as they are likely to perform poorly. It is recommended that you upgrade &#039;$(FILE)&#039; to a .lm file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|83||[[Help:VE83|&amp;quot;The file &#039;$(FILE)&#039; is provided in LM format despite having no attachment points and no animation support. This may have a negative impact on performance.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|84||[[Help:VE84|&amp;quot;The file &#039;$(FILE)&#039; is provided in LM format despite containing only a single mesh. This may have a negative impact on performance.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|85||[[Help:VE85|&amp;quot;The file &#039;$(FILE)&#039; is provided in LM format, however the high-detail mesh is comprised of less than 300 polygons. This may have a negative impact on performance.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|86||[[Help:VE86|&amp;quot;Legacy .pm files are no longer supported, and will perform poorly. It is recommended that you switch to using a .lm file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|87||[[Help:VE87|&amp;quot;Legacy .pm files are no longer supported, and will perform poorly. It is recommended that you switch to using a .lm file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|88||[[Help:VE88|&amp;quot;This asset has a trainz-build number which is not recognised by this tool.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|89||[[Help:VE89|&amp;quot;Tag &#039;$(TAG_NAME)&#039; in the container &#039;$(CONT_NAME)&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|90||[[Help:VE90|&amp;quot;This asset has an invalid KUID user id&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|91||[[Help:VE91|&amp;quot;The dependency $(KUID) has an invalid KUID User ID and cannot be used&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|92||[[Help:VE92|&amp;quot;Duplicate &#039;$(TAG_NAME)&#039; containers in &#039;$(CONT_NAME)&#039;. Containers must have a unique name.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|93||[[Help:VE93|&amp;quot;Duplicate &#039;$(TAG_NAME)&#039; tags in &#039;$(CONT_NAME)&#039;. Tags must have a unique name.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|94||[[Help:VE94|&amp;quot;This asset requires a shadow mesh, but the mesh table does not contain one.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|95||[[Help:VE95|&amp;quot;This asset does not have a mesh that is visible by default.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|96||[[Help:VE96|&amp;quot;Maximum of 5 running number fonts supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|97||[[Help:VE97|&amp;quot;The running number font directory &#039;$(DIR)&#039; could not be found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|98||[[Help:VE98|&amp;quot;The running number font file &#039;$(DIR)/$(FILE)&#039; could not be found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|99||[[Help:VE99|&amp;quot;The track-sound container &#039;$(NAME)&#039; has no bogey, track or track-parent tag.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|100||[[Help:VE100|&amp;quot;Required tag &#039;$(TAG_NAME)&#039; was missing and has been set to default.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|101||[[Help:VE101|&amp;quot;The file &#039;$(FILE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|102||[[Help:VE102|&amp;quot;Failed to load sound file &#039;$(FILE)&#039;, please ensure this is a valid wav file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|103||[[Help:VE103|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|104||[[Help:VE104|&amp;quot;Multiple template property bindings for rule property &#039;$(PROP)&#039; for rule &#039;$(RULE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|105||[[Help:VE105|&amp;quot;The template property &#039;$(NAME)&#039; specified in the rule-template-bindings container of rule &#039;$(RULE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|106||[[Help:VE106|&amp;quot;The high-detail meshes in season $(SEASON) total more than $(LIMIT) polygons. This may have a negative impact on performance: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|107||[[Help:VE107|&amp;quot;The high-detail meshes total more than $(LIMIT) polygons. This may have a negative impact on performance: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|108||[[Help:VE108|&amp;quot;The low-detail meshes in season $(SEASON) total more than 500 polygons. This may have a negative impact on performance: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|109||[[Help:VE109|&amp;quot;The low-detail meshes total more than 500 polygons. This may have a negative impact on performance: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|110||[[Help:VE110|&amp;quot;The meshes in LOD level $(LOD_LEVEL) in season $(SEASON) must total at least 20% fewer polygons than the next higher LOD in the same season: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|111||[[Help:VE111|&amp;quot;The meshes in LOD level $(LOD_LEVEL) must total at least 20% fewer polygons than the next higher LOD: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|112||[[Help:VE112|&amp;quot;Multiple track stretches between &#039;$(FROM_VERTEX)&#039; and &#039;$(TO_VERTEX)&#039; in container &#039;$(CONT_NAME)&#039;. Track stretches must be unique.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|113||[[Help:VE113|&amp;quot;An image file (&#039;$(FILE)&#039;) has been supplied where a texture file (&#039;*.texture.txt&#039;) is required.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|114||[[Help:VE114|&amp;quot;An image file (&#039;$(FILE)&#039;) has been supplied where a texture file (&#039;*.texture.txt&#039;) is required.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|115||[[Help:VE115|&amp;quot;The texture file &#039;$(FILE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|116||[[Help:VE116|&amp;quot;No texture file has been specified for this texture asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|117||[[Help:VE117|&amp;quot;&#039;$(TAG_0)&#039; must be set to a &#039;$(KIND)&#039; for &#039;$(TAG_1)&#039; to be allowed.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|118||[[Help:VE118|&amp;quot;Tag &#039;$(TAG_0)&#039; requires that &#039;$(TAG_1)&#039; be set to &#039;$(KIND)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|119||[[Help:VE119|&amp;quot;The tag &#039;$(TAG_NAME)&#039; is not valid for kind &#039;$(KIND)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|120||[[Help:VE120|&amp;quot;Tag &#039;$(TAG_0)&#039;, requires the tag &#039;$(TAG_1)&#039; to be present.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|121||[[Help:VE121|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|122||[[Help:VE122|&amp;quot;&#039;$(TAG_NAME)&#039; must have a positive value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|123||[[Help:VE123|&amp;quot;The script file &#039;$(FILE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|124||[[Help:VE124|&amp;quot;The file &#039;$(FILE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|125||[[Help:VE125|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|126||[[Help:VE126|&amp;quot;&#039;$(TAG_NAME)&#039; must not be zero.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|127||[[Help:VE127|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|128||[[Help:VE128|&amp;quot;The value for &#039;$(TAG_NAME)&#039; must be between &#039;$(MIN)&#039; and &#039;$(MAX)&#039; but was specified as &#039;$(VALUE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|129||[[Help:VE129|&amp;quot;Incorrect number of values for the tag &#039;$(TAG_NAME)&#039;, expected $(NUM_0) values, found $(NUM_1).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|130||[[Help:VE130|&amp;quot;Too many values for the tag &#039;$(TAG_NAME)&#039;, maximum is $(MAX) values, found $(FOUND).&amp;quot;]]]]&lt;br /&gt;
|-&lt;br /&gt;
|131||[[Help:VE131|&amp;quot;Value must be a mesh from the mesh-table (not a parent container).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|132||[[Help:VE132|&amp;quot;The attachment point &#039;$(ATT)&#039; must belong to the parent mesh of the effect (mesh=$(MESH)).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|133||[[Help:VE133|&amp;quot;A light container must be present to link the signals.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|134||[[Help:VE134|&amp;quot;&#039;$(NUM)&#039; must be a valid light number from the light container.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|135||[[Help:VE135|&amp;quot;&#039;$(TAG_0)&#039; requires that the tag &#039;$(TAG_1)&#039; be present.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|136||[[Help:VE136|&amp;quot;&#039;$(TAG_0)&#039; requires that the tag &#039;$(TAG_1)&#039; be present.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|137||[[Help:VE137|&amp;quot;Empty or invalid running number specified at character index $(INDEX)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|138||[[Help:VE138|&amp;quot;Running number specified at character index $(INDEX) is too large, must be less than 9 characters.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|139||[[Help:VE139|&amp;quot;Invalid running number range specified at character index $(INDEX), ($(FROM)-$(TO)).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|140||[[Help:VE140|&amp;quot;Running number range &#039;$(FROM)-$(TO)&#039; specified at character index $(INDEX) overlaps already in use numbers, running numbers must be unique.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|141||[[Help:VE141|&amp;quot;Running number &#039;$(NUMBER)&#039; specified at character index $(INDEX) is already in use.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|142||[[Help:VE142|&amp;quot;Invalid character &#039;$(CHAR)&#039; specified in running number list, only numbers, &#039;,&#039; and &#039;-&#039; are supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|143||[[Help:VE143|&amp;quot;Possible running number list is too large, the set must contain less than 20000 possibilities.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|144||[[Help:VE144|&amp;quot;Category code &#039;ZX - Paintshed template&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|145||[[Help:VE145|&amp;quot;Category code &#039;ZX - Paintshed template&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|146||[[Help:VE146|&amp;quot;An asset must be specified for tag &#039;$(TAG_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|147||[[Help:VE147|&amp;quot;The tag(s) $(MISPLACED_TAGS) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|148||[[Help:VE148|&amp;quot;The tag(s) $(MISPLACED_TAGS) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|149||[[Help:VE149|&amp;quot;The mesh(es) $(MISPLACED_MESHES) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|150||[[Help:VE150|&amp;quot;The mesh(es) $(MISPLACED_MESHES) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|151||[[Help:VE150|&amp;quot;The mesh(es) $(MISPLACED_MESHES) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|152||[[Help:VE152|&amp;quot;The tags $(MISSING_TAGS) are not all defined. The default values will be used and the positions of the elements may not fit your track.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|153||[[Help:VE153|&amp;quot;The mesh $(MESH) is present but the tag $(MISSING_TAG) is not defined.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|154||[[Help:VE154|&amp;quot;The mesh $(MESH) is present but the tag $(MISSING_TAG) is not defined.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|155||[[Help:VE155|&amp;quot;The mesh $(MESH) is present but the tags $(MISSING_TAGS) are not all defined.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|156||[[Help:VE156|&amp;quot;The tag $(MISSING_TAG) is not defined. The default value will be used and the positions of the elements may not fit your track.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|157||[[Help:VE157|&amp;quot;The mesh $(MESH) is present but the tag $(MISSING_TAG) is missing. The default value will be used and the positions of the elements may not fit your track.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|158||[[Help:VE158|&amp;quot;Unable to open .lm.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|159||[[Help:VE159|&amp;quot;Unable to parse .lm.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|160||[[Help:VE160|&amp;quot;No &#039;mesh&#039; keys found in .lm.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|161||[[Help:VE161|&amp;quot;$(LODCOUNT) LODs in .lm.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|162||[[Help:VE162|&amp;quot;One of the LOD reductions of &#039;$(FILE)&#039; introduces a new attachment point: $(ATT)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|163||[[Help:VE163|&amp;quot;Unable to parse .im file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|164||[[Help:VE164|&amp;quot;Invalid position data in .im file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|165||[[Help:VE165|&amp;quot;Texture &#039;$(TEXTURE)&#039; is missing or could not be loaded in mesh &#039;$(FILE)&#039;, material &#039;$(MATERIAL)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|166||[[Help:VE166|&amp;quot;$(COMBINEDCOUNT) combined chunks (of $(SOURCECOUNT) source) in .im file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|167||[[Help:VE167|&amp;quot;Source image texture file &#039;$(TEXTUREFILE)&#039; is too large for &#039;$(ASSETFILE)&#039; ($(WIDTH)x$(HEIGHT))&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|168||[[Help:VE168|&amp;quot;File &#039;$(TEXTUREFILE)&#039; is not a valid compiled texture file for &#039;$(ASSETFILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|169||[[Help:VE169|&amp;quot;Compiled texture file &#039;$(TEXTUREFILE)&#039; is unsupported version for &#039;$(ASSETFILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|170||[[Help:VE170|&amp;quot;Failed to open compiled texture &#039;$(TEXTUREFILE)&#039; for &#039;$(ASSETFILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|171||[[Help:VE171|&amp;quot;Expected texture file type but found &#039;$(TEXTUREFILE)&#039; for &#039;$(ASSETFILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|172||[[Help:VE172|&amp;quot;Script class does not match asset kind ($(KIND)).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|173||[[Help:VE173|&amp;quot;Material &#039;$(MATERIAL)&#039; in mesh &#039;$(FILE)&#039; is not of a recognised material type.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|174||[[Help:VE174|&amp;quot;MeshObjectSpec::LinkSpecs&amp;gt; Mesh-table element #$(MESH_INDEX) parent mesh is invalid.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|175||[[Help:VE175|&amp;quot;MeshObjectSpec::LinkSpecs&amp;gt; Mesh-table element #$(MESH_INDEX) is part of invalid hierarchy.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|176||[[Help:VE176|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must have a texture file extension.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|177||[[Help:VE177|&amp;quot;The kuid &#039;$(KUID)&#039; is not in the database, and could not be found in any known location. Ensure that this is a valid asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|178||[[Help:VE178|&amp;quot;The asset specified in &#039;$(KUID)&#039; is not installed locally but is available for download.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|179||[[Help:VE179|&amp;quot;The kuid &#039;$(KUID)&#039; specified in &#039;$(TAG_NAME)&#039; is not of the correct type.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|180||[[Help:VE180|&amp;quot;Integrity check failure on $(FILE). One or more route/session tiles may be missing.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|181||[[Help:VE181|&amp;quot;The tag &#039;$(TAG_NAME)&#039; requires a minimum asset version of $(MIN_VERSION)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|182||[[Help:VE182|&amp;quot;Material &#039;$(MATERIAL)&#039; in mesh &#039;$(FILE)&#039; is missing a texture for a mandatory texture slot.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|183||[[Help:VE183|&amp;quot;FBX file is in an unsupported older format.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|184||[[Help:VE184|&amp;quot;KIND &#039;$(KIND)&#039; requires trainz-build $(TRAINZBUILD).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|185||[[Help:VE185|&amp;quot;Material &#039;$(MATERIAL)&#039; in mesh &#039;$(FILE)&#039; has heightmap texture. Provide a normal map instead.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|186||[[Help:VE186|&amp;quot;Material &#039;$(MATERIAL)&#039; is shared between multiple chunks in this asset but the material parameters conflict.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|187||[[Help:VE187|&amp;quot;The value &#039;$(VALUE)&#039; in not a valid KUID.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|188||[[Help:VE188|&amp;quot;Custom render plugin failed to load mesh &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|189||[[Help:VE189|&amp;quot;Collision data exceeds $(LIMIT)KB. Please specify a different generation method or a simplified mesh.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|190||[[Help:VE190|&amp;quot;Tag &#039;$(NAME)&#039; is unable to be converted from $(TYPE1) to $(TYPE2)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|191||[[Help:VE191|&amp;quot;Tag &#039;$(NAME)&#039; does not contain a valid integer: $(VALUE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|192||[[Help:VE192|&amp;quot;Tag &#039;$(NAME)&#039; does not contain a valid float list: $(VALUE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|193||[[Help:VE193|&amp;quot;Tag &#039;$(NAME)&#039; does not contain a valid float&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|194||[[Help:VE194|&amp;quot;Tag &#039;$(NAME)&#039; does not contain a valid kuid: $(VALUE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|195||[[Help:VE195|&amp;quot;Unable to parse chunk $(CHUNK_INDEX) in mesh file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|196||[[Help:VE196|&amp;quot;Failed to load bogey $(KUID)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|197||[[Help:VE197|&amp;quot;Syntax error in script &#039;$(SCRIPT)&#039; for asset $(ASSET)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|198||[[Help:VE198|&amp;quot;Session failed to load route asset: $(KUID)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|199||[[Help:VE199|&amp;quot;Asset $(KUID) failed to load. Unloading resources.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|200||[[Help:VE200|&amp;quot;Unable to load mesh $(NAME) for $(ASSET_ID)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|201||[[Help:VE201|&amp;quot;Traincar is missing required attachment point: $(ATT_NAME)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|202||[[Help:VE202|&amp;quot;Parse error reading twinkles file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|203||[[Help:VE203|&amp;quot;Bad sequence order in $(TAG_NAME) list. Each element must be greater than the last.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|204||[[Help:VE204|&amp;quot;Invalid range in $(TAG_NAME) list. Elements must be greater than or equal to $(INC_MIN) and less than $(EXC_MAX).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|205||[[Help:VE205|&amp;quot;Invalid element count in $(TAG_NAME) list. This list must have at least $(COUNT) elements (to match the $(TAG_START) list).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|206||[[Help:VE206|&amp;quot;The season-selector references season &#039;$(SEASON)&#039;, but this does not exist in the texture-variants container.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|207||[[Help:VE207|&amp;quot;Attached track asset $(CHILD) failed to load.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|208||[[Help:VE208|&amp;quot;Attached track asset not specified for track $(INDEX).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|209||[[Help:VE209|&amp;quot;Asset is missing the required &#039;attached-track&#039; container.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|210||[[Help:VE210|&amp;quot;Asset is missing the required &#039;track&#039; tag.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|211||[[Help:VE211|&amp;quot;Asset is missing the required &#039;road&#039; tag.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|212||[[Help:VE212|&amp;quot;Traincar asset must have at least two bogeys.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|213||[[Help:VE213|&amp;quot;Traincar asset has invalid bogey placement.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|214||[[Help:VE214|&amp;quot;Traincar asset has invalid length.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|215||[[Help:VE215|&amp;quot;Asset has an invalid number of LODs: $(LOD_COUNT)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|216||[[Help:VE216|&amp;quot;Material $(MATERIAL) in mesh file $(MESH) has an inappropriate texture slot assigned: $(TEXTURE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|217||[[Help:VE217|&amp;quot;Material $(MATERIAL) in mesh file $(MESH) has no texture assigned to a required slot: $(TEXTURE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|218||[[Help:VE218|&amp;quot;Asset has duplicate attached track at track $(INDEX).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|225||[[Help:VE225|&amp;quot;Failed to query asset details for featured asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|226||[[Help:VE226|&amp;quot;Failed to upload asset details for featured asset: $(ERRORTEXT)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|227||[[Help:VE227|&amp;quot;Missing image for featured asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|228||[[Help:VE228|&amp;quot;Failed to read image file for featured asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|229||[[Help:VE229|&amp;quot;DLC marketing image is missing or incorrectly sized for featured asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|230||[[Help:VE230|&amp;quot;DLS thumbnail image is missing or incorrectly sized for featured asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|231||[[Help:VE231|&amp;quot;Failed to open image file for featured asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|232||[[Help:VE232|&amp;quot;Failed to upload image for featured asset: $(ERRORTEXT)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|233||[[Help:VE233|&amp;quot;One or more featured assets was not provided.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|234||[[Help:VE234|&amp;quot;Asset is not present in the featured assets list.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|235||[[Help:VE235|&amp;quot;Featured asset is not present in the input.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|236||[[Help:VE236|&amp;quot;Featured asset was not available.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|237||[[Help:VE237|&amp;quot;Featured asset failed validation.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|238||[[Help:VE238|&amp;quot;Featured asset has faulty or missing dependencies.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|239||[[Help:VE239|&amp;quot;Featured asset is Base content.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|240||[[Help:VE240|&amp;quot;Featured asset is missing an English name or description.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|241||[[Help:VE241|&amp;quot;Newly built package is not compatible with previously released version.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|242||[[Help:VE242|&amp;quot;Unable to load animation file &#039;$(FILE)&#039; (file not found, or is damaged).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|243||[[Help:VE243|&amp;quot;Failed to submit changes to asset $(ASSET_KUID) due to file access error&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|244||[[Help:VE244|&amp;quot;Files in base assets cannot use importers: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|245||[[Help:VE245|&amp;quot;Missing compiled texture: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|246||[[Help:VE246|&amp;quot;Missing source texture: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|247||[[Help:VE247|&amp;quot;Creating default texture.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|248||[[Help:VE248|&amp;quot;Failed to create *.texture.txt file for source image: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|249||[[Help:VE249|&amp;quot;Failed to compile *.texture.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|250||[[Help:VE250|&amp;quot;Material Metadata expected data for texture slot &#039;$(SLOT)&#039; of material &#039;$(MATERIAL)&#039; but none found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|251||[[Help:VE251|&amp;quot;Material Metadata expected *.texture resource for texture slot &#039;$(SLOT)&#039; of material &#039;$(MATERIAL)&#039; bout found: $(FOUND)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|252||[[Help:VE252|&amp;quot;Mesh material expected data for texture slot &#039;$(SLOT)&#039; of material &#039;$(MATERIAL)&#039; but none found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|253||[[Help:VE253|&amp;quot;WriteAnimationFileBoneChunk&amp;gt; excessive bone-chunk count.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|254||[[Help:VE254|&amp;quot;Unable to open mesh metadata file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|255||[[Help:VE255|&amp;quot;Mesh contains unsupported non-triangle primitives.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|256||[[Help:VE256|&amp;quot;Mesh contains invalid material index.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|257||[[Help:VE257|&amp;quot;Mesh contains no primitives.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|258||[[Help:VE258|&amp;quot;Unable to determine vertex format.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|259||[[Help:VE259|&amp;quot;Unsupported number of texture channels.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|260||[[Help:VE260|&amp;quot;Invalid index in primitive.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|261||[[Help:VE261|&amp;quot;Unable to create animation file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|262||[[Help:VE262|&amp;quot;Unable to open animation event file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|263||[[Help:VE263|&amp;quot;Unable to parse animation event file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|264||[[Help:VE264|&amp;quot;Parsed animation event file $(FILE) with $(COUNT) events.&amp;quot;]]&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=Category:Validation_Errors&amp;diff=23705</id>
		<title>Category:Validation Errors</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=Category:Validation_Errors&amp;diff=23705"/>
		<updated>2020-06-11T03:56:05Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Validation Error (VE) numbers are logged during content validation, to allow users to look up particular validation messages to better understand the source of the problem. Normal logs provide a substantial amount of technical detail about the error, but typically assume that the reader is familiar with the subject matter and will understand why the log is relevant. This wiki provides the necessary background information to understanding many of the logs, however a user who is unfamiliar with the area in question may not know where to start looking. VE numbers allow users to quickly find relevant pages in the wiki without any prior knowledge of the subject.&lt;br /&gt;
&lt;br /&gt;
This page serves as a master guide to all VE numbers currently logged by Trainz. This page does not provide detailed information on any given VE number- please refer to the individual VE number pages for specific details. The error text here is correct for the English localisation of Trainz at the time of writing, however the exact text may change from time to time. It is intended that the overall meaning of a VE number will never change- new VE numbers will be issued instead, and old VE numbers may be made obsolete.&lt;br /&gt;
&lt;br /&gt;
Logs which lack VE numbers do not belong on this page.&lt;br /&gt;
&lt;br /&gt;
The individual VE pages can be found at the links below, or can be accessed directly from [[Content Manager]] by right-clicking on the Validation Error in the results log, and selecting &amp;quot;View Help for This Message&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|1||[[Help:VE1|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Decimal value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|2||[[Help:VE2|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Integer value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|3||[[Help:VE3|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|4||[[Help:VE4|&amp;quot;&#039;$(TAG_NAME)&#039; must have a positive value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|5||[[Help:VE5|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|6||[[Help:VE6|&amp;quot;&#039;$(TAG_NAME)&#039; must not be zero.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|7||[[Help:VE7|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|8||[[Help:VE8|&amp;quot;The value for &#039;$(TAG_NAME)&#039; must be between &#039;$(MIN)&#039; and &#039;$(MAX)&#039; but was specified as &#039;$(VALUE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|9||[[Help:VE9|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|10||[[Help:VE10|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|11||[[Help:VE11|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|12||[[Help:VE12|&amp;quot;No string-table entry found with tag &#039;$(VALUE)&#039; for for string-token tag &#039;$(TAG)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|13||[[Help:VE13|&amp;quot;Missing or invalid selection for tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|14||[[Help:VE14|&amp;quot;Missing or invalid selection for tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|15||[[Help:VE15|&amp;quot;Attachment point &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must be found in mesh &#039;$(MESH_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|16||[[Help:VE16|&amp;quot;Container &#039;$(CONT_NAME)&#039; does not have an &#039;att-parent&#039; tag which is required to reference an attachment point.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|17||[[Help:VE17|&amp;quot;Attachment point &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must be found in mesh &#039;$(MESH_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|18||[[Help:VE18|&amp;quot;Attachment point &#039;$(TAG_VAL)&#039; referenced by tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; was not found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|19||[[Help:VE19|&amp;quot;Effect &#039;$(EFFECT_NAME)&#039; in &#039;$(CONT_NAME)&#039; was not found within the mesh table.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|20||[[Help:VE20|&amp;quot;Mesh &#039;$(MESH_NAME)&#039; referenced in &#039;$(CONT_NAME)&#039; was not found within the mesh table.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|21||[[Help:VE21|&amp;quot;Attachment point &#039;$(TAG_VAL)&#039; referenced by tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; was not found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|22||[[Help:VE22|&amp;quot;Missing or invalid selection for tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|23||[[Help:VE23|&amp;quot;Invalid tag name &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|24||[[Help:VE24|&amp;quot;Invalid tag name &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|25||[[Help:VE25|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|26||[[Help:VE26|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|27||[[Help:VE27|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must have a mesh file extension.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|28||[[Help:VE28|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must have an image file extension.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|29||[[Help:VE29|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must have an animation file extension.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|30||[[Help:VE30|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; refers to a nonexistent file: &#039;$(FILENAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|31||[[Help:VE31|&amp;quot;Invalid tag name &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|32||[[Help:VE32|&amp;quot;Alias mesh requires valid parent asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|33||[[Help:VE33|&amp;quot;Alias mesh &#039;$(FILE)&#039; not found in dependency $(KUID).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|34||[[Help:VE34|&amp;quot;Alias mesh &#039;$(FILE)&#039; not found in latest version ($(NEW_KUID)) of dependency $(OLD_KUID).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|35||[[Help:VE35|&amp;quot;Required alias mesh asset $(KUID) is missing and cannot be validated.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|36||[[Help:VE36|&amp;quot;The texture &#039;$(FILE)&#039; failed to load.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|37||[[Help:VE37|&amp;quot;The texture &#039;$(FILE)&#039; is not a power of 2, please resize it.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|38||[[Help:VE38|&amp;quot;The texture &#039;$(FILE)&#039; is not square. Cubemap textures need to have the same width and height.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|39||[[Help:VE39|&amp;quot;The texture &#039;$(FILE)&#039; is a uniform color.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|40||[[Help:VE40|&amp;quot;Unable to load $(TYPE) texture &#039;$(TEXTURE)&#039; for texture file &#039;$(FILE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|41||[[Help:VE41|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Integer value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|42||[[Help:VE42|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Decimal value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|43||[[Help:VE43|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Boolean value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|44||[[Help:VE44|&amp;quot;Tag &#039;$(TAG_NAME)&#039; in the container &#039;$(CONT_NAME)&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|45||[[Help:VE45|&amp;quot;The Tag &#039;$(TAG_NAME)&#039; is not permitted within a container of type &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|46||[[Help:VE46|&amp;quot;Internal Error: The template does not specify that a smoke container is valid in the container being parsed.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|47||[[Help:VE47|&amp;quot;Container &#039;$(CONT_NAME)&#039; is not permitted in this section.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|48||[[Help:VE48|&amp;quot;This asset uses an obsolete trainz-build number. Trainz-build numbers below $(LOWEST_TRAINZBUILD) are no longer supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|49||[[Help:VE49|&amp;quot;Required tag &#039;kind&#039; is not present. Ensure this is a valid config file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|50||[[Help:VE50|&amp;quot;Unsupported kind &#039;$(KIND)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|51||[[Help:VE51|&amp;quot;Tag &#039;$(TAG_NAME)&#039; in the container &#039;$(CONT_NAME)&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|52||[[Help:VE52|&amp;quot;The Tag &#039;$(TAG_NAME)&#039; is not permitted within a container of type &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|53||[[Help:VE53|&amp;quot;This container is no longer supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|54||[[Help:VE54|&amp;quot;The Tag &#039;$(TAG_NAME)&#039; is not permitted within a container of type &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|55||[[Help:VE55|&amp;quot;This container is no longer supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|56||[[Help:VE56|&amp;quot;Container &#039;$(CONT_NAME)&#039; is not permitted in this section.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|57||[[Help:VE57|&amp;quot;Container &#039;$(CONT_NAME)&#039; is not permitted in this section.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|58||[[Help:VE58|&amp;quot;The tag &#039;$(TAG_NAME)&#039; is not a valid container type (expected &#039;$(TYPE)&#039;).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|59||[[Help:VE59|&amp;quot;Internal error: unknown dataType - kind &#039;$(KIND)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|60||[[Help:VE60|&amp;quot;Required tag &#039;$(TAG_NAME)&#039; was missing and has been set to default.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|61||[[Help:VE61|&amp;quot;Required tag &#039;$(TAG_NAME)&#039; was missing and has been set to default.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|62||[[Help:VE62|&amp;quot;Required container &#039;$(CONT_NAME)&#039; is missing.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|63||[[Help:VE63|&amp;quot;The cubemap texture &#039;$(FILE)&#039; has missing images. Please verify the texture.txt file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|64||[[Help:VE64|&amp;quot;Cubemap texture &#039;$(FILE)&#039; contains images of different sizes.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|65||[[Help:VE65|&amp;quot;The *.texture.txt file is missing for texture resource &#039;$(FILE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|66||[[Help:VE66|&amp;quot;The texture file &#039;$(FILE)&#039; contains non-ANSI characters. Textures must be ANSI.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|67||[[Help:VE67|&amp;quot;The texture &#039;$(FILE)&#039; does not seem to have a primary texture set. Please verify the texture.txt file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|68||[[Help:VE68|&amp;quot;The primary and alpha texture are not the same size for &#039;$(FILE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|69||[[Help:VE69|&amp;quot;Binary conversion failed for texture resource &#039;$(FILE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|70||[[Help:VE70|&amp;quot;The KUID tag is not a valid KUID value: &#039;$(string)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|71||[[Help:VE71|&amp;quot;Unsupported SpeedTree version for mesh: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|72||[[Help:VE72|&amp;quot;Unable to load mesh file: &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|73||[[Help:VE73|&amp;quot;Image file &#039;$(FILE)&#039; is incorrectly used as both a texture.txt source file and a raw image file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|74||[[Help:VE74|&amp;quot;Image file &#039;$(FILE)&#039; is incorrectly used as both a texture.txt source file and a raw image file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|76||[[Help:VE76|&amp;quot;Unable to load mesh file: &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|77||[[Help:VE77|&amp;quot;Unable to load indexed mesh &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|79||[[Help:VE79|&amp;quot;Unable to load animation file &#039;$(FILE)&#039; (mesh has not been loaded correctly).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|81||[[Help:VE81|&amp;quot;The high-poly mesh &#039;$(FILE)&#039; should have LOD levels.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|82||[[Help:VE82|&amp;quot;High-detail .im files are not supported for traincar assets, as they are likely to perform poorly. It is recommended that you upgrade &#039;$(FILE)&#039; to a .lm file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|83||[[Help:VE83|&amp;quot;The file &#039;$(FILE)&#039; is provided in LM format despite having no attachment points and no animation support. This may have a negative impact on performance.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|84||[[Help:VE84|&amp;quot;The file &#039;$(FILE)&#039; is provided in LM format despite containing only a single mesh. This may have a negative impact on performance.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|85||[[Help:VE85|&amp;quot;The file &#039;$(FILE)&#039; is provided in LM format, however the high-detail mesh is comprised of less than 300 polygons. This may have a negative impact on performance.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|86||[[Help:VE86|&amp;quot;Legacy .pm files are no longer supported, and will perform poorly. It is recommended that you switch to using a .lm file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|87||[[Help:VE87|&amp;quot;Legacy .pm files are no longer supported, and will perform poorly. It is recommended that you switch to using a .lm file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|88||[[Help:VE88|&amp;quot;This asset has a trainz-build number which is not recognised by this tool.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|89||[[Help:VE89|&amp;quot;Tag &#039;$(TAG_NAME)&#039; in the container &#039;$(CONT_NAME)&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|90||[[Help:VE90|&amp;quot;This asset has an invalid KUID user id&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|91||[[Help:VE91|&amp;quot;The dependency $(KUID) has an invalid KUID User ID and cannot be used&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|92||[[Help:VE92|&amp;quot;Duplicate &#039;$(TAG_NAME)&#039; containers in &#039;$(CONT_NAME)&#039;. Containers must have a unique name.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|93||[[Help:VE93|&amp;quot;Duplicate &#039;$(TAG_NAME)&#039; tags in &#039;$(CONT_NAME)&#039;. Tags must have a unique name.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|94||[[Help:VE94|&amp;quot;This asset requires a shadow mesh, but the mesh table does not contain one.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|95||[[Help:VE95|&amp;quot;This asset does not have a mesh that is visible by default.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|96||[[Help:VE96|&amp;quot;Maximum of 5 running number fonts supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|97||[[Help:VE97|&amp;quot;The running number font directory &#039;$(DIR)&#039; could not be found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|98||[[Help:VE98|&amp;quot;The running number font file &#039;$(DIR)/$(FILE)&#039; could not be found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|99||[[Help:VE99|&amp;quot;The track-sound container &#039;$(NAME)&#039; has no bogey, track or track-parent tag.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|100||[[Help:VE100|&amp;quot;Required tag &#039;$(TAG_NAME)&#039; was missing and has been set to default.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|101||[[Help:VE101|&amp;quot;The file &#039;$(FILE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|102||[[Help:VE102|&amp;quot;Failed to load sound file &#039;$(FILE)&#039;, please ensure this is a valid wav file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|103||[[Help:VE103|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|104||[[Help:VE104|&amp;quot;Multiple template property bindings for rule property &#039;$(PROP)&#039; for rule &#039;$(RULE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|105||[[Help:VE105|&amp;quot;The template property &#039;$(NAME)&#039; specified in the rule-template-bindings container of rule &#039;$(RULE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|106||[[Help:VE106|&amp;quot;The high-detail meshes in season $(SEASON) total more than $(LIMIT) polygons. This may have a negative impact on performance: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|107||[[Help:VE107|&amp;quot;The high-detail meshes total more than $(LIMIT) polygons. This may have a negative impact on performance: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|108||[[Help:VE108|&amp;quot;The low-detail meshes in season $(SEASON) total more than 500 polygons. This may have a negative impact on performance: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|109||[[Help:VE109|&amp;quot;The low-detail meshes total more than 500 polygons. This may have a negative impact on performance: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|110||[[Help:VE110|&amp;quot;The meshes in LOD level $(LOD_LEVEL) in season $(SEASON) must total at least 20% fewer polygons than the next higher LOD in the same season: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|111||[[Help:VE111|&amp;quot;The meshes in LOD level $(LOD_LEVEL) must total at least 20% fewer polygons than the next higher LOD: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|112||[[Help:VE112|&amp;quot;Multiple track stretches between &#039;$(FROM_VERTEX)&#039; and &#039;$(TO_VERTEX)&#039; in container &#039;$(CONT_NAME)&#039;. Track stretches must be unique.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|113||[[Help:VE113|&amp;quot;An image file (&#039;$(FILE)&#039;) has been supplied where a texture file (&#039;*.texture.txt&#039;) is required.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|114||[[Help:VE114|&amp;quot;An image file (&#039;$(FILE)&#039;) has been supplied where a texture file (&#039;*.texture.txt&#039;) is required.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|115||[[Help:VE115|&amp;quot;The texture file &#039;$(FILE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|116||[[Help:VE116|&amp;quot;No texture file has been specified for this texture asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|117||[[Help:VE117|&amp;quot;&#039;$(TAG_0)&#039; must be set to a &#039;$(KIND)&#039; for &#039;$(TAG_1)&#039; to be allowed.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|118||[[Help:VE118|&amp;quot;Tag &#039;$(TAG_0)&#039; requires that &#039;$(TAG_1)&#039; be set to &#039;$(KIND)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|119||[[Help:VE119|&amp;quot;The tag &#039;$(TAG_NAME)&#039; is not valid for kind &#039;$(KIND)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|120||[[Help:VE120|&amp;quot;Tag &#039;$(TAG_0)&#039;, requires the tag &#039;$(TAG_1)&#039; to be present.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|121||[[Help:VE121|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|122||[[Help:VE122|&amp;quot;&#039;$(TAG_NAME)&#039; must have a positive value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|123||[[Help:VE123|&amp;quot;The script file &#039;$(FILE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|124||[[Help:VE124|&amp;quot;The file &#039;$(FILE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|125||[[Help:VE125|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|126||[[Help:VE126|&amp;quot;&#039;$(TAG_NAME)&#039; must not be zero.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|127||[[Help:VE127|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|128||[[Help:VE128|&amp;quot;The value for &#039;$(TAG_NAME)&#039; must be between &#039;$(MIN)&#039; and &#039;$(MAX)&#039; but was specified as &#039;$(VALUE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|129||[[Help:VE129|&amp;quot;Incorrect number of values for the tag &#039;$(TAG_NAME)&#039;, expected $(NUM_0) values, found $(NUM_1).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|130||[[Help:VE130|&amp;quot;Too many values for the tag &#039;$(TAG_NAME)&#039;, maximum is $(MAX) values, found $(FOUND).&amp;quot;]]]]&lt;br /&gt;
|-&lt;br /&gt;
|131||[[Help:VE131|&amp;quot;Value must be a mesh from the mesh-table (not a parent container).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|132||[[Help:VE132|&amp;quot;The attachment point &#039;$(ATT)&#039; must belong to the parent mesh of the effect (mesh=$(MESH)).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|133||[[Help:VE133|&amp;quot;A light container must be present to link the signals.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|134||[[Help:VE134|&amp;quot;&#039;$(NUM)&#039; must be a valid light number from the light container.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|135||[[Help:VE135|&amp;quot;&#039;$(TAG_0)&#039; requires that the tag &#039;$(TAG_1)&#039; be present.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|136||[[Help:VE136|&amp;quot;&#039;$(TAG_0)&#039; requires that the tag &#039;$(TAG_1)&#039; be present.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|137||[[Help:VE137|&amp;quot;Empty or invalid running number specified at character index $(INDEX)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|138||[[Help:VE138|&amp;quot;Running number specified at character index $(INDEX) is too large, must be less than 9 characters.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|139||[[Help:VE139|&amp;quot;Invalid running number range specified at character index $(INDEX), ($(FROM)-$(TO)).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|140||[[Help:VE140|&amp;quot;Running number range &#039;$(FROM)-$(TO)&#039; specified at character index $(INDEX) overlaps already in use numbers, running numbers must be unique.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|141||[[Help:VE141|&amp;quot;Running number &#039;$(NUMBER)&#039; specified at character index $(INDEX) is already in use.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|142||[[Help:VE142|&amp;quot;Invalid character &#039;$(CHAR)&#039; specified in running number list, only numbers, &#039;,&#039; and &#039;-&#039; are supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|143||[[Help:VE143|&amp;quot;Possible running number list is too large, the set must contain less than 20000 possibilities.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|144||[[Help:VE144|&amp;quot;Category code &#039;ZX - Paintshed template&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|145||[[Help:VE145|&amp;quot;Category code &#039;ZX - Paintshed template&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|146||[[Help:VE146|&amp;quot;An asset must be specified for tag &#039;$(TAG_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|147||[[Help:VE147|&amp;quot;The tag(s) $(MISPLACED_TAGS) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|148||[[Help:VE148|&amp;quot;The tag(s) $(MISPLACED_TAGS) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|149||[[Help:VE149|&amp;quot;The mesh(es) $(MISPLACED_MESHES) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|150||[[Help:VE150|&amp;quot;The mesh(es) $(MISPLACED_MESHES) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|151||[[Help:VE150|&amp;quot;The mesh(es) $(MISPLACED_MESHES) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|152||[[Help:VE152|&amp;quot;The tags $(MISSING_TAGS) are not all defined. The default values will be used and the positions of the elements may not fit your track.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|153||[[Help:VE153|&amp;quot;The mesh $(MESH) is present but the tag $(MISSING_TAG) is not defined.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|154||[[Help:VE154|&amp;quot;The mesh $(MESH) is present but the tag $(MISSING_TAG) is not defined.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|155||[[Help:VE155|&amp;quot;The mesh $(MESH) is present but the tags $(MISSING_TAGS) are not all defined.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|156||[[Help:VE156|&amp;quot;The tag $(MISSING_TAG) is not defined. The default value will be used and the positions of the elements may not fit your track.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|157||[[Help:VE157|&amp;quot;The mesh $(MESH) is present but the tag $(MISSING_TAG) is missing. The default value will be used and the positions of the elements may not fit your track.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|158||[[Help:VE158|&amp;quot;Unable to open .lm.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|159||[[Help:VE159|&amp;quot;Unable to parse .lm.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|160||[[Help:VE160|&amp;quot;No &#039;mesh&#039; keys found in .lm.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|161||[[Help:VE161|&amp;quot;$(LODCOUNT) LODs in .lm.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|162||[[Help:VE162|&amp;quot;One of the LOD reductions of &#039;$(FILE)&#039; introduces a new attachment point: $(ATT)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|163||[[Help:VE163|&amp;quot;Unable to parse .im file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|164||[[Help:VE164|&amp;quot;Invalid position data in .im file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|165||[[Help:VE165|&amp;quot;Texture &#039;$(TEXTURE)&#039; is missing or could not be loaded in mesh &#039;$(FILE)&#039;, material &#039;$(MATERIAL)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|166||[[Help:VE166|&amp;quot;$(COMBINEDCOUNT) combined chunks (of $(SOURCECOUNT) source) in .im file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|167||[[Help:VE167|&amp;quot;Source image texture file &#039;$(TEXTUREFILE)&#039; is too large for &#039;$(ASSETFILE)&#039; ($(WIDTH)x$(HEIGHT))&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|168||[[Help:VE168|&amp;quot;File &#039;$(TEXTUREFILE)&#039; is not a valid compiled texture file for &#039;$(ASSETFILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|169||[[Help:VE169|&amp;quot;Compiled texture file &#039;$(TEXTUREFILE)&#039; is unsupported version for &#039;$(ASSETFILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|170||[[Help:VE170|&amp;quot;Failed to open compiled texture &#039;$(TEXTUREFILE)&#039; for &#039;$(ASSETFILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|171||[[Help:VE171|&amp;quot;Expected texture file type but found &#039;$(TEXTUREFILE)&#039; for &#039;$(ASSETFILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|172||[[Help:VE172|&amp;quot;Script class does not match asset kind ($(KIND)).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|173||[[Help:VE173|&amp;quot;Material &#039;$(MATERIAL)&#039; in mesh &#039;$(FILE)&#039; is not of a recognised material type.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|174||[[Help:VE174|&amp;quot;MeshObjectSpec::LinkSpecs&amp;gt; Mesh-table element #$(MESH_INDEX) parent mesh is invalid.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|175||[[Help:VE175|&amp;quot;MeshObjectSpec::LinkSpecs&amp;gt; Mesh-table element #$(MESH_INDEX) is part of invalid hierarchy.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|176||[[Help:VE176|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must have a texture file extension.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|177||[[Help:VE177|&amp;quot;The kuid &#039;$(KUID)&#039; is not in the database, and could not be found in any known location. Ensure that this is a valid asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|178||[[Help:VE178|&amp;quot;The asset specified in &#039;$(KUID)&#039; is not installed locally but is available for download.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|179||[[Help:VE179|&amp;quot;The kuid &#039;$(KUID)&#039; specified in &#039;$(TAG_NAME)&#039; is not of the correct type.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|180||[[Help:VE180|&amp;quot;Integrity check failure on $(FILE). One or more route/session tiles may be missing.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|181||[[Help:VE181|&amp;quot;The tag &#039;$(TAG_NAME)&#039; requires a minimum asset version of $(MIN_VERSION)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|182||[[Help:VE182|&amp;quot;Material &#039;$(MATERIAL)&#039; in mesh &#039;$(FILE)&#039; is missing a texture for a mandatory texture slot.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|183||[[Help:VE183|&amp;quot;FBX file is in an unsupported older format.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|184||[[Help:VE184|&amp;quot;KIND &#039;$(KIND)&#039; requires trainz-build $(TRAINZBUILD).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|185||[[Help:VE185|&amp;quot;Material &#039;$(MATERIAL)&#039; in mesh &#039;$(FILE)&#039; has heightmap texture. Provide a normal map instead.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|186||[[Help:VE186|&amp;quot;Material &#039;$(MATERIAL)&#039; is shared between multiple chunks in this asset but the material parameters conflict.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|187||[[Help:VE187|&amp;quot;The value &#039;$(VALUE)&#039; in not a valid KUID.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|188||[[Help:VE188|&amp;quot;Custom render plugin failed to load mesh &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|189||[[Help:VE189|&amp;quot;Collision data exceeds $(LIMIT)KB. Please specify a different generation method or a simplified mesh.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|190||[[Help:VE190|&amp;quot;Tag &#039;$(NAME)&#039; is unable to be converted from $(TYPE1) to $(TYPE2)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|191||[[Help:VE191|&amp;quot;Tag &#039;$(NAME)&#039; does not contain a valid integer: $(VALUE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|192||[[Help:VE192|&amp;quot;Tag &#039;$(NAME)&#039; does not contain a valid float list: $(VALUE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|193||[[Help:VE193|&amp;quot;Tag &#039;$(NAME)&#039; does not contain a valid float&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|194||[[Help:VE194|&amp;quot;Tag &#039;$(NAME)&#039; does not contain a valid kuid: $(VALUE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|195||[[Help:VE195|&amp;quot;Unable to parse chunk $(CHUNK_INDEX) in mesh file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|196||[[Help:VE196|&amp;quot;Failed to load bogey $(KUID)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|197||[[Help:VE197|&amp;quot;Syntax error in script &#039;$(SCRIPT)&#039; for asset $(ASSET)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|198||[[Help:VE198|&amp;quot;Session failed to load route asset: $(KUID)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|199||[[Help:VE199|&amp;quot;Asset $(KUID) failed to load. Unloading resources.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|200||[[Help:VE200|&amp;quot;Unable to load mesh $(NAME) for $(ASSET_ID)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|201||[[Help:VE201|&amp;quot;Traincar is missing required attachment point: $(ATT_NAME)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|202||[[Help:VE202|&amp;quot;Parse error reading twinkles file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|203||[[Help:VE203|&amp;quot;Bad sequence order in $(TAG_NAME) list. Each element must be greater than the last.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|204||[[Help:VE204|&amp;quot;Invalid range in $(TAG_NAME) list. Elements must be greater than or equal to $(INC_MIN) and less than $(EXC_MAX).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|205||[[Help:VE205|&amp;quot;Invalid element count in $(TAG_NAME) list. This list must have at least $(COUNT) elements (to match the $(TAG_START) list).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|206||[[Help:VE206|&amp;quot;The season-selector references season &#039;$(SEASON)&#039;, but this does not exist in the texture-variants container.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|207||[[Help:VE207|&amp;quot;Attached track asset $(CHILD) failed to load.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|208||[[Help:VE208|&amp;quot;Attached track asset not specified for track $(INDEX).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|209||[[Help:VE209|&amp;quot;Asset is missing the required &#039;attached-track&#039; container.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|210||[[Help:VE210|&amp;quot;Asset is missing the required &#039;track&#039; tag.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|211||[[Help:VE211|&amp;quot;Asset is missing the required &#039;road&#039; tag.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|212||[[Help:VE212|&amp;quot;Traincar asset must have at least two bogeys.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|213||[[Help:VE213|&amp;quot;Traincar asset has invalid bogey placement.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|214||[[Help:VE214|&amp;quot;Traincar asset has invalid length.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|215||[[Help:VE215|&amp;quot;Asset has an invalid number of LODs: $(LOD_COUNT)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|216||[[Help:VE216|&amp;quot;Material $(MATERIAL) in mesh file $(MESH) has an inappropriate texture slot assigned: $(TEXTURE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|217||[[Help:VE217|&amp;quot;Material $(MATERIAL) in mesh file $(MESH) has no texture assigned to a required slot: $(TEXTURE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|218||[[Help:VE218|&amp;quot;Asset has duplicate attached track at track $(INDEX).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|225||[[Help:VE225|&amp;quot;Failed to query asset details for featured asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|226||[[Help:VE226|&amp;quot;Failed to upload asset details for featured asset: $(ERRORTEXT)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|227||[[Help:VE227|&amp;quot;Missing image for featured asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|228||[[Help:VE228|&amp;quot;Failed to read image file for featured asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|229||[[Help:VE229|&amp;quot;DLC marketing image is missing or incorrectly sized for featured asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|230||[[Help:VE230|&amp;quot;DLS thumbnail image is missing or incorrectly sized for featured asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|231||[[Help:VE231|&amp;quot;Failed to open image file for featured asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|232||[[Help:VE232|&amp;quot;Failed to upload image for featured asset: $(ERRORTEXT)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|233||[[Help:VE233|&amp;quot;One or more featured assets was not provided.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|234||[[Help:VE234|&amp;quot;Asset is not present in the featured assets list.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|235||[[Help:VE235|&amp;quot;Featured asset is not present in the input.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|236||[[Help:VE236|&amp;quot;Featured asset was not available.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|237||[[Help:VE237|&amp;quot;Featured asset failed validation.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|238||[[Help:VE238|&amp;quot;Featured asset has faulty or missing dependencies.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|239||[[Help:VE239|&amp;quot;Featured asset is Base content.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|240||[[Help:VE240|&amp;quot;Featured asset is missing an English name or description.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|241||[[Help:VE241|&amp;quot;Newly built package is not compatible with previously released version.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|242||[[Help:VE242|&amp;quot;Unable to load animation file &#039;$(FILE)&#039; (file not found, or is damaged).&amp;quot;]]&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=Category:Validation_Errors&amp;diff=23704</id>
		<title>Category:Validation Errors</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=Category:Validation_Errors&amp;diff=23704"/>
		<updated>2020-06-11T03:55:38Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Validation Error (VE) numbers are logged during content validation, to allow users to look up particular validation messages to better understand the source of the problem. Normal logs provide a substantial amount of technical detail about the error, but typically assume that the reader is familiar with the subject matter and will understand why the log is relevant. This wiki provides the necessary background information to understanding many of the logs, however a user who is unfamiliar with the area in question may not know where to start looking. VE numbers allow users to quickly find relevant pages in the wiki without any prior knowledge of the subject.&lt;br /&gt;
&lt;br /&gt;
This page serves as a master guide to all VE numbers currently logged by Trainz. This page does not provide detailed information on any given VE number- please refer to the individual VE number pages for specific details. The error text here is correct for the English localisation of Trainz at the time of writing, however the exact text may change from time to time. It is intended that the overall meaning of a VE number will never change- new VE numbers will be issued instead, and old VE numbers may be made obsolete.&lt;br /&gt;
&lt;br /&gt;
Logs which lack VE numbers do not belong on this page.&lt;br /&gt;
&lt;br /&gt;
The individual VE pages can be found at the links below, or can be accessed directly from [[Content Manager]] by right-clicking on the Validation Error in the results log, and selecting &amp;quot;View Help for This Message&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|1||[[Help:VE1|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Decimal value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|2||[[Help:VE2|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Integer value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|3||[[Help:VE3|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|4||[[Help:VE4|&amp;quot;&#039;$(TAG_NAME)&#039; must have a positive value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|5||[[Help:VE5|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|6||[[Help:VE6|&amp;quot;&#039;$(TAG_NAME)&#039; must not be zero.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|7||[[Help:VE7|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|8||[[Help:VE8|&amp;quot;The value for &#039;$(TAG_NAME)&#039; must be between &#039;$(MIN)&#039; and &#039;$(MAX)&#039; but was specified as &#039;$(VALUE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|9||[[Help:VE9|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|10||[[Help:VE10|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|11||[[Help:VE11|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|12||[[Help:VE12|&amp;quot;No string-table entry found with tag &#039;$(VALUE)&#039; for for string-token tag &#039;$(TAG)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|13||[[Help:VE13|&amp;quot;Missing or invalid selection for tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|14||[[Help:VE14|&amp;quot;Missing or invalid selection for tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|15||[[Help:VE15|&amp;quot;Attachment point &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must be found in mesh &#039;$(MESH_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|16||[[Help:VE16|&amp;quot;Container &#039;$(CONT_NAME)&#039; does not have an &#039;att-parent&#039; tag which is required to reference an attachment point.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|17||[[Help:VE17|&amp;quot;Attachment point &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must be found in mesh &#039;$(MESH_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|18||[[Help:VE18|&amp;quot;Attachment point &#039;$(TAG_VAL)&#039; referenced by tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; was not found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|19||[[Help:VE19|&amp;quot;Effect &#039;$(EFFECT_NAME)&#039; in &#039;$(CONT_NAME)&#039; was not found within the mesh table.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|20||[[Help:VE20|&amp;quot;Mesh &#039;$(MESH_NAME)&#039; referenced in &#039;$(CONT_NAME)&#039; was not found within the mesh table.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|21||[[Help:VE21|&amp;quot;Attachment point &#039;$(TAG_VAL)&#039; referenced by tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; was not found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|22||[[Help:VE22|&amp;quot;Missing or invalid selection for tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|23||[[Help:VE23|&amp;quot;Invalid tag name &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|24||[[Help:VE24|&amp;quot;Invalid tag name &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|25||[[Help:VE25|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|26||[[Help:VE26|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|27||[[Help:VE27|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must have a mesh file extension.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|28||[[Help:VE28|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must have an image file extension.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|29||[[Help:VE29|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must have an animation file extension.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|30||[[Help:VE30|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; refers to a nonexistent file: &#039;$(FILENAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|31||[[Help:VE31|&amp;quot;Invalid tag name &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|32||[[Help:VE32|&amp;quot;Alias mesh requires valid parent asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|33||[[Help:VE33|&amp;quot;Alias mesh &#039;$(FILE)&#039; not found in dependency $(KUID).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|34||[[Help:VE34|&amp;quot;Alias mesh &#039;$(FILE)&#039; not found in latest version ($(NEW_KUID)) of dependency $(OLD_KUID).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|35||[[Help:VE35|&amp;quot;Required alias mesh asset $(KUID) is missing and cannot be validated.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|36||[[Help:VE36|&amp;quot;The texture &#039;$(FILE)&#039; failed to load.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|37||[[Help:VE37|&amp;quot;The texture &#039;$(FILE)&#039; is not a power of 2, please resize it.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|38||[[Help:VE38|&amp;quot;The texture &#039;$(FILE)&#039; is not square. Cubemap textures need to have the same width and height.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|39||[[Help:VE39|&amp;quot;The texture &#039;$(FILE)&#039; is a uniform color.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|40||[[Help:VE40|&amp;quot;Unable to load $(TYPE) texture &#039;$(TEXTURE)&#039; for texture file &#039;$(FILE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|41||[[Help:VE41|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Integer value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|42||[[Help:VE42|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Decimal value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|43||[[Help:VE43|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Boolean value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|44||[[Help:VE44|&amp;quot;Tag &#039;$(TAG_NAME)&#039; in the container &#039;$(CONT_NAME)&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|45||[[Help:VE45|&amp;quot;The Tag &#039;$(TAG_NAME)&#039; is not permitted within a container of type &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|46||[[Help:VE46|&amp;quot;Internal Error: The template does not specify that a smoke container is valid in the container being parsed.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|47||[[Help:VE47|&amp;quot;Container &#039;$(CONT_NAME)&#039; is not permitted in this section.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|48||[[Help:VE48|&amp;quot;This asset uses an obsolete trainz-build number. Trainz-build numbers below $(LOWEST_TRAINZBUILD) are no longer supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|49||[[Help:VE49|&amp;quot;Required tag &#039;kind&#039; is not present. Ensure this is a valid config file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|50||[[Help:VE50|&amp;quot;Unsupported kind &#039;$(KIND)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|51||[[Help:VE51|&amp;quot;Tag &#039;$(TAG_NAME)&#039; in the container &#039;$(CONT_NAME)&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|52||[[Help:VE52|&amp;quot;The Tag &#039;$(TAG_NAME)&#039; is not permitted within a container of type &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|53||[[Help:VE53|&amp;quot;This container is no longer supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|54||[[Help:VE54|&amp;quot;The Tag &#039;$(TAG_NAME)&#039; is not permitted within a container of type &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|55||[[Help:VE55|&amp;quot;This container is no longer supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|56||[[Help:VE56|&amp;quot;Container &#039;$(CONT_NAME)&#039; is not permitted in this section.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|57||[[Help:VE57|&amp;quot;Container &#039;$(CONT_NAME)&#039; is not permitted in this section.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|58||[[Help:VE58|&amp;quot;The tag &#039;$(TAG_NAME)&#039; is not a valid container type (expected &#039;$(TYPE)&#039;).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|59||[[Help:VE59|&amp;quot;Internal error: unknown dataType - kind &#039;$(KIND)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|60||[[Help:VE60|&amp;quot;Required tag &#039;$(TAG_NAME)&#039; was missing and has been set to default.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|61||[[Help:VE61|&amp;quot;Required tag &#039;$(TAG_NAME)&#039; was missing and has been set to default.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|62||[[Help:VE62|&amp;quot;Required container &#039;$(CONT_NAME)&#039; is missing.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|63||[[Help:VE63|&amp;quot;The cubemap texture &#039;$(FILE)&#039; has missing images. Please verify the texture.txt file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|64||[[Help:VE64|&amp;quot;Cubemap texture &#039;$(FILE)&#039; contains images of different sizes.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|65||[[Help:VE65|&amp;quot;The *.texture.txt file is missing for texture resource &#039;$(FILE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|66||[[Help:VE66|&amp;quot;The texture file &#039;$(FILE)&#039; contains non-ANSI characters. Textures must be ANSI.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|67||[[Help:VE67|&amp;quot;The texture &#039;$(FILE)&#039; does not seem to have a primary texture set. Please verify the texture.txt file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|68||[[Help:VE68|&amp;quot;The primary and alpha texture are not the same size for &#039;$(FILE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|69||[[Help:VE69|&amp;quot;Binary conversion failed for texture resource &#039;$(FILE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|70||[[Help:VE70|&amp;quot;The KUID tag is not a valid KUID value: &#039;$(string)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|71||[[Help:VE71|&amp;quot;Unsupported SpeedTree version for mesh: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|72||[[Help:VE72|&amp;quot;Unable to load mesh file: &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|73||[[Help:VE73|&amp;quot;Image file &#039;$(FILE)&#039; is incorrectly used as both a texture.txt source file and a raw image file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|74||[[Help:VE74|&amp;quot;Image file &#039;$(FILE)&#039; is incorrectly used as both a texture.txt source file and a raw image file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|76||[[Help:VE76|&amp;quot;Unable to load mesh file: &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|77||[[Help:VE77|&amp;quot;Unable to load indexed mesh &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|79||[[Help:VE79|&amp;quot;Unable to load animation file &#039;$(FILE)&#039; (mesh has not been loaded correctly).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|81||[[Help:VE81|&amp;quot;The high-poly mesh &#039;$(FILE)&#039; should have LOD levels.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|82||[[Help:VE82|&amp;quot;High-detail .im files are not supported for traincar assets, as they are likely to perform poorly. It is recommended that you upgrade &#039;$(FILE)&#039; to a .lm file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|83||[[Help:VE83|&amp;quot;The file &#039;$(FILE)&#039; is provided in LM format despite having no attachment points and no animation support. This may have a negative impact on performance.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|84||[[Help:VE84|&amp;quot;The file &#039;$(FILE)&#039; is provided in LM format despite containing only a single mesh. This may have a negative impact on performance.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|85||[[Help:VE85|&amp;quot;The file &#039;$(FILE)&#039; is provided in LM format, however the high-detail mesh is comprised of less than 300 polygons. This may have a negative impact on performance.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|86||[[Help:VE86|&amp;quot;Legacy .pm files are no longer supported, and will perform poorly. It is recommended that you switch to using a .lm file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|87||[[Help:VE87|&amp;quot;Legacy .pm files are no longer supported, and will perform poorly. It is recommended that you switch to using a .lm file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|88||[[Help:VE88|&amp;quot;This asset has a trainz-build number which is not recognised by this tool.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|89||[[Help:VE89|&amp;quot;Tag &#039;$(TAG_NAME)&#039; in the container &#039;$(CONT_NAME)&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|90||[[Help:VE90|&amp;quot;This asset has an invalid KUID user id&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|91||[[Help:VE91|&amp;quot;The dependency $(KUID) has an invalid KUID User ID and cannot be used&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|92||[[Help:VE92|&amp;quot;Duplicate &#039;$(TAG_NAME)&#039; containers in &#039;$(CONT_NAME)&#039;. Containers must have a unique name.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|93||[[Help:VE93|&amp;quot;Duplicate &#039;$(TAG_NAME)&#039; tags in &#039;$(CONT_NAME)&#039;. Tags must have a unique name.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|94||[[Help:VE94|&amp;quot;This asset requires a shadow mesh, but the mesh table does not contain one.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|95||[[Help:VE95|&amp;quot;This asset does not have a mesh that is visible by default.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|96||[[Help:VE96|&amp;quot;Maximum of 5 running number fonts supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|97||[[Help:VE97|&amp;quot;The running number font directory &#039;$(DIR)&#039; could not be found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|98||[[Help:VE98|&amp;quot;The running number font file &#039;$(DIR)/$(FILE)&#039; could not be found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|99||[[Help:VE99|&amp;quot;The track-sound container &#039;$(NAME)&#039; has no bogey, track or track-parent tag.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|100||[[Help:VE100|&amp;quot;Required tag &#039;$(TAG_NAME)&#039; was missing and has been set to default.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|101||[[Help:VE101|&amp;quot;The file &#039;$(FILE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|102||[[Help:VE102|&amp;quot;Failed to load sound file &#039;$(FILE)&#039;, please ensure this is a valid wav file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|103||[[Help:VE103|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|104||[[Help:VE104|&amp;quot;Multiple template property bindings for rule property &#039;$(PROP)&#039; for rule &#039;$(RULE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|105||[[Help:VE105|&amp;quot;The template property &#039;$(NAME)&#039; specified in the rule-template-bindings container of rule &#039;$(RULE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|106||[[Help:VE106|&amp;quot;The high-detail meshes in season $(SEASON) total more than $(LIMIT) polygons. This may have a negative impact on performance: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|107||[[Help:VE107|&amp;quot;The high-detail meshes total more than $(LIMIT) polygons. This may have a negative impact on performance: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|108||[[Help:VE108|&amp;quot;The low-detail meshes in season $(SEASON) total more than 500 polygons. This may have a negative impact on performance: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|109||[[Help:VE109|&amp;quot;The low-detail meshes total more than 500 polygons. This may have a negative impact on performance: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|110||[[Help:VE110|&amp;quot;The meshes in LOD level $(LOD_LEVEL) in season $(SEASON) must total at least 20% fewer polygons than the next higher LOD in the same season: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|111||[[Help:VE111|&amp;quot;The meshes in LOD level $(LOD_LEVEL) must total at least 20% fewer polygons than the next higher LOD: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|112||[[Help:VE112|&amp;quot;Multiple track stretches between &#039;$(FROM_VERTEX)&#039; and &#039;$(TO_VERTEX)&#039; in container &#039;$(CONT_NAME)&#039;. Track stretches must be unique.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|113||[[Help:VE113|&amp;quot;An image file (&#039;$(FILE)&#039;) has been supplied where a texture file (&#039;*.texture.txt&#039;) is required.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|114||[[Help:VE114|&amp;quot;An image file (&#039;$(FILE)&#039;) has been supplied where a texture file (&#039;*.texture.txt&#039;) is required.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|115||[[Help:VE115|&amp;quot;The texture file &#039;$(FILE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|116||[[Help:VE116|&amp;quot;No texture file has been specified for this texture asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|117||[[Help:VE117|&amp;quot;&#039;$(TAG_0)&#039; must be set to a &#039;$(KIND)&#039; for &#039;$(TAG_1)&#039; to be allowed.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|118||[[Help:VE118|&amp;quot;Tag &#039;$(TAG_0)&#039; requires that &#039;$(TAG_1)&#039; be set to &#039;$(KIND)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|119||[[Help:VE119|&amp;quot;The tag &#039;$(TAG_NAME)&#039; is not valid for kind &#039;$(KIND)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|120||[[Help:VE120|&amp;quot;Tag &#039;$(TAG_0)&#039;, requires the tag &#039;$(TAG_1)&#039; to be present.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|121||[[Help:VE121|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|122||[[Help:VE122|&amp;quot;&#039;$(TAG_NAME)&#039; must have a positive value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|123||[[Help:VE123|&amp;quot;The script file &#039;$(FILE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|124||[[Help:VE124|&amp;quot;The file &#039;$(FILE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|125||[[Help:VE125|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|126||[[Help:VE126|&amp;quot;&#039;$(TAG_NAME)&#039; must not be zero.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|127||[[Help:VE127|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|128||[[Help:VE128|&amp;quot;The value for &#039;$(TAG_NAME)&#039; must be between &#039;$(MIN)&#039; and &#039;$(MAX)&#039; but was specified as &#039;$(VALUE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|129||[[Help:VE129|&amp;quot;Incorrect number of values for the tag &#039;$(TAG_NAME)&#039;, expected $(NUM_0) values, found $(NUM_1).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|130||[[Help:VE130|&amp;quot;Too many values for the tag &#039;$(TAG_NAME)&#039;, maximum is $(MAX) values, found $(FOUND).&amp;quot;]]]]&lt;br /&gt;
|-&lt;br /&gt;
|131||[[Help:VE131|&amp;quot;Value must be a mesh from the mesh-table (not a parent container).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|132||[[Help:VE132|&amp;quot;The attachment point &#039;$(ATT)&#039; must belong to the parent mesh of the effect (mesh=$(MESH)).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|133||[[Help:VE133|&amp;quot;A light container must be present to link the signals.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|134||[[Help:VE134|&amp;quot;&#039;$(NUM)&#039; must be a valid light number from the light container.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|135||[[Help:VE135|&amp;quot;&#039;$(TAG_0)&#039; requires that the tag &#039;$(TAG_1)&#039; be present.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|136||[[Help:VE136|&amp;quot;&#039;$(TAG_0)&#039; requires that the tag &#039;$(TAG_1)&#039; be present.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|137||[[Help:VE137|&amp;quot;Empty or invalid running number specified at character index $(INDEX)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|138||[[Help:VE138|&amp;quot;Running number specified at character index $(INDEX) is too large, must be less than 9 characters.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|139||[[Help:VE139|&amp;quot;Invalid running number range specified at character index $(INDEX), ($(FROM)-$(TO)).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|140||[[Help:VE140|&amp;quot;Running number range &#039;$(FROM)-$(TO)&#039; specified at character index $(INDEX) overlaps already in use numbers, running numbers must be unique.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|141||[[Help:VE141|&amp;quot;Running number &#039;$(NUMBER)&#039; specified at character index $(INDEX) is already in use.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|142||[[Help:VE142|&amp;quot;Invalid character &#039;$(CHAR)&#039; specified in running number list, only numbers, &#039;,&#039; and &#039;-&#039; are supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|143||[[Help:VE143|&amp;quot;Possible running number list is too large, the set must contain less than 20000 possibilities.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|144||[[Help:VE144|&amp;quot;Category code &#039;ZX - Paintshed template&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|145||[[Help:VE145|&amp;quot;Category code &#039;ZX - Paintshed template&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|146||[[Help:VE146|&amp;quot;An asset must be specified for tag &#039;$(TAG_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|147||[[Help:VE147|&amp;quot;The tag(s) $(MISPLACED_TAGS) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|148||[[Help:VE148|&amp;quot;The tag(s) $(MISPLACED_TAGS) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|149||[[Help:VE149|&amp;quot;The mesh(es) $(MISPLACED_MESHES) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|150||[[Help:VE150|&amp;quot;The mesh(es) $(MISPLACED_MESHES) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|151||[[Help:VE150|&amp;quot;The mesh(es) $(MISPLACED_MESHES) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|152||[[Help:VE152|&amp;quot;The tags $(MISSING_TAGS) are not all defined. The default values will be used and the positions of the elements may not fit your track.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|153||[[Help:VE153|&amp;quot;The mesh $(MESH) is present but the tag $(MISSING_TAG) is not defined.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|154||[[Help:VE154|&amp;quot;The mesh $(MESH) is present but the tag $(MISSING_TAG) is not defined.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|155||[[Help:VE155|&amp;quot;The mesh $(MESH) is present but the tags $(MISSING_TAGS) are not all defined.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|156||[[Help:VE156|&amp;quot;The tag $(MISSING_TAG) is not defined. The default value will be used and the positions of the elements may not fit your track.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|157||[[Help:VE157|&amp;quot;The mesh $(MESH) is present but the tag $(MISSING_TAG) is missing. The default value will be used and the positions of the elements may not fit your track.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|158||[[Help:VE158|&amp;quot;Unable to open .lm.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|159||[[Help:VE159|&amp;quot;Unable to parse .lm.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|160||[[Help:VE160|&amp;quot;No &#039;mesh&#039; keys found in .lm.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|161||[[Help:VE161|&amp;quot;$(LODCOUNT) LODs in .lm.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|162||[[Help:VE162|&amp;quot;One of the LOD reductions of &#039;$(FILE)&#039; introduces a new attachment point: $(ATT)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|163||[[Help:VE163|&amp;quot;Unable to parse .im file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|164||[[Help:VE164|&amp;quot;Invalid position data in .im file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|165||[[Help:VE165|&amp;quot;Texture &#039;$(TEXTURE)&#039; is missing or could not be loaded in mesh &#039;$(FILE)&#039;, material &#039;$(MATERIAL)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|166||[[Help:VE166|&amp;quot;$(COMBINEDCOUNT) combined chunks (of $(SOURCECOUNT) source) in .im file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|167||[[Help:VE167|&amp;quot;Source image texture file &#039;$(TEXTUREFILE)&#039; is too large for &#039;$(ASSETFILE)&#039; ($(WIDTH)x$(HEIGHT))&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|168||[[Help:VE168|&amp;quot;File &#039;$(TEXTUREFILE)&#039; is not a valid compiled texture file for &#039;$(ASSETFILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|169||[[Help:VE169|&amp;quot;Compiled texture file &#039;$(TEXTUREFILE)&#039; is unsupported version for &#039;$(ASSETFILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|170||[[Help:VE170|&amp;quot;Failed to open compiled texture &#039;$(TEXTUREFILE)&#039; for &#039;$(ASSETFILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|171||[[Help:VE171|&amp;quot;Expected texture file type but found &#039;$(TEXTUREFILE)&#039; for &#039;$(ASSETFILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|172||[[Help:VE172|&amp;quot;Script class does not match asset kind ($(KIND)).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|173||[[Help:VE173|&amp;quot;Material &#039;$(MATERIAL)&#039; in mesh &#039;$(FILE)&#039; is not of a recognised material type.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|174||[[Help:VE174|&amp;quot;MeshObjectSpec::LinkSpecs&amp;gt; Mesh-table element #$(MESH_INDEX) parent mesh is invalid.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|175||[[Help:VE175|&amp;quot;MeshObjectSpec::LinkSpecs&amp;gt; Mesh-table element #$(MESH_INDEX) is part of invalid hierarchy.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|176||[[Help:VE176|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must have a texture file extension.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|177||[[Help:VE177|&amp;quot;The kuid &#039;$(KUID)&#039; is not in the database, and could not be found in any known location. Ensure that this is a valid asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|178||[[Help:VE178|&amp;quot;The asset specified in &#039;$(KUID)&#039; is not installed locally but is available for download.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|179||[[Help:VE179|&amp;quot;The kuid &#039;$(KUID)&#039; specified in &#039;$(TAG_NAME)&#039; is not of the correct type.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|180||[[Help:VE180|&amp;quot;Integrity check failure on $(FILE). One or more route/session tiles may be missing.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|181||[[Help:VE181|&amp;quot;The tag &#039;$(TAG_NAME)&#039; requires a minimum asset version of $(MIN_VERSION)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|182||[[Help:VE182|&amp;quot;Material &#039;$(MATERIAL)&#039; in mesh &#039;$(FILE)&#039; is missing a texture for a mandatory texture slot.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|183||[[Help:VE183|&amp;quot;FBX file is in an unsupported older format.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|184||[[Help:VE184|&amp;quot;KIND &#039;$(KIND)&#039; requires trainz-build $(TRAINZBUILD).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|185||[[Help:VE185|&amp;quot;Material &#039;$(MATERIAL)&#039; in mesh &#039;$(FILE)&#039; has heightmap texture. Provide a normal map instead.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|186||[[Help:VE186|&amp;quot;Material &#039;$(MATERIAL)&#039; is shared between multiple chunks in this asset but the material parameters conflict.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|187||[[Help:VE187|&amp;quot;The value &#039;$(VALUE)&#039; in not a valid KUID.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|188||[[Help:VE188|&amp;quot;Custom render plugin failed to load mesh &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|189||[[Help:VE189|&amp;quot;Collision data exceeds $(LIMIT)KB. Please specify a different generation method or a simplified mesh.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|190||[[Help:VE190|&amp;quot;Tag &#039;$(NAME)&#039; is unable to be converted from $(TYPE1) to $(TYPE2)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|191||[[Help:VE191|&amp;quot;Tag &#039;$(NAME)&#039; does not contain a valid integer: $(VALUE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|192||[[Help:VE192|&amp;quot;Tag &#039;$(NAME)&#039; does not contain a valid float list: $(VALUE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|193||[[Help:VE193|&amp;quot;Tag &#039;$(NAME)&#039; does not contain a valid float&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|194||[[Help:VE194|&amp;quot;Tag &#039;$(NAME)&#039; does not contain a valid kuid: $(VALUE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|195||[[Help:VE195|&amp;quot;Unable to parse chunk $(CHUNK_INDEX) in mesh file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|196||[[Help:VE196|&amp;quot;Failed to load bogey $(KUID)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|197||[[Help:VE197|&amp;quot;Syntax error in script &#039;$(SCRIPT)&#039; for asset $(ASSET)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|198||[[Help:VE198|&amp;quot;Session failed to load route asset: $(KUID)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|199||[[Help:VE199|&amp;quot;Asset $(KUID) failed to load. Unloading resources.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|200||[[Help:VE200|&amp;quot;Unable to load mesh $(NAME) for $(ASSET_ID)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|201||[[Help:VE201|&amp;quot;Traincar is missing required attachment point: $(ATT_NAME)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|202||[[Help:VE202|&amp;quot;Parse error reading twinkles file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|203||[[Help:VE203|&amp;quot;Bad sequence order in $(TAG_NAME) list. Each element must be greater than the last.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|204||[[Help:VE204|&amp;quot;Invalid range in $(TAG_NAME) list. Elements must be greater than or equal to $(INC_MIN) and less than $(EXC_MAX).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|205||[[Help:VE205|&amp;quot;Invalid element count in $(TAG_NAME) list. This list must have at least $(COUNT) elements (to match the $(TAG_START) list).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|206||[[Help:VE206|&amp;quot;The season-selector references season &#039;$(SEASON)&#039;, but this does not exist in the texture-variants container.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|207||[[Help:VE207|&amp;quot;Attached track asset $(CHILD) failed to load.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|208||[[Help:VE208|&amp;quot;Attached track asset not specified for track $(INDEX).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|209||[[Help:VE209|&amp;quot;Asset is missing the required &#039;attached-track&#039; container.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|210||[[Help:VE210|&amp;quot;Asset is missing the required &#039;track&#039; tag.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|211||[[Help:VE211|&amp;quot;Asset is missing the required &#039;road&#039; tag.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|212||[[Help:VE212|&amp;quot;Traincar asset must have at least two bogeys.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|213||[[Help:VE213|&amp;quot;Traincar asset has invalid bogey placement.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|214||[[Help:VE214|&amp;quot;Traincar asset has invalid length.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|215||[[Help:VE215|&amp;quot;Asset has an invalid number of LODs: $(LOD_COUNT)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|216||[[Help:VE216|&amp;quot;Material $(MATERIAL) in mesh file $(MESH) has an inappropriate texture slot assigned: $(TEXTURE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|217||[[Help:VE217|&amp;quot;Material $(MATERIAL) in mesh file $(MESH) has no texture assigned to a required slot: $(TEXTURE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|218||[[Help:VE218|&amp;quot;Asset has duplicate attached track at track $(INDEX).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|225||[[Help:VE225|&amp;quot;Failed to query asset details for featured asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|226||[[Help:VE226|&amp;quot;Failed to upload asset details for featured asset: $(ERRORTEXT)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|227||[[Help:VE227|&amp;quot;Missing image for featured asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|228||[[Help:VE228|&amp;quot;Failed to read image file for featured asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|229||[[Help:VE229|&amp;quot;DLC marketing image is missing or incorrectly sized for featured asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|230||[[Help:VE230|&amp;quot;DLS thumbnail image is missing or incorrectly sized for featured asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|231||[[Help:VE231|&amp;quot;Failed to open image file for featured asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|232||[[Help:VE232|&amp;quot;Failed to upload image for featured asset: $(ERRORTEXT)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|233||[[Help:VE233|&amp;quot;One or more featured assets was not provided.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|234||[[Help:VE234|&amp;quot;Asset is not present in the featured assets list.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|235||[[Help:VE235|&amp;quot;Featured asset is not present in the input.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|236||[[Help:VE236|&amp;quot;Featured asset was not available.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|237||[[Help:VE237|&amp;quot;Featured asset failed validation.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|238||[[Help:VE238|&amp;quot;Featured asset has faulty or missing dependencies.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|239||[[Help:VE239|&amp;quot;Featured asset is Base content.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|240||[[Help:VE240|&amp;quot;Featured asset is missing an English name or description.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|241||[[Help:VE241|&amp;quot;Newly built package is not compatible with previously released version.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|241||[[Help:VE241|&amp;quot;Unable to load animation file &#039;$(FILE)&#039; (file not found, or is damaged).&amp;quot;]]&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=Texture_file&amp;diff=21804</id>
		<title>Texture file</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=Texture_file&amp;diff=21804"/>
		<updated>2019-11-04T03:58:10Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{ORP-top}}&lt;br /&gt;
Trainz &#039;&#039;&#039;Texture files&#039;&#039;&#039; are ASCII text format specification files describing a single texture. Texture files have a &amp;quot;.texture.txt&amp;quot; name extension, however when a texture file is specified within a [[config.txt file]] or similar, the &amp;quot;.txt&amp;quot; must be omitted (as you are specifying a resource name, not a file path), leaving only the &amp;quot;.texture&amp;quot; extension.&lt;br /&gt;
&lt;br /&gt;
Texture files (*.texture.txt) should be distinguished from [[image file]]s (*.tga, etc.) and [[material]]s. A material may utilize zero or more texture files, and a texture file may utilize one or more image files. While we often refer to the image data as &amp;quot;a texture&amp;quot;, this usage isn&#039;t strictly correct as any given texture also has a number of metadata attributes which are not present in the source image. Additionally, a texture may be compressed (at installation time) which may actually lose some of the data originally present in the source image.&lt;br /&gt;
&lt;br /&gt;
When importing a [[trainzmesh file]] from an [[FBX file]], any image files referenced in the FBX which do not already have corresponding texture files will have generic texture files created automatically. These files may be suitable for basic purposes, but may need to be customized for more advanced functionality. Once the file has been created (and optionally customised) the importer will not recreate/overwrite it on subsequent runs.&lt;br /&gt;
&lt;br /&gt;
This page describes [[&amp;quot;Trainz-build&amp;quot; number|content format v4.6]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=File format=&lt;br /&gt;
&lt;br /&gt;
The user-editable *.texture.txt files are ASCII text formatted key-value pairs with the following options. Please note that this format is not the same (despite some similarities) as other text-based formats used by Trainz. Please be aware of the [[filename character restrictions]] when naming texture and image files.&lt;br /&gt;
&lt;br /&gt;
;Syntax&lt;br /&gt;
Each key is specified on a new line. There is no white space anywhere in the line. A empty value is sometimes valid. The syntax is:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;key&amp;gt;=&amp;lt;value&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Example:&lt;br /&gt;
 Primary=WayCoolTexture.tga&lt;br /&gt;
 Alpha=WayCoolTexture.tga&lt;br /&gt;
 Tile=st&lt;br /&gt;
 AlphaHint=masked&lt;br /&gt;
&#039;&#039;(Example only, not recommended settings)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Keys and Values==&lt;br /&gt;
&lt;br /&gt;
 Primary=diffusemap.bmp&lt;br /&gt;
&lt;br /&gt;
This tag specifies the filename of the image file representing the color (R, G, B) channels of the texture. Any alpha channel in the image file is ignored. The resultant texture will have a pure white (100%) alpha channel.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Primary=diffusemap.jpg&lt;br /&gt;
 Alpha=diffusemap.bmp&lt;br /&gt;
&lt;br /&gt;
This tag combination specifies the filenames of the image file representing the color (R, G, B) channels of the texture (Primary) and the image file representing the transparency of the texture (Alpha). The Alpha image should be grayscale. Neither file should contain an alpha (A) channel (ie, both images should be 24-bit). The two image files must be of identical size.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Primary=diffusemap.tga&lt;br /&gt;
 Alpha=diffusemap.tga&lt;br /&gt;
&lt;br /&gt;
This tag combination specifies the filename of a single image file representing the color and transparency (R, G, B, A) channels of the texture. In this case both tags must reference the same filename. The image file must contain an alpha channel.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Compression=dxt3&lt;br /&gt;
&lt;br /&gt;
This tag hints the usage of a particular texture compression scheme. If you don&#039;t have a specific effect in mind, don&#039;t include this tag. Valid options are currently &#039;none&#039;, &#039;dxt1&#039;, &#039;dxt3&#039;, &#039;dxt5&#039;. Refer [[DXT Compression]].&lt;br /&gt;
&lt;br /&gt;
The current selection logic for texture compression is as follows, however it should be noted that this may change between Trainz versions. The first matching rule is used.&lt;br /&gt;
&lt;br /&gt;
* Special texture formats (such as HDR) which don&#039;t support compression are stored uncompressed.&lt;br /&gt;
* &amp;quot;Compression=none&amp;quot; forces no compression. This gives the best visual result for a given input image, but typically yields worse visual results per output texture filesize. It is often better to activate compression and double the image dimensions, rather than disabling compression.&lt;br /&gt;
* Images with an &amp;quot;opaque&amp;quot; alpha hint use DXT1 compression.&lt;br /&gt;
* &amp;quot;Compression=dxt3&amp;quot; will use DXT3 compression.&lt;br /&gt;
* DXT5 compression is used.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 NormalMapHint=normalmap&lt;br /&gt;
&lt;br /&gt;
The &#039;NormalMapHint&#039; tag allows the texture to be specified as a [[normal map]]. By default, Trainz will assume that your texture is a [[diffuse map]] and will apply some processing options which are not appropriate for normal maps. You must specify this option for normal maps. Valid options are &#039;none&#039; and &#039;normalmap&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 ModifyMap=flipgreen&lt;br /&gt;
&lt;br /&gt;
The &#039;ModifyMap&#039; option allows a texture&#039;s green color channel to be flipped.  Some programs such as [[Autodesk 3ds Max]] create [[normal map]]s with the Y axis facing the opposite way to what is expected by the Trainz shaders.  This option can be used to make the bump effect look correct in Trainz. Valid options are &#039;none&#039; and &#039;flipgreen&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 AlphaHint=opaque&lt;br /&gt;
&lt;br /&gt;
The &#039;AlphaHint&#039; tag allows you to force a particular alpha mode on the texture. Valid options are &#039;opaque&#039; (meaning that the alpha channel is overwritten with pure white), &#039;semitransparent&#039; (meaning that the alpha channel is a grayscale blend) and &#039;masked&#039; (meaning that the alpha channel is clamped to a pure black&amp;amp;white bitmap based on a 50% threshold.) If omitted, Trainz will supply an appropriate value for this tag based on the actual contents of the Alpha channel.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Tile=st&lt;br /&gt;
&lt;br /&gt;
Tiling refers to the ability for texture coordinates outside the range of (0.0 .. 1.0) to be treated as valid coordinates on an infinitely tiled texture. With tiling active, coordinates which pass the right/bottom side of the texture effectively wrap back onto the left/top side, and so on. Valid options include &#039;s&#039; (tile horizontally), &#039;t&#039; (tile vertically), &#039;st&#039; (tile both horizontally and vertically), and &#039;none&#039; (do not tile the image).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 MipAlgorithm=no-weight-by-alpha&lt;br /&gt;
&lt;br /&gt;
The default [[mipmap]] generation algorithm generally treats the alpha channel as an opacity and prioritizes opaque texels over transparent ones. This can lead to poor results in cases where the alpha channel is used for a different purpose (such as with PBR parameter textures). The &amp;quot;no-weight-by-alpha&amp;quot; hint can be used to ensure that the game will give equal weighting to texels regardless of their alpha channel.&lt;br /&gt;
&lt;br /&gt;
The value of this key is only relevant where [[Content Manager]] is responsible for producing mipmap images. It is not relevant on any mipmap images provided in the source images.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 nonpoweroftwo=1&lt;br /&gt;
&lt;br /&gt;
By default, all textures must have both their width and height as a power of two (eg. 8, 16, 32, 64, 128, 256, 512, 1024, 2048), though they need not be square. Setting the value &#039;1&#039; for the &#039;nonpoweroftwo&#039; key allows this restriction to be relaxed. This is currently considered experimental and may have unexpected performance, quality, or functionality outcomes. It is not recommended that end-users utilize this format at the current time.&lt;br /&gt;
&lt;br /&gt;
Non-power-of-two (NPOT) textures may not support mipmapping and thus may be noticeably affected by the moire effect in addition to having higher overall GPU bandwidth requirements.&lt;br /&gt;
&lt;br /&gt;
=Texture Formats=&lt;br /&gt;
The following texture formats are supported internally by Trainz on desktop platforms.&lt;br /&gt;
* R8 G8 B8 A8&lt;br /&gt;
* DXT1&lt;br /&gt;
* DXT3&lt;br /&gt;
* DXT5&lt;br /&gt;
* R32F G32F B32F A32F&lt;br /&gt;
&lt;br /&gt;
The selection of internal format depends on the source image format and the value of the &#039;Compression&#039; key.&lt;br /&gt;
&lt;br /&gt;
=Texture Size=&lt;br /&gt;
Textures must be no more than 4096 pixels in either dimension, although it is strongly recommended that textures are kept below this maximum to avoid performance problems. Small objects should typically use approximately 512x512. Large, highly detailed objects such as train vehicles or ground textures will typically use 2048x2048.&lt;br /&gt;
Uniform-color textures (ie. textures in which all [[texel]]s have the same color) should be 8x8.&lt;br /&gt;
Textures must be a power-of-two size in each dimension (unless the &#039;nonpoweroftwo&#039; key is activated), but need not be square. Some materials may give unexpected results for non-square textures; consult the material-specific documentation for details.&lt;br /&gt;
&lt;br /&gt;
=Source Image Formats=&lt;br /&gt;
The following image formats are acceptable as source data for the texture file. Note that these formats are not used at runtime, and that format-specific benefits such as compression will apply to the DLS download size of the content but not to the runtime memory footprint or GPU bandwidth usage.&lt;br /&gt;
&lt;br /&gt;
* Targa (.tga) files. Targa is a lossless image format with optional compression and optional alpha channel. This is a sensible choice where compatibility with older versions of Trainz is desired.&lt;br /&gt;
* JPEG (.jpg) files. JPEG is a lossy image compression format with no alpha channel support. This format should generally be avoided since it will typically lead to the image being compressed in a lossy format (JPG), decompressed, recompressed again into another lossy format (DXT1), losing detail at each stage. Worse, if JPEG files are used during the creation of the image, each edit-save-test cycle may result in a loss of image quality.&lt;br /&gt;
* Windows Bitmap (.bmp) files. BMP is a lossless image format with no compression and optional alpha channel. This format should generally be avoided since it does not offer compression and has no redeeming benefits.&lt;br /&gt;
* HDR (.hdr) files. HDR is a lossless image format with 32 bits of precision per channel. The R32F G32F B32F A32F internal texture format is used, and texture compression is not supported. This is a very expensive format (in terms of memory and performance) and should only be used where absolutely essential. Textures created in this format should be kept as small as possible (eg. 256-512 pixels wide and high).&lt;br /&gt;
* PNG (.png) files. PNG is a lossless compressed image format with alpha channel support. This is the best choice where compatibility with older versions of Trainz is not required.&lt;br /&gt;
* DDS (.dds) files. This has very limited support intended for specific internal purposes; it is not recommended that end-users utilize this format at the current time.&lt;br /&gt;
&lt;br /&gt;
All images which comprise a given texture must have identical dimensions (width, height).&lt;br /&gt;
&lt;br /&gt;
Source images should use the SRGB color space except where material-specific documentation indicates otherwise.&lt;br /&gt;
&lt;br /&gt;
=Notes on Image Editors=&lt;br /&gt;
* The Targa Exporter plugin shipped with some older versions of Adobe Photoshop is broken and silently corrupts or discards alpha channels; a free update is available which resolves this issue.&lt;br /&gt;
* Some image editors do not support alpha channels on BMP files.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=*.txt File Extension=&lt;br /&gt;
Texture files have a &amp;quot;.texture.txt&amp;quot; name extension, however when a texture file is specified within a [[config.txt file]] or similar, the &amp;quot;.txt&amp;quot; must be omitted, leaving the &amp;quot;.texture&amp;quot; extension.&lt;br /&gt;
For example, a texture file named &#039;&#039;grass.texture.txt&#039;&#039; is specified in a [[KIND Groundtexture]] config file using the syntax &#039;&#039;texture &amp;quot;grass.texture&amp;quot;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=Use of Image Files in Place of Texture Files=&lt;br /&gt;
Trainz previously supported using &#039;&#039;any supported image file&#039;&#039; type in place of a [[Texture file]]. [[TANE]] does not support this technique; a texture.txt file must be used.&lt;br /&gt;
&lt;br /&gt;
[[Category:File formats]]&lt;br /&gt;
[[Category:Modeling]]&lt;br /&gt;
[[Category:Content creation]]&lt;br /&gt;
{{ORP-bot}}&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=%22Soundscript%22_container&amp;diff=18736</id>
		<title>&quot;Soundscript&quot; container</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=%22Soundscript%22_container&amp;diff=18736"/>
		<updated>2019-06-12T01:50:46Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: /* distance */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{ORP-top}}&lt;br /&gt;
A container type tag for defining asset sounds.&lt;br /&gt;
&lt;br /&gt;
==Supported Tags==&lt;br /&gt;
Each soundscript subcontainer supports the following tags. Each tag is shown here with its default value.&lt;br /&gt;
&lt;br /&gt;
  repeat-delay  0,0&lt;br /&gt;
  distance      50,150&lt;br /&gt;
  ambient       0&lt;br /&gt;
  attachment    &amp;quot;&amp;quot;&lt;br /&gt;
  nostartdelay  0&lt;br /&gt;
  priority      1&lt;br /&gt;
  trigger       &amp;quot;&amp;quot;&lt;br /&gt;
  volume        1&lt;br /&gt;
  value-range   0,0&lt;br /&gt;
  sound-asset&lt;br /&gt;
  sound&lt;br /&gt;
  {&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
====ambient====&lt;br /&gt;
:Type: Boolean&lt;br /&gt;
:Default: 0&lt;br /&gt;
:Compulsory: No&lt;br /&gt;
:Desc: If true this is an &#039;ambient&#039; sound, ambient sounds are played in 2D and do not make use of 3D positioning in the world other than to affect volume. Unlike positional sounds, ambient sounds may be stereo.&lt;br /&gt;
&lt;br /&gt;
====attachment====&lt;br /&gt;
:Type: Attachment point&lt;br /&gt;
:Default: &amp;quot;&amp;quot;&lt;br /&gt;
:Compulsory: No&lt;br /&gt;
:Desc: Point to attach the sound source to. Attachment points are specified in the mesh file during creation.&lt;br /&gt;
&lt;br /&gt;
====distance====&lt;br /&gt;
:Type: Decimal Pair&lt;br /&gt;
:Default: 50,150&lt;br /&gt;
:Compulsory: No&lt;br /&gt;
:Desc: The minimum distance (first value, in meters) defines the radius within which the sound remains at 100% volume. Beyond that distance, the sound volume will begin to decay naturally. The maximum distance (second value, in meters) defines a radius beyond which the game need no longer play the sound. This does not mean that the sound will fade to zero by the maximum distance, but rather that the sound may cut off abruptly beyond that point. It is up to the content creator to choose an appropriate maximum distance - smaller is better for performance, but overly small values may result in the sound audibly cutting off. Many Trainz editions ignore the configured maximum distance value and instead perform their own optimized calculation of the appropriate value.&lt;br /&gt;
&lt;br /&gt;
====nostartdelay====&lt;br /&gt;
:Type: Boolean&lt;br /&gt;
:Default: 0&lt;br /&gt;
:Compulsory: No&lt;br /&gt;
:Desc: If added and true this tag specifies that the sound will play immediately once triggered. By default sounds have a random start delay between 0 &amp;amp; 4 seconds. Start delay should be left active in most cases, as turning it off may cause significant audio artifacts when several identical sounds are in proximity.&lt;br /&gt;
&lt;br /&gt;
====priority====&lt;br /&gt;
:Type: Integer&lt;br /&gt;
:Default: 1&lt;br /&gt;
:Compulsory: No&lt;br /&gt;
:Desc: Sets the priority of the sound, if their are not enough sound channels available higher priority sounds will be played first. Defaults to 1, can be negative.&lt;br /&gt;
&lt;br /&gt;
====repeat-delay====&lt;br /&gt;
:Type: Decimal Pair&lt;br /&gt;
:Default: 0,0&lt;br /&gt;
:Compulsory: No&lt;br /&gt;
:Desc: Time range (in seconds) to delay, after the sound finishes playing, before playing the sound again. To set a constant delay either set both these values the same or only provide one of them, otherwise a random value between them will be chosen. When used with a trigger event (see the &#039;trigger&#039; tag), a positive value indicates that the sound should not repeat, but should wait until triggered again.&lt;br /&gt;
&lt;br /&gt;
====sound====&lt;br /&gt;
:Type: Container&lt;br /&gt;
:Default: {}&lt;br /&gt;
:Compulsory: Yes&lt;br /&gt;
:Desc: Contains list of the sound files to play. If the list has more than one entry then one file will be picked at random from the list.  The value of each tag in this container is the filename of a WAV sound file.  Filenames are relative to the base directory of the asset, i.e. relative to the location of the config file.&lt;br /&gt;
&lt;br /&gt;
:Valid WAV files are:&lt;br /&gt;
:* Uncompressed.&lt;br /&gt;
:* 8 or 16 bit&lt;br /&gt;
:* Mono, Stereo or Surround&lt;br /&gt;
&lt;br /&gt;
:Sampling rate can be 22kHz (22,050Hz) or 44kHz (44,100Hz).  The higher sampling rate doubles the size of the file for no significant improvement in quality, and is not recommended.  For some purposes there are additional requirements - for instance directional sounds must be mono.&lt;br /&gt;
&lt;br /&gt;
====sound-asset====&lt;br /&gt;
:Type: KUID&lt;br /&gt;
:Compulsory: No&lt;br /&gt;
:Desc: The asset to source the sound files from. Allows the creation of &amp;quot;sound library&amp;quot; assets, so that sound files can be shared between multiple other assets. Defaults to the current asset.&lt;br /&gt;
&lt;br /&gt;
====trigger====&lt;br /&gt;
:Type: String&lt;br /&gt;
:Default: &amp;quot;&amp;quot;&lt;br /&gt;
:Compulsory: No&lt;br /&gt;
:Desc: The &#039;trigger&#039; tag gives your sound a name that can allow it to be played from [[Scripting|TrainzScript]] (see: Class MapObject), animations and certain predefined events. (At least one of these &amp;quot;predefined events&amp;quot; is to use the word &amp;quot;toggle&amp;quot; when including a soundscript container in the config.txt of a &amp;quot;MOjunction&amp;quot;.  This will make the sound fire each time the turnout is switched)&lt;br /&gt;
&lt;br /&gt;
====value-range====&lt;br /&gt;
:Type: Float pair&lt;br /&gt;
:Default: 0,0 (off)&lt;br /&gt;
:Compulsory: No&lt;br /&gt;
:Desc: 2 numbers, where the numbers are not the same, which set the start and end times for the sound to play. Midnight is 0.5, midday = 0.0 or 1.0. (TBD.  This is a bit vague.)&lt;br /&gt;
&lt;br /&gt;
====volume====&lt;br /&gt;
:Type: Decimal&lt;br /&gt;
:Default: 1&lt;br /&gt;
:Compulsory: No&lt;br /&gt;
:Desc: Specifies the volume gain of the sound. Defaults to 1 (100%).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Example Config.txt==&lt;br /&gt;
Sample [[config.txt file]] for a map asset that has a different day and night background sounds:&lt;br /&gt;
&lt;br /&gt;
  kind map&lt;br /&gt;
  kuid &amp;lt;KUID:0:0&amp;gt;&lt;br /&gt;
  soundscript&lt;br /&gt;
  {&lt;br /&gt;
    morning&lt;br /&gt;
    {&lt;br /&gt;
      ambient 1&lt;br /&gt;
      value-range 1, 0.1&lt;br /&gt;
      volume 0.3&lt;br /&gt;
      sound&lt;br /&gt;
      {&lt;br /&gt;
        0 &amp;quot;ctry_day_1.wav&amp;quot;&lt;br /&gt;
        1 &amp;quot;ctry_day_2.wav&amp;quot;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    night&lt;br /&gt;
    {&lt;br /&gt;
      ambient 1&lt;br /&gt;
      value-range 0, 0.9&lt;br /&gt;
      volume 0.3&lt;br /&gt;
      sound&lt;br /&gt;
      {&lt;br /&gt;
        0 &amp;quot;night_loop.wav&amp;quot;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
==Categories==&lt;br /&gt;
[[Category:Config Container|Soundscript container]]&lt;br /&gt;
{{ORP-bot|Soundscript container}}&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=Trainz_Life-Cycle_Policy&amp;diff=17417</id>
		<title>Trainz Life-Cycle Policy</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=Trainz_Life-Cycle_Policy&amp;diff=17417"/>
		<updated>2019-01-29T07:03:52Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;N3V Games typically maintain support for major product releases for at least four years from the initial release date. This is known as the &amp;quot;end-of-support&amp;quot; date for the product. Support includes the following areas:&lt;br /&gt;
&lt;br /&gt;
* Product-specific information, downloads, and utilities on the N3V Games web site.&lt;br /&gt;
* Product assistance through the N3V Games Helpdesk.&lt;br /&gt;
* Maintenance of product-specific forums.&lt;br /&gt;
* Access to the [[Download Station]].&lt;br /&gt;
* Access to upload content to the [[Download Station]] &lt;br /&gt;
* Access to the iTrainz network.&lt;br /&gt;
* Access to other product-specific network services.&lt;br /&gt;
&lt;br /&gt;
At the end-of-support date for a given product release (or at any time thereafter), some or all of the above services MAY be withdrawn at N3V Games&#039;s discretion. Users are encouraged to upgrade to a more recent version of Trainz to maintain support.&lt;br /&gt;
&lt;br /&gt;
= Upgrades to Trainz Versions =&lt;br /&gt;
Prior to a new &amp;quot;Version&amp;quot; of Trainz being released (i.e. a new release with a new name), there may be one or more Service Pack released (i.e. game patches). These free updates provide a variety of fixes, improvements and upgrades to a product. A Service Pack will generally increment the [[&amp;quot;Trainz-build&amp;quot; tag]] as these usually contain changes to the way content is configured or validated.&lt;br /&gt;
&lt;br /&gt;
Once a Service Pack is released, we no longer test against older builds so we strongly recommend all Service Packs are applied to ensure you are using the latest, fully supported version. If any retrograde issues are identified, we may also release a &amp;quot;Hotfix&amp;quot; update to resolve the issue immediately (i.e. without waiting for a group of fixes or improvements) but these hotfixes will always be only for the latest version.&lt;br /&gt;
&lt;br /&gt;
Please remember that “not-supported” does not mean the product is “unusable” or &amp;quot;broken&amp;quot;, but rather it means that we do not test against that build nor release updates for it.&lt;br /&gt;
&lt;br /&gt;
= End-of-support Dates =&lt;br /&gt;
&lt;br /&gt;
The following end-of-support dates are formally acknowledged, and as of May 2015, 3 months advance notice will be provided prior to any changes to support.&lt;br /&gt;
&lt;br /&gt;
{| border=1 cellpadding=2 cellspacing=0&lt;br /&gt;
|&#039;&#039;&#039;Product&#039;&#039;&#039;||&#039;&#039;&#039;End-of-support Date&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|[[Trainz 1.0]]||September 2010&lt;br /&gt;
|-&lt;br /&gt;
|[[UTC]]||September 2010&lt;br /&gt;
|-&lt;br /&gt;
|MSTS Regional Add-on Pack: USA and Canada Volume 1||September 2010&lt;br /&gt;
|-&lt;br /&gt;
|Microsoft Train Simulator Paint Shed||September 2010&lt;br /&gt;
|-&lt;br /&gt;
|Content Creation Art Source||September 2010&lt;br /&gt;
|-&lt;br /&gt;
|[[TRS2004]]||September 2010&lt;br /&gt;
|-&lt;br /&gt;
|Trainz Driver||September 2010&lt;br /&gt;
|-&lt;br /&gt;
|[[TRS2006]]||September 2010&lt;br /&gt;
|-&lt;br /&gt;
|Trainz Routes 1,2,3,4||September 2010&lt;br /&gt;
|-&lt;br /&gt;
|Trainz Collection||September 2010&lt;br /&gt;
|-&lt;br /&gt;
|Trainz Paintshed||September 2010&lt;br /&gt;
|-&lt;br /&gt;
|[[TC1|Trainz Classics 1]] (Harlem Line)||September 2011&lt;br /&gt;
|-&lt;br /&gt;
|[[TC2|Trainz Classics 2]] (Metropolis)||September 2011&lt;br /&gt;
|-&lt;br /&gt;
|[[TC3|Trainz Classics 3]] (Settle &amp;amp; Carlisle)||September 2012&lt;br /&gt;
|-&lt;br /&gt;
|[[TS2009]] World Builder Edition||September 2014&lt;br /&gt;
|-&lt;br /&gt;
|Treez Content Pack||September 2014&lt;br /&gt;
|-&lt;br /&gt;
|Settle and Carlisle Content Pack||September 2014&lt;br /&gt;
|-&lt;br /&gt;
|Cabon City Content Pack||September 2014&lt;br /&gt;
|-&lt;br /&gt;
|Murchison 2 Content Pack||September 2014&lt;br /&gt;
|-&lt;br /&gt;
|[[TS2010|Trainz Simulator 2010]] (Engineers Edition)||September 2014&lt;br /&gt;
|-&lt;br /&gt;
|[[TS12|Trainz Simulator 12]]||September 2018&lt;br /&gt;
|-&lt;br /&gt;
|[[Trainz Simulator Mac]]||September 2016&lt;br /&gt;
|-&lt;br /&gt;
|[[Trainz Simulator Mac 2]]||September 2018&lt;br /&gt;
|-&lt;br /&gt;
|[[TANE|Trainz: A New Era]]||September 2020&lt;br /&gt;
|-&lt;br /&gt;
|[[TRS19|Trainz Railroad Simulator 2019]]||September 2023&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Q&amp;amp;A =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Q: &#039;&#039;Will the named products continue to operate after the listed end-of-support date?&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;A:&#039;&#039;&#039; We will do nothing specific to prevent the products from operating. However, if they were to stop working for some reason (for example, they were found to be incompatible with the latest Windows Operating System) we would not take any steps to resolve the issue. Additionally, any product features which rely on server support (for example, in-game [[Download Station]] access or iTrainz) may cease functioning correctly.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Q: &#039;&#039;Do you support non-upgraded products after a Service Pack has been released?&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;A:&#039;&#039;&#039; Once we have released a Service Pack update, the product has moved on from where it once was and we can no longer &amp;quot;fully support&amp;quot; the older version. e.g. we will not release an update solely for the older version, only further updates to the latest version. We will support all owners of the product and we will do nothing specific to prevent an non-updated version from operating normally, within reason. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Q: &#039;&#039;Should I always upgrade?&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;A:&#039;&#039;&#039;Service Packs implement additional features and fixes that we believe improve upon the original release. If you do not wish to update to the latest Service Pack release, then you are free to continue using the older version with whatever limitations come with that version. If there are problems identified with older versions that are resolved by upgrading, then the obvious solution is to upgrade.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Q: &#039;&#039;Can I still access the Download Station after the end-of-support date?&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;A:&#039;&#039;&#039; Access granted to you by the unsupported product may be terminated. If you have purchased access through other means (newer products, [[First Class Ticket]], etc.) then your access will continue thanks to these products.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Q: &#039;&#039;Can I still access the Download Station from within Trainz, Trainz Helper, or [[Content Manager]] after the end-of-support date?&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;A:&#039;&#039;&#039; Access to our servers from an unsupported product is not guaranteed, regardless of your level of Download Station access. You may need to download the content separately and then manually move it into the unsupported Trainz installation.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Q: &#039;&#039;Will the Download Station continue to host content for Trainz editions beyond their end-of-support date?&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;A:&#039;&#039;&#039; We will not immediately remove older content from the Download Station, as newer editions of Trainz can still use this content. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Q: &#039;&#039;Will I be able to upload old-format content to the Download Station?&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;A:&#039;&#039;&#039; New uploads to the Download Station must be in a format no older than our oldest supported product. Attempts to upload content with a trainz-build number lower than our oldest supported product will be rejected or will result in the content being flagged for third-party repair. This ensures that legacy formats are cleanly phased out over time.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Q: &#039;&#039;Will my Lifetime First Class Ticket continue to operate if all my registered products are beyond their end-of-support date?&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;A:&#039;&#039;&#039; Yes, we will ensure that all users who have a right to Download Station access can continue to download content. The specific techniques required to download content may change. At the current time, we offer support for using an FCT with the DLS web site to manually download content. We do not offer support for using an FCT with Content Manager (or similar) in an unsupported product. We do not offer support for installing manually-downloaded content into an unsupported product.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Q: &#039;&#039;I recently bought a copy of an unsupported product. Will you give support?&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;A:&#039;&#039;&#039; No. We will not sell products which are nearing the end-of-support date. It may be possible to purchase such a product from a third party through a bargain-bin outlet or similar, however we can not offer support for these products. We expect that the product will continue to operate as normal, and hope that you enjoy your experience with the product will be sufficiently enjoyable that you&#039;ll decide to upgrade to one of our supported products.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Q: &#039;&#039;My only Trainz product will shortly become unsupported. Will my forum access be removed?&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;A:&#039;&#039;&#039; No. We&#039;re not in the business of kicking our loyal users out of the community. We really think it would be beneficial if you upgraded to a supported version of Trainz, but that&#039;s a decision that you&#039;ll have to make. The product-specific forum may be removed, but your overall forum access will remain valid.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Q: &#039;&#039;Will the Download Station website be removed?&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;A:&#039;&#039;&#039; The Download Station website is not tied to a specific product. Our plans for this website are not affected by the end-of-support for any specific Trainz product. Your access to the Download Station is conditional upon having a supported product or other form of access such as a First Class Ticket. We expect to continue support and development of our web services indefinitely, although the exact form of these services may change over time.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Q: &#039;&#039;Is there a list of validation changes by version number?&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;A:&#039;&#039;&#039; No, but we have prepared a non-exhaustive list of [[validation changes]] made in the 5 years after TS2009 was released.&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=Help:VE218&amp;diff=17416</id>
		<title>Help:VE218</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=Help:VE218&amp;diff=17416"/>
		<updated>2019-01-29T07:02:10Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: Created page with &amp;quot;&amp;#039;&amp;#039;&amp;#039;Asset has duplicate attached track at track $(INDEX).&amp;#039;&amp;#039;&amp;#039;  This error results when a KIND SceneryWithTrack-derived asset specifies two or more attached tracks between th...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Asset has duplicate attached track at track $(INDEX).&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This error results when a [[KIND SceneryWithTrack]]-derived asset specifies two or more attached tracks between the same pair of track vertices. This construction is never permitted by Trainz, and so the requested configuration cannot be fulfilled.&lt;br /&gt;
&lt;br /&gt;
Note that in cases where the track vertices move (such as a turntable or transfer table) it may be possible for this scenario to exist only at specific instants within the animation. Current asset validation will only detect this problem if it occurs in the default state of the asset, meaning that it is possible for such an asset to pass validation but still encounter problems at runtime. This should still be considered a fault in the asset construction, as Trainz will not correctly honor such a configuration.&lt;br /&gt;
&lt;br /&gt;
When repairing legacy assets which exhibit this error, the simplistic fix is to remove the duplicate entry. Such a change will, however, result in a different number of attached-track entries which means that existing instances of the asset saved into routes may encounter loader conflicts with the updated asset. If this is found to cause problems in practice, a more robust fix might be to move the duplicate entry to a &amp;quot;harmless&amp;quot; location which resolves the problem without introducing other concerns. &lt;br /&gt;
&lt;br /&gt;
[[Category:Validation Errors]]&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=Session_Rule_Implementation&amp;diff=16839</id>
		<title>Session Rule Implementation</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=Session_Rule_Implementation&amp;diff=16839"/>
		<updated>2018-11-28T04:31:59Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page seeks to clearly define expected script behavior for [[KIND Scenariobehavior|Session Rule assets]]. This focuses specifically on correct behavior from the code perspective, rather than addressing how rules should be designed for best gameplay outcomes.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Legacy Behavior Note =&lt;br /&gt;
Please note that many existing rules do not behave correctly as defined here. This is considered a bug in the individual session rules. [[N3V Games]] has a policy of updating session rules to behave correctly even where that may lead to changes of function in existing [[session]] assets. Where reasonable to achieve, emulation of the existing (buggy) behavior may occur for existing rule instances in existing sessions, however any newly created rule instances will use the corrected behavior.&lt;br /&gt;
&lt;br /&gt;
These expectations were codified at the end of [[TS12]] development due to an increasing inability of session rules to work together resulting from the unpredictable nature of their responses to various common use-cases. The systems as a whole, including most of the core rules discussed in this document, have existed for far longer than this document. The document does not redefine any existing systems, but simply presents the only reasonable implementation approach possible if rules are to be expected to work properly in all use-cases. In some cases we also choose to mandate specific points of behavior relating to user expectations rather than technical necessities.&lt;br /&gt;
&lt;br /&gt;
Certain additional API mechanisms were introduced alongside the development of this document, to allow better communication with session authors regarding the differences in behavior between certain types of rule. The correct usage for these mechanisms is also included in this document.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= The Rule Hierarchy =&lt;br /&gt;
All rules within a given session form a simple tree structure.&lt;br /&gt;
&lt;br /&gt;
== Rule State Flags ==&lt;br /&gt;
Each rule in the tree may have certain associated state flagged, including a combination of the following:&lt;br /&gt;
&lt;br /&gt;
=== PAUSED ===&lt;br /&gt;
The rule is currently paused, meaning that it does not affect the game world in any way and does not respond to any changes in the game world. The parent rule must cause the rule to become unpaused for the rule to have any effect. It is not correct behavior for a rule to unpause itself.&lt;br /&gt;
&lt;br /&gt;
=== COMPLETE ===&lt;br /&gt;
This flag indicates that rule has fully completed its operation (including any child rule operations) and does not affect the game world in any way. This flag is set by the rule itself, not by an outside entity such as the parent. This state should not be changed while the rule is PAUSED.&lt;br /&gt;
&lt;br /&gt;
Being COMPLETE does not imply being PAUSED. In many scenarios, the parent rule may respond to a child becoming COMPLETE by causing it to also become PAUSED, however this is certainly not guaranteed in all cases, and is not guaranteed to be immediate in the cases where it does happen.&lt;br /&gt;
&lt;br /&gt;
The rule may optionally respond to specific changes in the game world by deflagging the COMPLETE status. For example, a rule which specifically implements a condition check may choose to become COMPLETE when that condition is met, but return to an incomplete state when the condition is no longer met (again, remembering that a change in either direction should only happen while the rule itself is not PAUSED).&lt;br /&gt;
&lt;br /&gt;
When a rule&#039;s COMPLETE state is changed via ScenarioBehavior.SetComplete(), a &amp;quot;ScenarioBehavior&amp;quot;, &amp;quot;Touch&amp;quot; message is sent to its parent rule (if any), unless the parent is in the PAUSED state. This allows the parent to react to changes in its child rules&#039; states. It is important to note that the message indicates a possible change which the parent may be interested in, but it is the parent rule&#039;s responsibility to determine whether the state change is worth reacting to.&lt;br /&gt;
&lt;br /&gt;
=== WAS COMPLETE ===&lt;br /&gt;
This is typically set when a rule first becomes flagged as COMPLETE, and will stay set even if the rule later flags as incomplete. This can be used by a parent which only cares that the child rule has been flagged as COMPLETE at some point, rather than caring what its current completion status is.&lt;br /&gt;
&lt;br /&gt;
=== DOES COMPLETE ===&lt;br /&gt;
This indicates whether the rule can ever reach the COMPLETE state. Its value is constant for a given rule configuration, and does not change based on the runtime rule state or other game state. Rules which are flagged as DOES COMPLETE are expected to become complete after some discreet operations are completed. Rules which are not flagged are expected to run indefinitely unless PAUSED by an external agent (such as the parent rule).&lt;br /&gt;
&lt;br /&gt;
== Initial State ==&lt;br /&gt;
All rules are initially in the PAUSED state when in [[Surveyor]], and only become unpaused after gameplay begins in a [[Driver]] session. Since a PAUSED rule is not permitted to unpause itself, this is a stable state which will persist until the native code takes step to begin program flow.&lt;br /&gt;
&lt;br /&gt;
== Top Level Rules ==&lt;br /&gt;
All rules at the top level (ie. rules which are not a child of any other rule) simultaneously become unpaused after the session has loaded into Driver. Some of these rules may take initial setup steps and then become COMPLETE. Some of these rules may begin monitoring for specific game conditions before taking any further action. Some of these rules may begin taking action immediately. The rules are not sequenced against each other in any way, and it is the session author&#039;s responsibility to ensure that this does not cause any conflicts.&lt;br /&gt;
&lt;br /&gt;
== Scheduling ==&lt;br /&gt;
Since the script VM is a cooperatively-threaded environment, it is technically true that rule evaluation will occur in an ordered manner rather than truly simultaneously. However, no guarantees are made regarding the order in which the simultaneously-running rules will perform their checks or outcomes. Since rules may wait internally rather than fulfilling their entire purpose in an atomic operation, it is also not guaranteed that a first-running rule will fully complete before some other simultaneously-executing rule begins completion. In short, if order-of-execution is critical to the correct behavior of a session, then the order should be enforced by the session creator using the rule hierarchy rather than by making assumptions about execution order of simultaneously-running rules.&lt;br /&gt;
&lt;br /&gt;
(Note: with the introduction of [[Asynchronous Route Streaming]], this is even more true than previously. What may have been a near-instantaneous operation in older builds may now require a wait of several seconds while the necessary data is streamed in.)&lt;br /&gt;
&lt;br /&gt;
It is important to note that some conditional rules may partially or completely rely on a polling behavior to evaluate their conditions. (An example of partial reliance is a rule which waits for an event, but then evaluates a condition to clarify whether the event should be acted upon.) In these cases, it is possible that the condition can rapidly become true and then become false again without the rule responding. This results in an uncertainty as to whether the conditional rule will correctly detect a given instance of the condition. This type of scenario should be avoided completely where possible, and should most definitely be limited to outcomes that do not significantly affect gameplay.&lt;br /&gt;
&lt;br /&gt;
For a hypothetical example, if the player&#039;s train speeds for 0.5sec, and a speeding check rule was implemented that polled every second, then the overspeed event may or may not trigger on any given occurrence. A session creator should not use this outcome as a failure condition, since some players may be able to speed without penalty, whereas other players would be penalised on the first attempt. A sensible solution in this case might be to increment a counter while speeding is detected, and only take action if the counter reaches a certain threshold. If the only penalty was a warning to the player which had no actual gameplay impact, then it might be acceptable to forgo this check and simply accept that some players will receive a warning where others may not.&lt;br /&gt;
&lt;br /&gt;
==Child Rules==&lt;br /&gt;
As with all other rules, child rules (ie. those that have parent rules in the hierarchy) start out in the PAUSED state. They do not become unpaused until the parent is ready for the children to start operating. Exactly when this occurs depends on the specific parent rule, but the general flow is the same for all rules:&lt;br /&gt;
&lt;br /&gt;
1. Parent rule becomes unpaused and begins operation.&lt;br /&gt;
&lt;br /&gt;
2. Parent rule configures any necessary world state changes.&lt;br /&gt;
&lt;br /&gt;
3. Parent rule optionally waits for a specific condition to occur.&lt;br /&gt;
&lt;br /&gt;
4. Parent rule begins executing its children. This involves unpausing one or more of the children (as discussed below in &amp;quot;Parent Rule Styles&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
5. Parent waits for its children to complete (as discussed below in &amp;quot;Parent Rule Styles&amp;quot;) and then pauses the children.&lt;br /&gt;
&lt;br /&gt;
6. Parent flags itself as COMPLETE.&lt;br /&gt;
&lt;br /&gt;
This process allows program control flow to pass from a top-level rule, to its immediate children, to their immediate children, and so on. As the bottom-level children become complete, completion flows back to the higher level children until finally the top-level rules become COMPLETE.&lt;br /&gt;
&lt;br /&gt;
It is worth noting that there is nothing special about a top-level rule being flagged as COMPLETE. This does not indicate an end-of-session or any other fundamental gameplay mode change. Since the pausing of rules on completion is handled by the parent rule (see step 5 above), the top-level rules never become PAUSED on completion.&lt;br /&gt;
&lt;br /&gt;
==Parent Rule Styles==&lt;br /&gt;
There are a few common techniques with which parent rules interact with their children. Rules should always fit one of these descriptions. The vast majority of rules should follow either the &amp;quot;Does Not Support Children&amp;quot; style, or the &amp;quot;Ordered Execution of Children&amp;quot; style.&lt;br /&gt;
&lt;br /&gt;
=== Does Not Support Children ===&lt;br /&gt;
The rule is incapable of supporting children and will always ignore them.&lt;br /&gt;
&lt;br /&gt;
This is used for trivial rules which perform a set function and then become permanently COMPLETE. Such rules are not conditional and do not wait for any world state changes except those which they initiate internally.&lt;br /&gt;
The rule should be configured to validate and/or enforce that no child rules can be added.&lt;br /&gt;
&lt;br /&gt;
=== Simultaneous Execution of Children ===&lt;br /&gt;
When the rule is ready to begin executing children, it unpauses all children simultaneously. The rule then waits for all children to flag as WAS COMPLETE. Once this is detected, the rule pauses all children and flags itself as COMPLETE.&lt;br /&gt;
This is used for rules which have a specific need to simultaneously execute children, such as the &amp;quot;Simultaneous List&amp;quot; rule.&lt;br /&gt;
&lt;br /&gt;
The rule editor interface should be explicit that child rules will be executed simultaneously. Child rules should be tagged appropriately in the rule editor list to denote unordered execution.&lt;br /&gt;
&lt;br /&gt;
=== Ordered Execution of Children ===&lt;br /&gt;
When the rule is ready to begin executing children, it iterates through the children in top-to-bottom order. If the child is flagged as WAS COMPLETE, the child is paused and iteration continues. If the child is not flagged as WAS COMPLETE, the child is unpaused and iteration ends. Whenever a child state change is detected, this process is repeated from the start. Once iteration passes over all children without leaving any child unpaused, the rule flags itself as COMPLETE.&lt;br /&gt;
&lt;br /&gt;
This style is used for all rules which do not explicitly fall under one of the other styles described here. Almost all third-party rules will follow this style. Implementing one of the other styles without there being a fundamental requirement to do so is considered a programming error.&lt;br /&gt;
&lt;br /&gt;
Rules which follow this style should derive from [[ConditionalScenarioBehavior]] in order to avoid re-implementing the control flow logic, as it is exceedingly complex to implement correctly. Any rules which do not derive from ConditionalScenarioBehavior should be accompanied by a clear explanation of the reasons that ConditionalScenarioBehavior is an unsuitable base class for the intended behavior. Rules which do derive from ConditionalScenarioBehavior should avoid complex overrides of the default logic.&lt;br /&gt;
&lt;br /&gt;
Child rules should be tagged appropriately in the rule editor list to denote execution order.&lt;br /&gt;
&lt;br /&gt;
=== Controlled Selection of a Single Child ===&lt;br /&gt;
When the rule is ready to begin executing children, it selects a single child and unpauses it. All other children remain paused. Once the selected child becomes flagged as WAS COMPLETE, the child is paused and the rule flags itself as COMPLETE.&lt;br /&gt;
&lt;br /&gt;
This style is used where complex conditional selection of child rules is required. This can be used to implement an &amp;quot;if-else&amp;quot; logic flow, a &amp;quot;switch-case&amp;quot; logic flow, or the &amp;quot;Random List&amp;quot; rule. This style should not be used to implement a simple &amp;quot;if&amp;quot; logic flow, because that would unnecessarily restrict the rule to a single child where the &amp;quot;Ordered Execution of Children&amp;quot; style would provide the same functionality while allowing multiple children.&lt;br /&gt;
The rule editor interface should be very explicit about how the child rules will be selected. Child rules should be tagged appropriately in the rule editor list to avoid the user attempting to fit a child rule into the wrong role.&lt;br /&gt;
&lt;br /&gt;
=== Custom Execution with Multiple Children ===&lt;br /&gt;
This style is used for very specific custom-purpose rules, such as a passenger station stop handler. Such rules should give a clear and complete explanation of their operation and their interaction with any child rules in the rule editor interface.&lt;br /&gt;
&lt;br /&gt;
Individual child rules may be executed in an ad-hoc manner by the rule in response to changes in game state. Child rules may or may not be executed simultaneously and may or may not be executed repeatedly depending on the rule; any limitations or gotchas deriving from this should be carefully explained in the rule editor interface.&lt;br /&gt;
&lt;br /&gt;
Child rules should be tagged appropriately in the rule editor list to avoid the user attempting to fit a child rule into the wrong role.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Early Termination via Pause =&lt;br /&gt;
A rule must accept being paused by its parent at any time. This should cause the rule to cease any game state monitoring or other direct effects. The rule must pause all child rules immediately.&lt;br /&gt;
&lt;br /&gt;
In cases where the rule is maintaining some reversible effect on the game world, pausing the rule should end this effect. For example, a rule which displays a message to the user should typically hide the message upon becoming paused, and a rule which causes a rain storm in a specific area should return the weather to normal upon becoming paused. Rules which make a single permanent change to the game world and then immediately flag as COMPLETE should not attempt to reverse the change upon becoming paused. Examples of these rules include configuration of the global weather conditions, or a rule which increments the player&#039;s score or penalty counter.&lt;br /&gt;
&lt;br /&gt;
It is important to note that any pause is resumable, although the parent may not choose to take advantage of this. Pausing a rule followed by unpausing it should result in the rule continuing operation where it left off. The notes on Saving and Loading Driver Sessions (below) are worth considering when evaluating techniques for implementing pause.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Early Termination via Internal Logic =&lt;br /&gt;
In some cases, a rule may begin executing child rules but then make an internal decision to abort execution. This typically occurs in conditional rules where the condition may be re-evaluated as false after it has already been evaluated as true. Such behavior should be made explicit in the rule editor interface and should usually be made optional by providing a checkbox.&lt;br /&gt;
&lt;br /&gt;
There are in fact several possible behavioral variants affecting how condition-deflag is interpreted:&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules and no further evaluation is performed. The rule eventually flags itself as COMPLETE and does not later deflag this.&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules. If the condition becomes deflagged, the child rules are paused. If the condition becomes flagged again, the child rules are continued. Once the child rules have fully completed execution, the rule flags itself as COMPLETE and does not later deflag this.&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules. If the condition becomes deflagged, the child rules are paused. If the condition becomes flagged again, the children are reset and execution starts anew. The rule flags itself as COMPLETE if all children successfully complete, but it will deflag if the condition deflags.&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules. If the condition becomes deflagged, the child rules continue executing. If the condition becomes flagged again, the children are reset and execution starts anew. The rule will flag as COMPLETE if all children successfully complete, but it will deflag if the condition deflags.&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules. The child rules continue execution with no regard for whether the condition changes between flagged or deflagged in either direction. If the condition transitions from deflagged to flagged again after the children have completed, the children are reset and execution starts anew. The rule will flag as COMPLETE if all children successfully complete, but it will deflag itself if the condition deflags. &lt;br /&gt;
&lt;br /&gt;
The complexity here derives from the fact that it is not possible to use the same set of rules multiple times concurrently for different trigger conditions. For example, if a set of rules is used to give demerit points and provide user notifications, and those rules live under a single conditional check which determines whether a train is speeding, it may be difficult to define what should happen if two trains are detected as speeding at the same time, or if a train stops speeding while the notification process is still in progress. It is not always possible to achieve a perfect solution to tracking multiple objects using a single set of rules, but correct selection from the above behaviors can minimise the possibility of serious side-effects.&lt;br /&gt;
&lt;br /&gt;
It is important to note that these behaviors describe how the rule reacts to internal condition checks. The rule&#039;s reaction to being paused by its parent is discussed above under &amp;quot;Early Termination via Pause&amp;quot; and is not affected by the description here.&lt;br /&gt;
&lt;br /&gt;
In short, there are many ways of handling this, and the important thing is for your (parent) rule to clearly explain which approach it is going to use.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Rule Reset =&lt;br /&gt;
A rule may be &#039;&#039;reset&#039;&#039; by its parent. This causes both the COMPLETE and WAS COMPLETE states to be deflagged. Individual rules may also react to the reset by modifying their internal state to forget past or present actions. Parent rules must also cause their children to be reset in turn.&lt;br /&gt;
&lt;br /&gt;
This mechanism is used to permit rules to be used in a repeating scenario, such as responding to a condition which can occur multiple times, or in a repeating loop. At some point after a rule has become flagged as WAS COMPLETE, it will typically become paused and will not be unpaused again. If the rule is to be included in some repeating behavior, this would normally prevent the behavior from operating successfully after the first run through. To avoid this, the parent rule responsible for implementing the repeating behavior will &#039;&#039;reset&#039;&#039; all children when a repeat occurs. This effectively cleans the rules back to their initial state ready to perform their roles again.&lt;br /&gt;
&lt;br /&gt;
It is important to note that a reset should cause the rule to return to its configured settings. For example, if a timer value is configured and is decremented during rule operation, the timer must be reset back to its initial value during rule reset.&lt;br /&gt;
&lt;br /&gt;
It is important to note that there is no requirement to pause a rule prior to resetting it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Saving and Loading Driver Sessions =&lt;br /&gt;
For better or worse, the script VM does not persist across a save/load operation. This means that each rule must correctly save both its configuration state and its runtime state, and must correctly reload those such that the state after a save/load operation is indistinguishable from the original state. The following aspects of the script state must be considered:&lt;br /&gt;
&lt;br /&gt;
* Member variables in the Rule instance.&lt;br /&gt;
* Which threads are running on the Rule instance, and where they are up to in the code flow.&lt;br /&gt;
* Local variables on the stack of each running thread.&lt;br /&gt;
* Non-persistent changes made to the state of other script objects (such as active &#039;sniff&#039; statements).&lt;br /&gt;
* Script Messages which might be in flight at the time of save (these are not persisted, so the net effect is that they are simply deleted between the save and the load.)&lt;br /&gt;
&lt;br /&gt;
Since the game state continues normal operation after a Save, no code flow or other behavioral changes should result from the Save operation itself. Instead, the Save operation (and the design of the rule as a whole) is responsible for ensuring that sufficient data is persisted in the save file such that the Load operation is able to restore to the correct running state.&lt;br /&gt;
&lt;br /&gt;
The rule base class, ScenarioBehavior, is responsible for saving and loading the rule state flags (COMPLETE, PAUSED, WAS COMPLETE, etc.) A rule which was paused at Save time will still be paused after the Load. A rule which was complete at Save time will still be complete after the Load. During a Load operation, the rule should inherit the parent class&#039; SetProperties() method so that these flags are correctly configured, then honor the paused state during the rest of the loading process.&lt;br /&gt;
&lt;br /&gt;
It is rarely appropriate for an unpaused rule to simply restart execution from the beginning. Care must be taken to ensure that execution resumes from the point that it left off at the time of saving. This process can be simplified by keeping as much state as possible in the rule member variables at all times, and only keeping reconstructible temporary values on the stack. If the member variables are correctly stored and restored, this approach will allow the loading process to detect the runtime state of the rule and resume any necessary threads, which will in turn be able to jump forward to the correct area of the code based on the stored state.&lt;br /&gt;
&lt;br /&gt;
Finally, the COMPLETE, WAS COMPLETE, and PAUSED flags on child rules should be honored. This is typically sufficient information to determine the running state of child rules, so no further state will generally need to be maintained. More accurately, the child rules take care of their own state at all times, and the parent only needs to react to changes in the child state. Since no child state change occurs across a Save/Load operation, the parent does not need to become involved.&lt;br /&gt;
&lt;br /&gt;
For rules which derive ConditionalScenarioBehavior, the majority of load/save logic is handled automatically. The only state information that such a rule should typically preserve is the instance-specific configuration data. The condition-monitor thread will be automatically restarted as required, and there is generally no need to distinguish between a first-startup and any subsequent startup.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Spurious Events =&lt;br /&gt;
There are various events (typically script messages) that a rule may listen for in order to detect state changes. It is important to note that spurious events are often possible, and that an event handler should often be coupled with a condition check. As a specific example, the &amp;quot;ScenarioBehavior&amp;quot;, &amp;quot;Touch&amp;quot; message typically indicates that a child state has changed, but the message may in fact be sent at any time. This message should prompt the rule to evaluate whether any state changes are necessary, but the rule should not simply assume that a state change is necessary without performing an evaluation.&lt;br /&gt;
&lt;br /&gt;
Similarly, calls to a function such as Pause() may in some cases have no effect. For example, if a rule is already executing and its parent calls Pause(false), the rule should not pause, reset, or change state in any way at all. Similarly, if a rule is already paused and its parent calls Pause(true), the rule should not unpause, reset, fire any events, or otherwise change state in any way at all.&lt;br /&gt;
&lt;br /&gt;
The short version is: do not assume that every event and every method call is supposed to achieve something meaningful. Check first, and if the event is meaningless to you then do nothing at all.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Future Considerations =&lt;br /&gt;
Rules should base their functionality on the state flags such as the PAUSED state, rather than attempting to detect and vary their functionality based on the state of the game.&lt;br /&gt;
&lt;br /&gt;
For example, we currently (in development builds) expose the rules editor in Driver for debugging purposes. This, or some mechanism like it, is likely to be included in public builds in the future. Rules should not assume that it is impossible to be reconfigured during gameplay. This will of course introduce some side effects, such as when an unpaused rule is modified during execution. It is the rule&#039;s responsibility to ensure that these side effects do not lead to script exceptions or to leaked state. For example, if a single thread is supposed to be running, reconfiguring the rule should not cause a second thread to run simultaneously. If a rule sniffs a target vehicle, and the target vehicle is redefined, then the rule should unsniff the original vehicle rather than now sniffing two vehicles.&lt;br /&gt;
&lt;br /&gt;
Likewise, we may in future allow some form of partial state swap between Driver and Surveyor. Rules should not assume that it is impossible to change from any one game state or module to any other game state or module, just because it is not possible at the current time. APIs already exist to detect such state changes where necessary, and in most cases it&#039;s simply not necessary to care whether your rule is in Surveyor or Driver - you should act based on the PAUSED state instead. Rules should deal with the game state as they find it rather than assuming that certain states will not ever occur.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Gotchas =&lt;br /&gt;
There are a few potential gotchas in the script environment that are worth considering when writing any non-trivial rule.&lt;br /&gt;
&lt;br /&gt;
== Response Latency ==&lt;br /&gt;
Scripts tend to rely heavily on message passing and threading. In both cases, there is a delay between triggering a certain behavior (eg. posting an event, or calling a threaded function) and having the receiving code react. Other code may execute during this delay.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
// Calling this might be expected to start and then stop the thread; in reality it&lt;br /&gt;
// will likely simply start the thread and leave it running, because the message&lt;br /&gt;
// is sent prior to the wait() statement starting.&lt;br /&gt;
void DemonstrateBug1(void)&lt;br /&gt;
{&lt;br /&gt;
  Pause(false);&lt;br /&gt;
  Pause(true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// In this case, we use a Sleep() statement to &amp;quot;ensure&amp;quot; that the thread has&lt;br /&gt;
// finished starting. This isn&#039;t actually reliable, but it works as long as the&lt;br /&gt;
// system isn&#039;t under too much load. We follow this up with a rapid pause-&lt;br /&gt;
// unpause sequence. As above, this doesn&#039;t work - the message is sent,&lt;br /&gt;
// then the function immediately checks whether the thread is still running&lt;br /&gt;
// (which it is) and thus the thread isn&#039;t restarted. The function completes,&lt;br /&gt;
// and finally the thread receives the message and exits.&lt;br /&gt;
void DemonstrateBug2(void)&lt;br /&gt;
{&lt;br /&gt;
  Pause(false);&lt;br /&gt;
  Sleep(1.0);&lt;br /&gt;
  Pause(true);&lt;br /&gt;
  Pause(false);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Helper code for the above functions.&lt;br /&gt;
void Pause(bool bIsPaused)&lt;br /&gt;
{&lt;br /&gt;
  if (bIsPaused)&lt;br /&gt;
  {&lt;br /&gt;
    PostMessage(me, &amp;quot;ThisRule&amp;quot;, &amp;quot;Pause&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  else if (!m_bIsThreadRunning)&lt;br /&gt;
  {&lt;br /&gt;
    m_bIsThreadRunning = true;&lt;br /&gt;
    StartThread();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
thread void StartThread(void)&lt;br /&gt;
{&lt;br /&gt;
  while (true)&lt;br /&gt;
  {&lt;br /&gt;
    wait ()&lt;br /&gt;
    {&lt;br /&gt;
    on &amp;quot;ThisRule&amp;quot;, &amp;quot;Pause&amp;quot;:&lt;br /&gt;
      break;&lt;br /&gt;
     ...&lt;br /&gt;
  }&lt;br /&gt;
  m_bIsThreadRunning = false;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Multiple Messages in Flight ==&lt;br /&gt;
It&#039;s possible to post multiple identical messages. This can be useful, but if you&#039;re expecting only one then it can be a source of errors.&lt;br /&gt;
&lt;br /&gt;
In the following pseudocode, each call to SetProperties() will place an additional &amp;quot;Timer&amp;quot;, &amp;quot;Tick&amp;quot; message into the cycle, effectively increasing the rate at which the IdleFunction is called. This will seem to be working for a single call to SetProperties(), which may be all that is called during a trivial testcase. It will probably give reasonable results for a few calls to SetProperties(), although if the function is time-sensitive then the results might be different to expectations. After a larger number of calls to SetProperties(), the object&#039;s message queue may become full, causing it to lose messages at random (perhaps the tick messages, or perhaps other unrelated messages that are more problematic).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
void Init(void)&lt;br /&gt;
{&lt;br /&gt;
  inherited();&lt;br /&gt;
  &lt;br /&gt;
  AddHandler(me, &amp;quot;Timer&amp;quot;, &amp;quot;Tick&amp;quot;, &amp;quot;IdleFunction&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void EnterIdleState(void)&lt;br /&gt;
{&lt;br /&gt;
  IdleFunction();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void IdleFunction(void)&lt;br /&gt;
{&lt;br /&gt;
  PostMessage(me, &amp;quot;Timer&amp;quot;, &amp;quot;Tick&amp;quot;, 1.0);&lt;br /&gt;
  .. do something here ..&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void SetProperties(Soup soup)&lt;br /&gt;
{&lt;br /&gt;
  inherited(soup);&lt;br /&gt;
  &lt;br /&gt;
  EnterIdleState();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A similar problem can occur if you start new threads rather than post new messages.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Thread Guard Variables ==&lt;br /&gt;
It&#039;s common to prevent a singleton thread from being started twice by using a boolean guard variable. Care must be taken to ensure that the guard variable is set and cleared at the correct locations, or they may be ineffective.&lt;br /&gt;
&lt;br /&gt;
The following pseudocode demonstrates one such correct usage. The key points to note are:&lt;br /&gt;
* We set &#039;m_bIsThreadedFunctionRunning&#039; prior to calling the threaded function. Setting it within the threaded function is too late; multiple threads might have already been started before the first thread reaches that point.&lt;br /&gt;
* We don&#039;t confuse whether the thread is actually running with whether we want the thread to be running. Once we ask a thread to start, we can&#039;t stop it starting. If we change our minds and want to stop it again, we must inform it in a way that it will realise after it finishes starting. In the worst-case scenario, we might flipflop on this multiple times before the thread actually starts.&lt;br /&gt;
* Similarly, we don&#039;t rely on messages to control the thread. Enqueuing a separate start or stop message with each StartThread()/StopThread() call might be possible, and we could clear any unwanted prior messages from the object&#039;s queue, but if the thread hasn&#039;t finished starting then it won&#039;t receive the messages anyway.&lt;br /&gt;
* We do rely on messages to wake the thread if it&#039;s waiting on messages, but we don&#039;t use those messages to imply any state - we just have it recheck the current state boolean to get the very latest info.&lt;br /&gt;
* We clear &#039;m_bIsThreadedFunctionRunning&#039; once the decision to exit has become unconditional. At this point, even though the thread is technically still running, we&#039;ll have to start a new thread if we want the thread to continue running.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
bool m_bIsThreadedFunctionRunning = false;&lt;br /&gt;
bool m_bWantThreadedFunctionRunning = false;&lt;br /&gt;
&lt;br /&gt;
void StartThread(void)&lt;br /&gt;
{&lt;br /&gt;
  m_bWantThreadedFunctionRunning = true;&lt;br /&gt;
  &lt;br /&gt;
  if (m_bIsThreadedFunctionRunning)&lt;br /&gt;
    return;&lt;br /&gt;
  &lt;br /&gt;
  m_bIsThreadedFunctionRunning = true;&lt;br /&gt;
  ThreadedFunction();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void StopThread(void)&lt;br /&gt;
{&lt;br /&gt;
  if (!m_bWantThreadedFunctionRunning)&lt;br /&gt;
    return;&lt;br /&gt;
  &lt;br /&gt;
  m_bWantThreadedFunctionRunning = false;&lt;br /&gt;
  PostMessage(me, &amp;quot;Thread&amp;quot;, &amp;quot;Touch&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
thread void ThreadedFunction(void)&lt;br /&gt;
{&lt;br /&gt;
  while (m_bWantThreadedFunctionRunning)&lt;br /&gt;
  {&lt;br /&gt;
    wait()&lt;br /&gt;
    {&lt;br /&gt;
      on &amp;quot;Thread&amp;quot;, &amp;quot;Touch&amp;quot;:&lt;br /&gt;
        break;&lt;br /&gt;
      .. whatever else..&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  m_bIsThreadedFunctionRunning = false;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Not Waiting For Messages ==&lt;br /&gt;
As seen above, it&#039;s possible for a thread to fail to receive posted messages because it wasn&#039;t waiting for them at the time. A more commonly problematic example follows.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
thread void MyThread(void)&lt;br /&gt;
{&lt;br /&gt;
  wait ()&lt;br /&gt;
  {&lt;br /&gt;
    on &amp;quot;Some&amp;quot;, &amp;quot;Condition&amp;quot;:&lt;br /&gt;
      HandleSomeCondition();&lt;br /&gt;
      continue;&lt;br /&gt;
    on &amp;quot;Thread&amp;quot;, &amp;quot;Exit&amp;quot;:&lt;br /&gt;
      break;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void HandleSomeCondition(void)&lt;br /&gt;
{&lt;br /&gt;
  wait ()&lt;br /&gt;
  {&lt;br /&gt;
    on &amp;quot;Some&amp;quot;, &amp;quot;End-Condition&amp;quot;:&lt;br /&gt;
      break;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In this example, the thread is waiting on both &amp;quot;Some&amp;quot;, &amp;quot;Condition&amp;quot; and also &amp;quot;Thread&amp;quot;, &amp;quot;Exit&amp;quot;. Either one will be handled correctly assuming that the thread is already running at the time they are posted. Even if multiple are posted, the thread will simply queue them and run each in turn.&lt;br /&gt;
&lt;br /&gt;
The problem occurs when HandleSomeCondition() is triggered and the thread begins waiting on &amp;quot;Some&amp;quot;, &amp;quot;End-Condition&amp;quot;. In this scenario, the thread is no longer waiting on &amp;quot;Thread&amp;quot;, &amp;quot;Exit&amp;quot;, and any attempt to post that message will simply be ignored. To reiterate: the message dispatch is NOT postponed until the function returns; the message is dropped entirely.&lt;br /&gt;
&lt;br /&gt;
In many cases, the correct behaviour is to move HandleSomeCondition() to a new thread, although that may also carry gotchas that you will need to be careful of (eg. you&#039;ll probably want to terminate the second thread at the same time as the first one, and you may need to consider whether you want multiple of the second thread to run simultaneously or not).&lt;br /&gt;
&lt;br /&gt;
== Performing Actions After Being Told to Stop ==&lt;br /&gt;
In many cases, you may wish to perform cleanup actions when stopping your rule. If your rule is threaded, this can easily become problematic.&lt;br /&gt;
&lt;br /&gt;
Consider the following pseudocode example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
void Pause(bool bIsPaused)&lt;br /&gt;
{&lt;br /&gt;
  if (!bIsPaused &amp;amp;&amp;amp; !m_bIsThreadRunning)&lt;br /&gt;
  {&lt;br /&gt;
    m_bIsThreadRunning = true;&lt;br /&gt;
    MyThread();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
thread void MyThread(void)&lt;br /&gt;
{&lt;br /&gt;
  BeginRule();&lt;br /&gt;
  while (!IsPaused())&lt;br /&gt;
  {&lt;br /&gt;
    Sleep(0.5);&lt;br /&gt;
    UpdateRule();&lt;br /&gt;
  }&lt;br /&gt;
  EndRule();&lt;br /&gt;
  m_bIsThreadRunning = false;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There are three immediately obvious problems:&lt;br /&gt;
&lt;br /&gt;
1. That BeginRule() is called when the thread starts, even if the rule has already been paused again.&lt;br /&gt;
&lt;br /&gt;
2. That UpdateRule() will be called after each sleep, even if the rule was paused during the sleep.&lt;br /&gt;
&lt;br /&gt;
3. That EndRule() will be called after the rule has been paused.&lt;br /&gt;
&lt;br /&gt;
This is very problematic because it likely violates a core principles of the rules system: that rules will not undertake any meaningful behaviour when paused. All three functions may be called while the rule is paused, so unless the rule does nothing meaningful at all, this is a guaranteed violation.&lt;br /&gt;
&lt;br /&gt;
The best approach to resolving this may depend on exactly what these functions do, but one possible solution is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
void Pause(bool bIsPaused)&lt;br /&gt;
{&lt;br /&gt;
  if (bIsPaused)&lt;br /&gt;
  {&lt;br /&gt;
    if (m_bNeedsEndRule)&lt;br /&gt;
    {&lt;br /&gt;
      m_bNeedsEndRule = false;&lt;br /&gt;
      EndRule();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  else&lt;br /&gt;
  {&lt;br /&gt;
    if (!m_bNeedsEndRule)&lt;br /&gt;
    {&lt;br /&gt;
      BeginRule();&lt;br /&gt;
      m_bNeedsEndRule = true;&lt;br /&gt;
    }&lt;br /&gt;
    if (!m_bIsThreadRunning)&lt;br /&gt;
    {&lt;br /&gt;
      m_bIsThreadRunning = true;&lt;br /&gt;
      MyThread();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
thread void MyThread(void)&lt;br /&gt;
{&lt;br /&gt;
  while (!IsPaused())&lt;br /&gt;
  {&lt;br /&gt;
    UpdateRule();&lt;br /&gt;
    Sleep(0.5);&lt;br /&gt;
  }&lt;br /&gt;
  m_bIsThreadRunning = false;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Handler Called while Paused ==&lt;br /&gt;
This one is pretty obvious, but can still catch you out. Handler functions created with AddHandler() will always be called, regardless of whether your rule is paused. You should generally only add your required handlers when your rule is unpaused, and remove them again when paused. If that&#039;s not feasible for some reason, then the alternative is to have you handler function confirm the paused state of the rule before doing any actual work (but keep in mind that this approach wastes CPU time).&lt;br /&gt;
&lt;br /&gt;
== Failing to Inherit from ConditionalScenarioBehavior ==&lt;br /&gt;
This isn&#039;t really a separate gotcha, but it can&#039;t be stressed enough that your rule should inherit from ConditionalScenarioBehavior and should minimise the number of overrides to its default behavior. Apart from the &amp;quot;users expect things to work like this, so that&#039;s what you should do&amp;quot; argument, there are some much more compelling arguments for would-be rule developers:&lt;br /&gt;
&lt;br /&gt;
1. Developing a rule with correct threading behavior is hard. Just have a look at some of the above gotchas. Were you already consciously aware of them all? If not, you&#039;re probably not ready to write your own rule which involves threading. ConditionalScenarioBehavior provides a polling thread mechanism that&#039;s already built, so you can reap the benefits of that approach without having to worry about whether you made any mistakes in the threading code.&lt;br /&gt;
&lt;br /&gt;
2. Developing a rule with correct load/save behavior can be hard. Did you correctly restart your threads when necessary? Did you accidentally restart your threads when you weren&#039;t supposed to? Was there a message in flight during the save which you lost by reloading, and have you handled that loss correctly? ConditionalScenarioBehavior can help with a lot of that kind of thing, leaving you to worry about your rule-specific implementation only.&lt;br /&gt;
&lt;br /&gt;
3. Developing a rule with correct child-rule-handling behavior can be really hard. You need to have a thorough understand of everything listed in this document, and you need to ensure that you don&#039;t make any mistakes which could cause your rule to violate any of the principles in this document, even in edge-case behaviours. Because this is the real world, you also need to handle child rules which don&#039;t necessarily follow the rules to the letter. ConditionalScenarioBehavior does all of this automatically with no effort on your part.&lt;br /&gt;
&lt;br /&gt;
4. Inheriting from ConditionalScenarioBehavior means that many future issues can be fixed automatically by [[N3V Games]] without you having to update your rule. This includes both fixes to our own code (hey, we&#039;re human too) and also new changes to adapt our code to future requirements.&lt;br /&gt;
&lt;br /&gt;
5. Inheriting from ConditionalScenarioBehavior typically means that there&#039;s a lot less semi-custom boilerplate in your rule, making your rule much simpler to read and maintain. This helps you while you&#039;re debugging your own rule, helps you when you&#039;re coming back in a year&#039;s time and wondering how it all worked, and perhaps helps others in the community if they need to update your rule in 10 years time after you&#039;ve moved on from developing Trainz script code.&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=Session_Rule_Implementation&amp;diff=16832</id>
		<title>Session Rule Implementation</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=Session_Rule_Implementation&amp;diff=16832"/>
		<updated>2018-11-27T17:26:22Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: /* Gotchas */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page seeks to clearly define expected script behavior for [[KIND Scenariobehavior|Session Rule assets]]. This focuses specifically on correct behavior from the code perspective, rather than addressing how rules should be designed for best gameplay outcomes.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Legacy Behavior Note =&lt;br /&gt;
Please note that many existing rules do not behave correctly as defined here. This is considered a bug in the individual session rules. [[N3V Games]] has a policy of updating session rules to behave correctly even where that may lead to changes of function in existing [[session]] assets. Where reasonable to achieve, emulation of the existing (buggy) behavior may occur for existing rule instances in existing sessions, however any newly created rule instances will use the corrected behavior.&lt;br /&gt;
&lt;br /&gt;
These expectations were codified at the end of [[TS12]] development due to an increasing inability of session rules to work together resulting from the unpredictable nature of their responses to various common use-cases. The systems as a whole, including most of the core rules discussed in this document, have existed for far longer than this document. The document does not redefine any existing systems, but simply presents the only reasonable implementation approach possible if rules are to be expected to work properly in all use-cases. In some cases we also choose to mandate specific points of behavior relating to user expectations rather than technical necessities.&lt;br /&gt;
&lt;br /&gt;
Certain additional API mechanisms were introduced alongside the development of this document, to allow better communication with session authors regarding the differences in behavior between certain types of rule. The correct usage for these mechanisms is also included in this document.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= The Rule Hierarchy =&lt;br /&gt;
All rules within a given session form a simple tree structure.&lt;br /&gt;
&lt;br /&gt;
== Rule State Flags ==&lt;br /&gt;
Each rule in the tree may have certain associated state flagged, including a combination of the following:&lt;br /&gt;
&lt;br /&gt;
=== PAUSED ===&lt;br /&gt;
The rule is currently paused, meaning that it does not affect the game world in any way and does not respond to any changes in the game world. The parent rule must cause the rule to become unpaused for the rule to have any effect. It is not correct behavior for a rule to unpause itself.&lt;br /&gt;
&lt;br /&gt;
=== COMPLETE ===&lt;br /&gt;
This flag indicates that rule has fully completed its operation (including any child rule operations) and does not affect the game world in any way. This flag is set by the rule itself, not by an outside entity such as the parent. This state should not be changed while the rule is PAUSED.&lt;br /&gt;
&lt;br /&gt;
Being COMPLETE does not imply being PAUSED. In many scenarios, the parent rule may respond to a child becoming COMPLETE by causing it to also become PAUSED, however this is certainly not guaranteed in all cases, and is not guaranteed to be immediate in the cases where it does happen.&lt;br /&gt;
&lt;br /&gt;
The rule may optionally respond to specific changes in the game world by deflagging the COMPLETE status. For example, a rule which specifically implements a condition check may choose to become COMPLETE when that condition is met, but return to an incomplete state when the condition is no longer met (again, remembering that a change in either direction should only happen while the rule itself is not PAUSED).&lt;br /&gt;
&lt;br /&gt;
When a rule&#039;s COMPLETE state is changed via ScenarioBehavior.SetComplete(), a &amp;quot;ScenarioBehavior&amp;quot;, &amp;quot;Touch&amp;quot; message is sent to its parent rule (if any), unless the parent is in the PAUSED state. This allows the parent to react to changes in its child rules&#039; states. It is important to note that the message indicates a possible change which the parent may be interested in, but it is the parent rule&#039;s responsibility to determine whether the state change is worth reacting to.&lt;br /&gt;
&lt;br /&gt;
=== WAS COMPLETE ===&lt;br /&gt;
This is typically set when a rule first becomes flagged as COMPLETE, and will stay set even if the rule later flags as incomplete. This can be used by a parent which only cares that the child rule has been flagged as COMPLETE at some point, rather than caring what its current completion status is.&lt;br /&gt;
&lt;br /&gt;
=== DOES COMPLETE ===&lt;br /&gt;
This indicates whether the rule can ever reach the COMPLETE state. Its value is constant for a given rule configuration, and does not change based on the runtime rule state or other game state. Rules which are flagged as DOES COMPLETE are expected to become complete after some discreet operations are completed. Rules which are not flagged are expected to run indefinitely unless PAUSED by an external agent (such as the parent rule).&lt;br /&gt;
&lt;br /&gt;
== Initial State ==&lt;br /&gt;
All rules are initially in the PAUSED state when in [[Surveyor]], and only become unpaused after gameplay begins in a [[Driver]] session. Since a PAUSED rule is not permitted to unpause itself, this is a stable state which will persist until the native code takes step to begin program flow.&lt;br /&gt;
&lt;br /&gt;
== Top Level Rules ==&lt;br /&gt;
All rules at the top level (ie. rules which are not a child of any other rule) simultaneously become unpaused after the session has loaded into Driver. Some of these rules may take initial setup steps and then become COMPLETE. Some of these rules may begin monitoring for specific game conditions before taking any further action. Some of these rules may begin taking action immediately. The rules are not sequenced against each other in any way, and it is the session author&#039;s responsibility to ensure that this does not cause any conflicts.&lt;br /&gt;
&lt;br /&gt;
== Scheduling ==&lt;br /&gt;
Since the script VM is a cooperatively-threaded environment, it is technically true that rule evaluation will occur in an ordered manner rather than truly simultaneously. However, no guarantees are made regarding the order in which the simultaneously-running rules will perform their checks or outcomes. Since rules may wait internally rather than fulfilling their entire purpose in an atomic operation, it is also not guaranteed that a first-running rule will fully complete before some other simultaneously-executing rule begins completion. In short, if order-of-execution is critical to the correct behavior of a session, then the order should be enforced by the session creator using the rule hierarchy rather than by making assumptions about execution order of simultaneously-running rules.&lt;br /&gt;
&lt;br /&gt;
(Note: with the introduction of [[Asynchronous Route Streaming]], this is even more true than previously. What may have been a near-instantaneous operation in older builds may now require a wait of several seconds while the necessary data is streamed in.)&lt;br /&gt;
&lt;br /&gt;
It is important to note that some conditional rules may partially or completely rely on a polling behavior to evaluate their conditions. (An example of partial reliance is a rule which waits for an event, but then evaluates a condition to clarify whether the event should be acted upon.) In these cases, it is possible that the condition can rapidly become true and then become false again without the rule responding. This results in an uncertainty as to whether the conditional rule will correctly detect a given instance of the condition. This type of scenario should be avoided completely where possible, and should most definitely be limited to outcomes that do not significantly affect gameplay.&lt;br /&gt;
&lt;br /&gt;
For a hypothetical example, if the player&#039;s train speeds for 0.5sec, and a speeding check rule was implemented that polled every second, then the overspeed event may or may not trigger on any given occurrence. A session creator should not use this outcome as a failure condition, since some players may be able to speed without penalty, whereas other players would be penalised on the first attempt. A sensible solution in this case might be to increment a counter while speeding is detected, and only take action if the counter reaches a certain threshold. If the only penalty was a warning to the player which had no actual gameplay impact, then it might be acceptable to forgo this check and simply accept that some players will receive a warning where others may not.&lt;br /&gt;
&lt;br /&gt;
==Child Rules==&lt;br /&gt;
As with all other rules, child rules (ie. those that have parent rules in the hierarchy) start out in the PAUSED state. They do not become unpaused until the parent is ready for the children to start operating. Exactly when this occurs depends on the specific parent rule, but the general flow is the same for all rules:&lt;br /&gt;
&lt;br /&gt;
1. Parent rule becomes unpaused and begins operation.&lt;br /&gt;
&lt;br /&gt;
2. Parent rule configures any necessary world state changes.&lt;br /&gt;
&lt;br /&gt;
3. Parent rule optionally waits for a specific condition to occur.&lt;br /&gt;
&lt;br /&gt;
4. Parent rule begins executing its children. This involves unpausing one or more of the children (as discussed below in &amp;quot;Parent Rule Styles&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
5. Parent waits for its children to complete (as discussed below in &amp;quot;Parent Rule Styles&amp;quot;) and then pauses the children.&lt;br /&gt;
&lt;br /&gt;
6. Parent flags itself as COMPLETE.&lt;br /&gt;
&lt;br /&gt;
This process allows program control flow to pass from a top-level rule, to its immediate children, to their immediate children, and so on. As the bottom-level children become complete, completion flows back to the higher level children until finally the top-level rules become COMPLETE.&lt;br /&gt;
&lt;br /&gt;
It is worth noting that there is nothing special about a top-level rule being flagged as COMPLETE. This does not indicate an end-of-session or any other fundamental gameplay mode change. Since the pausing of rules on completion is handled by the parent rule (see step 5 above), the top-level rules never become PAUSED on completion.&lt;br /&gt;
&lt;br /&gt;
==Parent Rule Styles==&lt;br /&gt;
There are a few common techniques with which parent rules interact with their children. Rules should always fit one of these descriptions. The vast majority of rules should follow either the &amp;quot;Does Not Support Children&amp;quot; style, or the &amp;quot;Ordered Execution of Children&amp;quot; style.&lt;br /&gt;
&lt;br /&gt;
=== Does Not Support Children ===&lt;br /&gt;
The rule is incapable of supporting children and will always ignore them.&lt;br /&gt;
&lt;br /&gt;
This is used for trivial rules which perform a set function and then become permanently COMPLETE. Such rules are not conditional and do not wait for any world state changes except those which they initiate internally.&lt;br /&gt;
The rule should be configured to validate and/or enforce that no child rules can be added.&lt;br /&gt;
&lt;br /&gt;
=== Simultaneous Execution of Children ===&lt;br /&gt;
When the rule is ready to begin executing children, it unpauses all children simultaneously. The rule then waits for all children to flag as WAS COMPLETE. Once this is detected, the rule pauses all children and flags itself as COMPLETE.&lt;br /&gt;
This is used for rules which have a specific need to simultaneously execute children, such as the &amp;quot;Simultaneous List&amp;quot; rule.&lt;br /&gt;
&lt;br /&gt;
The rule editor interface should be explicit that child rules will be executed simultaneously. Child rules should be tagged appropriately in the rule editor list to denote unordered execution.&lt;br /&gt;
&lt;br /&gt;
=== Ordered Execution of Children ===&lt;br /&gt;
When the rule is ready to begin executing children, it iterates through the children in top-to-bottom order. If the child is flagged as WAS COMPLETE, the child is paused and iteration continues. If the child is not flagged as WAS COMPLETE, the child is unpaused and iteration ends. Whenever a child state change is detected, this process is repeated from the start. Once iteration passes over all children without leaving any child unpaused, the rule flags itself as COMPLETE.&lt;br /&gt;
&lt;br /&gt;
This style is used for all rules which do not explicitly fall under one of the other styles described here. Almost all third-party rules will follow this style. Implementing one of the other styles without there being a fundamental requirement to do so is considered a programming error.&lt;br /&gt;
&lt;br /&gt;
Rules which follow this style should derive from [[ConditionalScenarioBehavior]] in order to avoid re-implementing the control flow logic, as it is exceedingly complex to implement correctly. Any rules which do not derive from ConditionalScenarioBehavior should be accompanied by a clear explanation of the reasons that ConditionalScenarioBehavior is an unsuitable base class for the intended behavior. Rules which do derive from ConditionalScenarioBehavior should avoid complex overrides of the default logic.&lt;br /&gt;
&lt;br /&gt;
Child rules should be tagged appropriately in the rule editor list to denote execution order.&lt;br /&gt;
&lt;br /&gt;
=== Controlled Selection of a Single Child ===&lt;br /&gt;
When the rule is ready to begin executing children, it selects a single child and unpauses it. All other children remain paused. Once the selected child becomes flagged as WAS COMPLETE, the child is paused and the rule flags itself as COMPLETE.&lt;br /&gt;
&lt;br /&gt;
This style is used where complex conditional selection of child rules is required. This can be used to implement an &amp;quot;if-else&amp;quot; logic flow, a &amp;quot;switch-case&amp;quot; logic flow, or the &amp;quot;Random List&amp;quot; rule. This style should not be used to implement a simple &amp;quot;if&amp;quot; logic flow, because that would unnecessarily restrict the rule to a single child where the &amp;quot;Ordered Execution of Children&amp;quot; style would provide the same functionality while allowing multiple children.&lt;br /&gt;
The rule editor interface should be very explicit about how the child rules will be selected. Child rules should be tagged appropriately in the rule editor list to avoid the user attempting to fit a child rule into the wrong role.&lt;br /&gt;
&lt;br /&gt;
=== Custom Execution with Multiple Children ===&lt;br /&gt;
This style is used for very specific custom-purpose rules, such as a passenger station stop handler. Such rules should give a clear and complete explanation of their operation and their interaction with any child rules in the rule editor interface.&lt;br /&gt;
&lt;br /&gt;
Individual child rules may be executed in an ad-hoc manner by the rule in response to changes in game state. Child rules may or may not be executed simultaneously and may or may not be executed repeatedly depending on the rule; any limitations or gotchas deriving from this should be carefully explained in the rule editor interface.&lt;br /&gt;
&lt;br /&gt;
Child rules should be tagged appropriately in the rule editor list to avoid the user attempting to fit a child rule into the wrong role.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Early Termination via Pause =&lt;br /&gt;
A rule must accept being paused by its parent at any time. This should cause the rule to cease any game state monitoring or other direct effects. The rule must pause all child rules immediately.&lt;br /&gt;
&lt;br /&gt;
In cases where the rule is maintaining some reversible effect on the game world, pausing the rule should end this effect. For example, a rule which displays a message to the user should typically hide the message upon becoming paused, and a rule which causes a rain storm in a specific area should return the weather to normal upon becoming paused. Rules which make a single permanent change to the game world and then immediately flag as COMPLETE should not attempt to reverse the change upon becoming paused. Examples of these rules include configuration of the global weather conditions, or a rule which increments the player&#039;s score or penalty counter.&lt;br /&gt;
&lt;br /&gt;
It is important to note that any pause is resumable, although the parent may not choose to take advantage of this. Pausing a rule followed by unpausing it should result in the rule continuing operation where it left off. The notes on Saving and Loading Driver Sessions (below) are worth considering when evaluating techniques for implementing pause.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Early Termination via Internal Logic =&lt;br /&gt;
In some cases, a rule may begin executing child rules but then make an internal decision to abort execution. This typically occurs in conditional rules where the condition may be re-evaluated as false after it has already been evaluated as true. Such behavior should be made explicit in the rule editor interface and should usually be made optional by providing a checkbox.&lt;br /&gt;
&lt;br /&gt;
There are in fact several possible behavioral variants affecting how condition-deflag is interpreted:&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules and no further evaluation is performed. The rule eventually flags itself as COMPLETE and does not later deflag this.&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules. If the condition becomes deflagged, the child rules are paused. If the condition becomes flagged again, the child rules are continued. Once the child rules have fully completed execution, the rule flags itself as COMPLETE and does not later deflag this.&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules. If the condition becomes deflagged, the child rules are paused. If the condition becomes flagged again, the children are reset and execution starts anew. The rule flags itself as COMPLETE if all children successfully complete, but it will deflag if the condition deflags.&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules. If the condition becomes deflagged, the child rules continue executing. If the condition becomes flagged again, the children are reset and execution starts anew. The rule will flag as COMPLETE if all children successfully complete, but it will deflag if the condition deflags.&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules. The child rules continue execution with no regard for whether the condition changes between flagged or deflagged in either direction. If the condition transitions from deflagged to flagged again after the children have completed, the children are reset and execution starts anew. The rule will flag as COMPLETE if all children successfully complete, but it will deflag itself if the condition deflags. &lt;br /&gt;
&lt;br /&gt;
The complexity here derives from the fact that it is not possible to use the same set of rules multiple times concurrently for different trigger conditions. For example, if a set of rules is used to give demerit points and provide user notifications, and those rules live under a single conditional check which determines whether a train is speeding, it may be difficult to define what should happen if two trains are detected as speeding at the same time, or if a train stops speeding while the notification process is still in progress. It is not always possible to achieve a perfect solution to tracking multiple objects using a single set of rules, but correct selection from the above behaviors can minimise the possibility of serious side-effects.&lt;br /&gt;
&lt;br /&gt;
It is important to note that these behaviors describe how the rule reacts to internal condition checks. The rule&#039;s reaction to being paused by its parent is discussed above under &amp;quot;Early Termination via Pause&amp;quot; and is not affected by the description here.&lt;br /&gt;
&lt;br /&gt;
In short, there are many ways of handling this, and the important thing is for your (parent) rule to clearly explain which approach it is going to use.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Rule Reset =&lt;br /&gt;
A rule may be &#039;&#039;reset&#039;&#039; by its parent. This causes both the COMPLETE and WAS COMPLETE states to be deflagged. Individual rules may also react to the reset by modifying their internal state to forget past or present actions. Parent rules must also cause their children to be reset in turn.&lt;br /&gt;
&lt;br /&gt;
This mechanism is used to permit rules to be used in a repeating scenario, such as responding to a condition which can occur multiple times, or in a repeating loop. At some point after a rule has become flagged as WAS COMPLETE, it will typically become paused and will not be unpaused again. If the rule is to be included in some repeating behavior, this would normally prevent the behavior from operating successfully after the first run through. To avoid this, the parent rule responsible for implementing the repeating behavior will &#039;&#039;reset&#039;&#039; all children when a repeat occurs. This effectively cleans the rules back to their initial state ready to perform their roles again.&lt;br /&gt;
&lt;br /&gt;
It is important to note that a reset should cause the rule to return to its configured settings. For example, if a timer value is configured and is decremented during rule operation, the timer must be reset back to its initial value during rule reset.&lt;br /&gt;
&lt;br /&gt;
It is important to note that there is no requirement to pause a rule prior to resetting it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Saving and Loading Driver Sessions =&lt;br /&gt;
For better or worse, the script VM does not persist across a save/load operation. This means that each rule must correctly save both its configuration state and its runtime state, and must correctly reload those such that the state after a save/load operation is indistinguishable from the original state. The following aspects of the script state must be considered:&lt;br /&gt;
&lt;br /&gt;
* Member variables in the Rule instance.&lt;br /&gt;
* Which threads are running on the Rule instance, and where they are up to in the code flow.&lt;br /&gt;
* Local variables on the stack of each running thread.&lt;br /&gt;
* Non-persistent changes made to the state of other script objects (such as active &#039;sniff&#039; statements).&lt;br /&gt;
* Script Messages which might be in flight at the time of save (these are not persisted, so the net effect is that they are simply deleted between the save and the load.)&lt;br /&gt;
&lt;br /&gt;
Since the game state continues normal operation after a Save, no code flow or other behavioral changes should result from the Save operation itself. Instead, the Save operation (and the design of the rule as a whole) is responsible for ensuring that sufficient data is persisted in the save file such that the Load operation is able to restore to the correct running state.&lt;br /&gt;
&lt;br /&gt;
The rule base class, ScenarioBehavior, is responsible for saving and loading the rule state flags (COMPLETE, PAUSED, WAS COMPLETE, etc.) A rule which was paused at Save time will still be paused after the Load. A rule which was complete at Save time will still be complete after the Load. During a Load operation, the rule should inherit the parent class&#039; SetProperties() method so that these flags are correctly configured, then honor the paused state during the rest of the loading process.&lt;br /&gt;
&lt;br /&gt;
It is rarely appropriate for an unpaused rule to simply restart execution from the beginning. Care must be taken to ensure that execution resumes from the point that it left off at the time of saving. This process can be simplified by keeping as much state as possible in the rule member variables at all times, and only keeping reconstructible temporary values on the stack. If the member variables are correctly stored and restored, this approach will allow the loading process to detect the runtime state of the rule and resume any necessary threads, which will in turn be able to jump forward to the correct area of the code based on the stored state.&lt;br /&gt;
&lt;br /&gt;
Finally, the COMPLETE, WAS COMPLETE, and PAUSED flags on child rules should be honored. This is typically sufficient information to determine the running state of child rules, so no further state will generally need to be maintained. More accurately, the child rules take care of their own state at all times, and the parent only needs to react to changes in the child state. Since no child state change occurs across a Save/Load operation, the parent does not need to become involved.&lt;br /&gt;
&lt;br /&gt;
For rules which derive ConditionalScenarioBehavior, the majority of load/save logic is handled automatically. The only state information that such a rule should typically preserve is the instance-specific configuration data. The condition-monitor thread will be automatically restarted as required, and there is generally no need to distinguish between a first-startup and any subsequent startup.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Spurious Events =&lt;br /&gt;
There are various events (typically script messages) that a rule may listen for in order to detect state changes. It is important to note that spurious events are often possible, and that an event handler should often be coupled with a condition check. As a specific example, the &amp;quot;ScenarioBehavior&amp;quot;, &amp;quot;Touch&amp;quot; message typically indicates that a child state has changed, but the message may in fact be sent at any time. This message should prompt the rule to evaluate whether any state changes are necessary, but the rule should not simply assume that a state change is necessary without performing an evaluation.&lt;br /&gt;
&lt;br /&gt;
Similarly, calls to a function such as Pause() may in some cases have no effect. For example, if a rule is already executing and its parent calls Pause(false), the rule should not pause, reset, or change state in any way at all. Similarly, if a rule is already paused and its parent calls Pause(true), the rule should not unpause, reset, fire any events, or otherwise change state in any way at all.&lt;br /&gt;
&lt;br /&gt;
The short version is: do not assume that every event and every method call is supposed to achieve something meaningful. Check first, and if the event is meaningless to you then do nothing at all.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Future Considerations =&lt;br /&gt;
Rules should base their functionality on the state flags such as the PAUSED state, rather than attempting to detect and vary their functionality based on the state of the game.&lt;br /&gt;
&lt;br /&gt;
For example, we currently (in development builds) expose the rules editor in Driver for debugging purposes. This, or some mechanism like it, is likely to be included in public builds in the future. Rules should not assume that it is impossible to be reconfigured during gameplay. This will of course introduce some side effects, such as when an unpaused rule is modified during execution. It is the rule&#039;s responsibility to ensure that these side effects do not lead to script exceptions or to leaked state. For example, if a single thread is supposed to be running, reconfiguring the rule should not cause a second thread to run simultaneously. If a rule sniffs a target vehicle, and the target vehicle is redefined, then the rule should unsniff the original vehicle rather than now sniffing two vehicles.&lt;br /&gt;
&lt;br /&gt;
Likewise, we may in future allow some form of partial state swap between Driver and Surveyor. Rules should not assume that it is impossible to change from any one game state or module to any other game state or module, just because it is not possible at the current time. APIs already exist to detect such state changes where necessary, and in most cases it&#039;s simply not necessary to care whether your rule is in Surveyor or Driver - you should act based on the PAUSED state instead. Rules should deal with the game state as they find it rather than assuming that certain states will not ever occur.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Gotchas =&lt;br /&gt;
There are a few potential gotchas in the script environment that are worth considering when writing any non-trivial rule.&lt;br /&gt;
&lt;br /&gt;
== Response Latency ==&lt;br /&gt;
Scripts tend to rely heavily on message passing and threading. In both cases, there is a delay between triggering a certain behavior (eg. posting an event, or calling a threaded function) and having the receiving code react. Other code may execute during this delay.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
// Calling this might be expected to start and then stop the thread; in reality it&lt;br /&gt;
// will likely simply start the thread and leave it running, because the message&lt;br /&gt;
// is sent prior to the wait() statement starting.&lt;br /&gt;
void DemonstrateBug1(void)&lt;br /&gt;
{&lt;br /&gt;
  Pause(false);&lt;br /&gt;
  Pause(true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// In this case, we use a Sleep() statement to &amp;quot;ensure&amp;quot; that the thread has&lt;br /&gt;
// finished starting. This isn&#039;t actually reliable, but it works as long as the&lt;br /&gt;
// system isn&#039;t under too much load. We follow this up with a rapid pause-&lt;br /&gt;
// unpause sequence. As above, this doesn&#039;t work - the message is sent,&lt;br /&gt;
// then the function immediately checks whether the thread is still running&lt;br /&gt;
// (which it is) and thus the thread isn&#039;t restarted. The function completes,&lt;br /&gt;
// and finally the thread receives the message and exits.&lt;br /&gt;
void DemonstrateBug2(void)&lt;br /&gt;
{&lt;br /&gt;
  Pause(false);&lt;br /&gt;
  Sleep(1.0);&lt;br /&gt;
  Pause(true);&lt;br /&gt;
  Pause(false);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Helper code for the above functions.&lt;br /&gt;
void Pause(bool bIsPaused)&lt;br /&gt;
{&lt;br /&gt;
  if (bIsPaused)&lt;br /&gt;
  {&lt;br /&gt;
    PostMessage(me, &amp;quot;ThisRule&amp;quot;, &amp;quot;Pause&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  else if (!m_bIsThreadRunning)&lt;br /&gt;
  {&lt;br /&gt;
    m_bIsThreadRunning = true;&lt;br /&gt;
    StartThread();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
thread void StartThread(void)&lt;br /&gt;
{&lt;br /&gt;
  while (true)&lt;br /&gt;
  {&lt;br /&gt;
    wait ()&lt;br /&gt;
    {&lt;br /&gt;
    on &amp;quot;ThisRule&amp;quot;, &amp;quot;Pause&amp;quot;:&lt;br /&gt;
      break;&lt;br /&gt;
     ...&lt;br /&gt;
  }&lt;br /&gt;
  m_bIsThreadRunning = false;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Multiple Messages in Flight ==&lt;br /&gt;
It&#039;s possible to post multiple identical messages. This can be useful, but if you&#039;re expecting only one then it can be a source of errors.&lt;br /&gt;
&lt;br /&gt;
In the following pseudocode, each call to SetProperties() will place an additional &amp;quot;Timer&amp;quot;, &amp;quot;Tick&amp;quot; message into the cycle, effectively increasing the rate at which the IdleFunction is called. This will seem to be working for a single call to SetProperties(), which may be all that is called during a trivial testcase. It will probably give reasonable results for a few calls to SetProperties(), although if the function is time-sensitive then the results might be different to expectations. After a larger number of calls to SetProperties(), the object&#039;s message queue may become full, causing it to lose messages at random (perhaps the tick messages, or perhaps other unrelated messages that are more problematic).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
void Init(void)&lt;br /&gt;
{&lt;br /&gt;
  inherited();&lt;br /&gt;
  &lt;br /&gt;
  AddHandler(me, &amp;quot;Timer&amp;quot;, &amp;quot;Tick&amp;quot;, &amp;quot;IdleFunction&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void EnterIdleState(void)&lt;br /&gt;
{&lt;br /&gt;
  IdleFunction();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void IdleFunction(void)&lt;br /&gt;
{&lt;br /&gt;
  PostMessage(me, &amp;quot;Timer&amp;quot;, &amp;quot;Tick&amp;quot;, 1.0);&lt;br /&gt;
  .. do something here ..&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void SetProperties(Soup soup)&lt;br /&gt;
{&lt;br /&gt;
  inherited(soup);&lt;br /&gt;
  &lt;br /&gt;
  EnterIdleState();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A similar problem can occur if you start new threads rather than post new messages.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Thread Guard Variables ==&lt;br /&gt;
It&#039;s common to prevent a singleton thread from being started twice by using a boolean guard variable. Care must be taken to ensure that the guard variable is set and cleared at the correct locations, or they may be ineffective.&lt;br /&gt;
&lt;br /&gt;
The following pseudocode demonstrates one such correct usage. The key points to note are:&lt;br /&gt;
* We set &#039;m_bIsThreadedFunctionRunning&#039; prior to calling the threaded function. Setting it within the threaded function is too late; multiple threads might have already been started before the first thread reaches that point.&lt;br /&gt;
* We don&#039;t confuse whether the thread is actually running with whether we want the thread to be running. Once we ask a thread to start, we can&#039;t stop it starting. If we change our minds and want to stop it again, we must inform it in a way that it will realise after it finishes starting. In the worst-case scenario, we might flipflop on this multiple times before the thread actually starts.&lt;br /&gt;
* Similarly, we don&#039;t rely on messages to control the thread. Enqueuing a separate start or stop message with each StartThread()/StopThread() call might be possible, and we could clear any unwanted prior messages from the object&#039;s queue, but if the thread hasn&#039;t finished starting then it won&#039;t receive the messages anyway.&lt;br /&gt;
* We do rely on messages to wake the thread if it&#039;s waiting on messages, but we don&#039;t use those messages to imply any state - we just have it recheck the current state boolean to get the very latest info.&lt;br /&gt;
* We clear &#039;m_bIsThreadedFunctionRunning&#039; once the decision to exit has become unconditional. At this point, even though the thread is technically still running, we&#039;ll have to start a new thread if we want the thread to continue running.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
bool m_bIsThreadedFunctionRunning = false;&lt;br /&gt;
bool m_bWantThreadedFunctionRunning = false;&lt;br /&gt;
&lt;br /&gt;
void StartThread(void)&lt;br /&gt;
{&lt;br /&gt;
  m_bWantThreadedFunctionRunning = true;&lt;br /&gt;
  &lt;br /&gt;
  if (m_bIsThreadedFunctionRunning)&lt;br /&gt;
    return;&lt;br /&gt;
  &lt;br /&gt;
  m_bIsThreadedFunctionRunning = true;&lt;br /&gt;
  ThreadedFunction();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void StopThread(void)&lt;br /&gt;
{&lt;br /&gt;
  if (!m_bWantThreadedFunctionRunning)&lt;br /&gt;
    return;&lt;br /&gt;
  &lt;br /&gt;
  m_bWantThreadedFunctionRunning = false;&lt;br /&gt;
  PostMessage(me, &amp;quot;Thread&amp;quot;, &amp;quot;Touch&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
thread void ThreadedFunction(void)&lt;br /&gt;
{&lt;br /&gt;
  while (m_bWantThreadedFunctionRunning)&lt;br /&gt;
  {&lt;br /&gt;
    wait()&lt;br /&gt;
    {&lt;br /&gt;
      on &amp;quot;Thread&amp;quot;, &amp;quot;Touch&amp;quot;:&lt;br /&gt;
        break;&lt;br /&gt;
      .. whatever else..&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  m_bIsThreadedFunctionRunning = false;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Not Waiting For Messages ==&lt;br /&gt;
As seen above, it&#039;s possible for a thread to fail to receive posted messages because it wasn&#039;t waiting for them at the time. A more commonly problematic example follows.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
thread void MyThread(void)&lt;br /&gt;
{&lt;br /&gt;
  wait ()&lt;br /&gt;
  {&lt;br /&gt;
    on &amp;quot;Some&amp;quot;, &amp;quot;Condition&amp;quot;:&lt;br /&gt;
      HandleSomeCondition();&lt;br /&gt;
      continue;&lt;br /&gt;
    on &amp;quot;Thread&amp;quot;, &amp;quot;Exit&amp;quot;:&lt;br /&gt;
      break;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void HandleSomeCondition(void)&lt;br /&gt;
{&lt;br /&gt;
  wait ()&lt;br /&gt;
  {&lt;br /&gt;
    on &amp;quot;Some&amp;quot;, &amp;quot;End-Condition&amp;quot;:&lt;br /&gt;
      break;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In this example, the thread is waiting on both &amp;quot;Some&amp;quot;, &amp;quot;Condition&amp;quot; and also &amp;quot;Thread&amp;quot;, &amp;quot;Exit&amp;quot;. Either one will be handled correctly assuming that the thread is already running at the time they are posted. Even if multiple are posted, the thread will simply queue them and run each in turn.&lt;br /&gt;
&lt;br /&gt;
The problem occurs when HandleSomeCondition() is triggered and the thread begins waiting on &amp;quot;Some&amp;quot;, &amp;quot;End-Condition&amp;quot;. In this scenario, the thread is no longer waiting on &amp;quot;Thread&amp;quot;, &amp;quot;Exit&amp;quot;, and any attempt to post that message will simply be ignored. To reiterate: the message dispatch is NOT postponed until the function returns; the message is dropped entirely.&lt;br /&gt;
&lt;br /&gt;
In many cases, the correct behaviour is to move HandleSomeCondition() to a new thread, although that may also carry gotchas that you will need to be careful of (eg. you&#039;ll probably want to terminate the second thread at the same time as the first one, and you may need to consider whether you want multiple of the second thread to run simultaneously or not).&lt;br /&gt;
&lt;br /&gt;
== Performing Actions After Being Told to Stop ==&lt;br /&gt;
In many cases, you may wish to perform cleanup actions when stopping your rule. If your rule is threaded, this can easily become problematic.&lt;br /&gt;
&lt;br /&gt;
Consider the following pseudocode example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
void Pause(bool bIsPaused)&lt;br /&gt;
{&lt;br /&gt;
  if (!bIsPaused &amp;amp;&amp;amp; !m_bIsThreadRunning)&lt;br /&gt;
  {&lt;br /&gt;
    m_bIsThreadRunning = true;&lt;br /&gt;
    MyThread();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
thread void MyThread(void)&lt;br /&gt;
{&lt;br /&gt;
  BeginRule();&lt;br /&gt;
  while (!IsPaused())&lt;br /&gt;
  {&lt;br /&gt;
    Sleep(0.5);&lt;br /&gt;
    UpdateRule();&lt;br /&gt;
  }&lt;br /&gt;
  EndRule();&lt;br /&gt;
  m_bIsThreadRunning = false;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There are three immediately obvious problems:&lt;br /&gt;
&lt;br /&gt;
1. That BeginRule() is called when the thread starts, even if the rule has already been paused again.&lt;br /&gt;
&lt;br /&gt;
2. That UpdateRule() will be called after each sleep, even if the rule was paused during the sleep.&lt;br /&gt;
&lt;br /&gt;
3. That EndRule() will be called after the rule has been paused.&lt;br /&gt;
&lt;br /&gt;
This is very problematic because it likely violates a core principles of the rules system: that rules will not undertake any meaningful behaviour when paused. All three functions may be called while the rule is paused, so unless the rule does nothing meaningful at all, this is a guaranteed violation.&lt;br /&gt;
&lt;br /&gt;
The best approach to resolving this may depend on exactly what these functions do, but one possible solution is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
void Pause(bool bIsPaused)&lt;br /&gt;
{&lt;br /&gt;
  if (bIsPaused)&lt;br /&gt;
  {&lt;br /&gt;
    if (m_bNeedsEndRule)&lt;br /&gt;
    {&lt;br /&gt;
      m_bNeedsEndRule = false;&lt;br /&gt;
      EndRule();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  else&lt;br /&gt;
  {&lt;br /&gt;
    if (!m_bNeedsEndRule)&lt;br /&gt;
    {&lt;br /&gt;
      BeginRule();&lt;br /&gt;
      m_bNeedsEndRule = true;&lt;br /&gt;
    }&lt;br /&gt;
    if (!m_bIsThreadRunning)&lt;br /&gt;
    {&lt;br /&gt;
      m_bIsThreadRunning = true;&lt;br /&gt;
      MyThread();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
thread void MyThread(void)&lt;br /&gt;
{&lt;br /&gt;
  while (!IsPaused())&lt;br /&gt;
  {&lt;br /&gt;
    UpdateRule();&lt;br /&gt;
    Sleep(0.5);&lt;br /&gt;
  }&lt;br /&gt;
  m_bIsThreadRunning = false;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Failing to Inherit from ConditionalScenarioBehavior ==&lt;br /&gt;
This isn&#039;t really a separate gotcha, but it can&#039;t be stressed enough that your rule should inherit from ConditionalScenarioBehavior and should minimise the number of overrides to its default behavior. Apart from the &amp;quot;users expect things to work like this, so that&#039;s what you should do&amp;quot; argument, there are some much more compelling arguments for would-be rule developers:&lt;br /&gt;
&lt;br /&gt;
1. Developing a rule with correct threading behavior is hard. Just have a look at some of the above gotchas. Were you already consciously aware of them all? If not, you&#039;re probably not ready to write your own rule which involves threading. ConditionalScenarioBehavior provides a polling thread mechanism that&#039;s already built, so you can reap the benefits of that approach without having to worry about whether you made any mistakes in the threading code.&lt;br /&gt;
&lt;br /&gt;
2. Developing a rule with correct load/save behavior can be hard. Did you correctly restart your threads when necessary? Did you accidentally restart your threads when you weren&#039;t supposed to? Was there a message in flight during the save which you lost by reloading, and have you handled that loss correctly? ConditionalScenarioBehavior can help with a lot of that kind of thing, leaving you to worry about your rule-specific implementation only.&lt;br /&gt;
&lt;br /&gt;
3. Developing a rule with correct child-rule-handling behavior can be really hard. You need to have a thorough understand of everything listed in this document, and you need to ensure that you don&#039;t make any mistakes which could cause your rule to violate any of the principles in this document, even in edge-case behaviours. Because this is the real world, you also need to handle child rules which don&#039;t necessarily follow the rules to the letter. ConditionalScenarioBehavior does all of this automatically with no effort on your part.&lt;br /&gt;
&lt;br /&gt;
4. Inheriting from ConditionalScenarioBehavior means that many future issues can be fixed automatically by [[N3V Games]] without you having to update your rule. This includes both fixes to our own code (hey, we&#039;re human too) and also new changes to adapt our code to future requirements.&lt;br /&gt;
&lt;br /&gt;
5. Inheriting from ConditionalScenarioBehavior typically means that there&#039;s a lot less semi-custom boilerplate in your rule, making your rule much simpler to read and maintain. This helps you while you&#039;re debugging your own rule, helps you when you&#039;re coming back in a year&#039;s time and wondering how it all worked, and perhaps helps others in the community if they need to update your rule in 10 years time after you&#039;ve moved on from developing Trainz script code.&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=Session_Rule_Implementation&amp;diff=16831</id>
		<title>Session Rule Implementation</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=Session_Rule_Implementation&amp;diff=16831"/>
		<updated>2018-11-27T17:10:40Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: /* COMPLETE */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page seeks to clearly define expected script behavior for [[KIND Scenariobehavior|Session Rule assets]]. This focuses specifically on correct behavior from the code perspective, rather than addressing how rules should be designed for best gameplay outcomes.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Legacy Behavior Note =&lt;br /&gt;
Please note that many existing rules do not behave correctly as defined here. This is considered a bug in the individual session rules. [[N3V Games]] has a policy of updating session rules to behave correctly even where that may lead to changes of function in existing [[session]] assets. Where reasonable to achieve, emulation of the existing (buggy) behavior may occur for existing rule instances in existing sessions, however any newly created rule instances will use the corrected behavior.&lt;br /&gt;
&lt;br /&gt;
These expectations were codified at the end of [[TS12]] development due to an increasing inability of session rules to work together resulting from the unpredictable nature of their responses to various common use-cases. The systems as a whole, including most of the core rules discussed in this document, have existed for far longer than this document. The document does not redefine any existing systems, but simply presents the only reasonable implementation approach possible if rules are to be expected to work properly in all use-cases. In some cases we also choose to mandate specific points of behavior relating to user expectations rather than technical necessities.&lt;br /&gt;
&lt;br /&gt;
Certain additional API mechanisms were introduced alongside the development of this document, to allow better communication with session authors regarding the differences in behavior between certain types of rule. The correct usage for these mechanisms is also included in this document.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= The Rule Hierarchy =&lt;br /&gt;
All rules within a given session form a simple tree structure.&lt;br /&gt;
&lt;br /&gt;
== Rule State Flags ==&lt;br /&gt;
Each rule in the tree may have certain associated state flagged, including a combination of the following:&lt;br /&gt;
&lt;br /&gt;
=== PAUSED ===&lt;br /&gt;
The rule is currently paused, meaning that it does not affect the game world in any way and does not respond to any changes in the game world. The parent rule must cause the rule to become unpaused for the rule to have any effect. It is not correct behavior for a rule to unpause itself.&lt;br /&gt;
&lt;br /&gt;
=== COMPLETE ===&lt;br /&gt;
This flag indicates that rule has fully completed its operation (including any child rule operations) and does not affect the game world in any way. This flag is set by the rule itself, not by an outside entity such as the parent. This state should not be changed while the rule is PAUSED.&lt;br /&gt;
&lt;br /&gt;
Being COMPLETE does not imply being PAUSED. In many scenarios, the parent rule may respond to a child becoming COMPLETE by causing it to also become PAUSED, however this is certainly not guaranteed in all cases, and is not guaranteed to be immediate in the cases where it does happen.&lt;br /&gt;
&lt;br /&gt;
The rule may optionally respond to specific changes in the game world by deflagging the COMPLETE status. For example, a rule which specifically implements a condition check may choose to become COMPLETE when that condition is met, but return to an incomplete state when the condition is no longer met (again, remembering that a change in either direction should only happen while the rule itself is not PAUSED).&lt;br /&gt;
&lt;br /&gt;
When a rule&#039;s COMPLETE state is changed via ScenarioBehavior.SetComplete(), a &amp;quot;ScenarioBehavior&amp;quot;, &amp;quot;Touch&amp;quot; message is sent to its parent rule (if any), unless the parent is in the PAUSED state. This allows the parent to react to changes in its child rules&#039; states. It is important to note that the message indicates a possible change which the parent may be interested in, but it is the parent rule&#039;s responsibility to determine whether the state change is worth reacting to.&lt;br /&gt;
&lt;br /&gt;
=== WAS COMPLETE ===&lt;br /&gt;
This is typically set when a rule first becomes flagged as COMPLETE, and will stay set even if the rule later flags as incomplete. This can be used by a parent which only cares that the child rule has been flagged as COMPLETE at some point, rather than caring what its current completion status is.&lt;br /&gt;
&lt;br /&gt;
=== DOES COMPLETE ===&lt;br /&gt;
This indicates whether the rule can ever reach the COMPLETE state. Its value is constant for a given rule configuration, and does not change based on the runtime rule state or other game state. Rules which are flagged as DOES COMPLETE are expected to become complete after some discreet operations are completed. Rules which are not flagged are expected to run indefinitely unless PAUSED by an external agent (such as the parent rule).&lt;br /&gt;
&lt;br /&gt;
== Initial State ==&lt;br /&gt;
All rules are initially in the PAUSED state when in [[Surveyor]], and only become unpaused after gameplay begins in a [[Driver]] session. Since a PAUSED rule is not permitted to unpause itself, this is a stable state which will persist until the native code takes step to begin program flow.&lt;br /&gt;
&lt;br /&gt;
== Top Level Rules ==&lt;br /&gt;
All rules at the top level (ie. rules which are not a child of any other rule) simultaneously become unpaused after the session has loaded into Driver. Some of these rules may take initial setup steps and then become COMPLETE. Some of these rules may begin monitoring for specific game conditions before taking any further action. Some of these rules may begin taking action immediately. The rules are not sequenced against each other in any way, and it is the session author&#039;s responsibility to ensure that this does not cause any conflicts.&lt;br /&gt;
&lt;br /&gt;
== Scheduling ==&lt;br /&gt;
Since the script VM is a cooperatively-threaded environment, it is technically true that rule evaluation will occur in an ordered manner rather than truly simultaneously. However, no guarantees are made regarding the order in which the simultaneously-running rules will perform their checks or outcomes. Since rules may wait internally rather than fulfilling their entire purpose in an atomic operation, it is also not guaranteed that a first-running rule will fully complete before some other simultaneously-executing rule begins completion. In short, if order-of-execution is critical to the correct behavior of a session, then the order should be enforced by the session creator using the rule hierarchy rather than by making assumptions about execution order of simultaneously-running rules.&lt;br /&gt;
&lt;br /&gt;
(Note: with the introduction of [[Asynchronous Route Streaming]], this is even more true than previously. What may have been a near-instantaneous operation in older builds may now require a wait of several seconds while the necessary data is streamed in.)&lt;br /&gt;
&lt;br /&gt;
It is important to note that some conditional rules may partially or completely rely on a polling behavior to evaluate their conditions. (An example of partial reliance is a rule which waits for an event, but then evaluates a condition to clarify whether the event should be acted upon.) In these cases, it is possible that the condition can rapidly become true and then become false again without the rule responding. This results in an uncertainty as to whether the conditional rule will correctly detect a given instance of the condition. This type of scenario should be avoided completely where possible, and should most definitely be limited to outcomes that do not significantly affect gameplay.&lt;br /&gt;
&lt;br /&gt;
For a hypothetical example, if the player&#039;s train speeds for 0.5sec, and a speeding check rule was implemented that polled every second, then the overspeed event may or may not trigger on any given occurrence. A session creator should not use this outcome as a failure condition, since some players may be able to speed without penalty, whereas other players would be penalised on the first attempt. A sensible solution in this case might be to increment a counter while speeding is detected, and only take action if the counter reaches a certain threshold. If the only penalty was a warning to the player which had no actual gameplay impact, then it might be acceptable to forgo this check and simply accept that some players will receive a warning where others may not.&lt;br /&gt;
&lt;br /&gt;
==Child Rules==&lt;br /&gt;
As with all other rules, child rules (ie. those that have parent rules in the hierarchy) start out in the PAUSED state. They do not become unpaused until the parent is ready for the children to start operating. Exactly when this occurs depends on the specific parent rule, but the general flow is the same for all rules:&lt;br /&gt;
&lt;br /&gt;
1. Parent rule becomes unpaused and begins operation.&lt;br /&gt;
&lt;br /&gt;
2. Parent rule configures any necessary world state changes.&lt;br /&gt;
&lt;br /&gt;
3. Parent rule optionally waits for a specific condition to occur.&lt;br /&gt;
&lt;br /&gt;
4. Parent rule begins executing its children. This involves unpausing one or more of the children (as discussed below in &amp;quot;Parent Rule Styles&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
5. Parent waits for its children to complete (as discussed below in &amp;quot;Parent Rule Styles&amp;quot;) and then pauses the children.&lt;br /&gt;
&lt;br /&gt;
6. Parent flags itself as COMPLETE.&lt;br /&gt;
&lt;br /&gt;
This process allows program control flow to pass from a top-level rule, to its immediate children, to their immediate children, and so on. As the bottom-level children become complete, completion flows back to the higher level children until finally the top-level rules become COMPLETE.&lt;br /&gt;
&lt;br /&gt;
It is worth noting that there is nothing special about a top-level rule being flagged as COMPLETE. This does not indicate an end-of-session or any other fundamental gameplay mode change. Since the pausing of rules on completion is handled by the parent rule (see step 5 above), the top-level rules never become PAUSED on completion.&lt;br /&gt;
&lt;br /&gt;
==Parent Rule Styles==&lt;br /&gt;
There are a few common techniques with which parent rules interact with their children. Rules should always fit one of these descriptions. The vast majority of rules should follow either the &amp;quot;Does Not Support Children&amp;quot; style, or the &amp;quot;Ordered Execution of Children&amp;quot; style.&lt;br /&gt;
&lt;br /&gt;
=== Does Not Support Children ===&lt;br /&gt;
The rule is incapable of supporting children and will always ignore them.&lt;br /&gt;
&lt;br /&gt;
This is used for trivial rules which perform a set function and then become permanently COMPLETE. Such rules are not conditional and do not wait for any world state changes except those which they initiate internally.&lt;br /&gt;
The rule should be configured to validate and/or enforce that no child rules can be added.&lt;br /&gt;
&lt;br /&gt;
=== Simultaneous Execution of Children ===&lt;br /&gt;
When the rule is ready to begin executing children, it unpauses all children simultaneously. The rule then waits for all children to flag as WAS COMPLETE. Once this is detected, the rule pauses all children and flags itself as COMPLETE.&lt;br /&gt;
This is used for rules which have a specific need to simultaneously execute children, such as the &amp;quot;Simultaneous List&amp;quot; rule.&lt;br /&gt;
&lt;br /&gt;
The rule editor interface should be explicit that child rules will be executed simultaneously. Child rules should be tagged appropriately in the rule editor list to denote unordered execution.&lt;br /&gt;
&lt;br /&gt;
=== Ordered Execution of Children ===&lt;br /&gt;
When the rule is ready to begin executing children, it iterates through the children in top-to-bottom order. If the child is flagged as WAS COMPLETE, the child is paused and iteration continues. If the child is not flagged as WAS COMPLETE, the child is unpaused and iteration ends. Whenever a child state change is detected, this process is repeated from the start. Once iteration passes over all children without leaving any child unpaused, the rule flags itself as COMPLETE.&lt;br /&gt;
&lt;br /&gt;
This style is used for all rules which do not explicitly fall under one of the other styles described here. Almost all third-party rules will follow this style. Implementing one of the other styles without there being a fundamental requirement to do so is considered a programming error.&lt;br /&gt;
&lt;br /&gt;
Rules which follow this style should derive from [[ConditionalScenarioBehavior]] in order to avoid re-implementing the control flow logic, as it is exceedingly complex to implement correctly. Any rules which do not derive from ConditionalScenarioBehavior should be accompanied by a clear explanation of the reasons that ConditionalScenarioBehavior is an unsuitable base class for the intended behavior. Rules which do derive from ConditionalScenarioBehavior should avoid complex overrides of the default logic.&lt;br /&gt;
&lt;br /&gt;
Child rules should be tagged appropriately in the rule editor list to denote execution order.&lt;br /&gt;
&lt;br /&gt;
=== Controlled Selection of a Single Child ===&lt;br /&gt;
When the rule is ready to begin executing children, it selects a single child and unpauses it. All other children remain paused. Once the selected child becomes flagged as WAS COMPLETE, the child is paused and the rule flags itself as COMPLETE.&lt;br /&gt;
&lt;br /&gt;
This style is used where complex conditional selection of child rules is required. This can be used to implement an &amp;quot;if-else&amp;quot; logic flow, a &amp;quot;switch-case&amp;quot; logic flow, or the &amp;quot;Random List&amp;quot; rule. This style should not be used to implement a simple &amp;quot;if&amp;quot; logic flow, because that would unnecessarily restrict the rule to a single child where the &amp;quot;Ordered Execution of Children&amp;quot; style would provide the same functionality while allowing multiple children.&lt;br /&gt;
The rule editor interface should be very explicit about how the child rules will be selected. Child rules should be tagged appropriately in the rule editor list to avoid the user attempting to fit a child rule into the wrong role.&lt;br /&gt;
&lt;br /&gt;
=== Custom Execution with Multiple Children ===&lt;br /&gt;
This style is used for very specific custom-purpose rules, such as a passenger station stop handler. Such rules should give a clear and complete explanation of their operation and their interaction with any child rules in the rule editor interface.&lt;br /&gt;
&lt;br /&gt;
Individual child rules may be executed in an ad-hoc manner by the rule in response to changes in game state. Child rules may or may not be executed simultaneously and may or may not be executed repeatedly depending on the rule; any limitations or gotchas deriving from this should be carefully explained in the rule editor interface.&lt;br /&gt;
&lt;br /&gt;
Child rules should be tagged appropriately in the rule editor list to avoid the user attempting to fit a child rule into the wrong role.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Early Termination via Pause =&lt;br /&gt;
A rule must accept being paused by its parent at any time. This should cause the rule to cease any game state monitoring or other direct effects. The rule must pause all child rules immediately.&lt;br /&gt;
&lt;br /&gt;
In cases where the rule is maintaining some reversible effect on the game world, pausing the rule should end this effect. For example, a rule which displays a message to the user should typically hide the message upon becoming paused, and a rule which causes a rain storm in a specific area should return the weather to normal upon becoming paused. Rules which make a single permanent change to the game world and then immediately flag as COMPLETE should not attempt to reverse the change upon becoming paused. Examples of these rules include configuration of the global weather conditions, or a rule which increments the player&#039;s score or penalty counter.&lt;br /&gt;
&lt;br /&gt;
It is important to note that any pause is resumable, although the parent may not choose to take advantage of this. Pausing a rule followed by unpausing it should result in the rule continuing operation where it left off. The notes on Saving and Loading Driver Sessions (below) are worth considering when evaluating techniques for implementing pause.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Early Termination via Internal Logic =&lt;br /&gt;
In some cases, a rule may begin executing child rules but then make an internal decision to abort execution. This typically occurs in conditional rules where the condition may be re-evaluated as false after it has already been evaluated as true. Such behavior should be made explicit in the rule editor interface and should usually be made optional by providing a checkbox.&lt;br /&gt;
&lt;br /&gt;
There are in fact several possible behavioral variants affecting how condition-deflag is interpreted:&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules and no further evaluation is performed. The rule eventually flags itself as COMPLETE and does not later deflag this.&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules. If the condition becomes deflagged, the child rules are paused. If the condition becomes flagged again, the child rules are continued. Once the child rules have fully completed execution, the rule flags itself as COMPLETE and does not later deflag this.&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules. If the condition becomes deflagged, the child rules are paused. If the condition becomes flagged again, the children are reset and execution starts anew. The rule flags itself as COMPLETE if all children successfully complete, but it will deflag if the condition deflags.&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules. If the condition becomes deflagged, the child rules continue executing. If the condition becomes flagged again, the children are reset and execution starts anew. The rule will flag as COMPLETE if all children successfully complete, but it will deflag if the condition deflags.&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules. The child rules continue execution with no regard for whether the condition changes between flagged or deflagged in either direction. If the condition transitions from deflagged to flagged again after the children have completed, the children are reset and execution starts anew. The rule will flag as COMPLETE if all children successfully complete, but it will deflag itself if the condition deflags. &lt;br /&gt;
&lt;br /&gt;
The complexity here derives from the fact that it is not possible to use the same set of rules multiple times concurrently for different trigger conditions. For example, if a set of rules is used to give demerit points and provide user notifications, and those rules live under a single conditional check which determines whether a train is speeding, it may be difficult to define what should happen if two trains are detected as speeding at the same time, or if a train stops speeding while the notification process is still in progress. It is not always possible to achieve a perfect solution to tracking multiple objects using a single set of rules, but correct selection from the above behaviors can minimise the possibility of serious side-effects.&lt;br /&gt;
&lt;br /&gt;
It is important to note that these behaviors describe how the rule reacts to internal condition checks. The rule&#039;s reaction to being paused by its parent is discussed above under &amp;quot;Early Termination via Pause&amp;quot; and is not affected by the description here.&lt;br /&gt;
&lt;br /&gt;
In short, there are many ways of handling this, and the important thing is for your (parent) rule to clearly explain which approach it is going to use.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Rule Reset =&lt;br /&gt;
A rule may be &#039;&#039;reset&#039;&#039; by its parent. This causes both the COMPLETE and WAS COMPLETE states to be deflagged. Individual rules may also react to the reset by modifying their internal state to forget past or present actions. Parent rules must also cause their children to be reset in turn.&lt;br /&gt;
&lt;br /&gt;
This mechanism is used to permit rules to be used in a repeating scenario, such as responding to a condition which can occur multiple times, or in a repeating loop. At some point after a rule has become flagged as WAS COMPLETE, it will typically become paused and will not be unpaused again. If the rule is to be included in some repeating behavior, this would normally prevent the behavior from operating successfully after the first run through. To avoid this, the parent rule responsible for implementing the repeating behavior will &#039;&#039;reset&#039;&#039; all children when a repeat occurs. This effectively cleans the rules back to their initial state ready to perform their roles again.&lt;br /&gt;
&lt;br /&gt;
It is important to note that a reset should cause the rule to return to its configured settings. For example, if a timer value is configured and is decremented during rule operation, the timer must be reset back to its initial value during rule reset.&lt;br /&gt;
&lt;br /&gt;
It is important to note that there is no requirement to pause a rule prior to resetting it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Saving and Loading Driver Sessions =&lt;br /&gt;
For better or worse, the script VM does not persist across a save/load operation. This means that each rule must correctly save both its configuration state and its runtime state, and must correctly reload those such that the state after a save/load operation is indistinguishable from the original state. The following aspects of the script state must be considered:&lt;br /&gt;
&lt;br /&gt;
* Member variables in the Rule instance.&lt;br /&gt;
* Which threads are running on the Rule instance, and where they are up to in the code flow.&lt;br /&gt;
* Local variables on the stack of each running thread.&lt;br /&gt;
* Non-persistent changes made to the state of other script objects (such as active &#039;sniff&#039; statements).&lt;br /&gt;
* Script Messages which might be in flight at the time of save (these are not persisted, so the net effect is that they are simply deleted between the save and the load.)&lt;br /&gt;
&lt;br /&gt;
Since the game state continues normal operation after a Save, no code flow or other behavioral changes should result from the Save operation itself. Instead, the Save operation (and the design of the rule as a whole) is responsible for ensuring that sufficient data is persisted in the save file such that the Load operation is able to restore to the correct running state.&lt;br /&gt;
&lt;br /&gt;
The rule base class, ScenarioBehavior, is responsible for saving and loading the rule state flags (COMPLETE, PAUSED, WAS COMPLETE, etc.) A rule which was paused at Save time will still be paused after the Load. A rule which was complete at Save time will still be complete after the Load. During a Load operation, the rule should inherit the parent class&#039; SetProperties() method so that these flags are correctly configured, then honor the paused state during the rest of the loading process.&lt;br /&gt;
&lt;br /&gt;
It is rarely appropriate for an unpaused rule to simply restart execution from the beginning. Care must be taken to ensure that execution resumes from the point that it left off at the time of saving. This process can be simplified by keeping as much state as possible in the rule member variables at all times, and only keeping reconstructible temporary values on the stack. If the member variables are correctly stored and restored, this approach will allow the loading process to detect the runtime state of the rule and resume any necessary threads, which will in turn be able to jump forward to the correct area of the code based on the stored state.&lt;br /&gt;
&lt;br /&gt;
Finally, the COMPLETE, WAS COMPLETE, and PAUSED flags on child rules should be honored. This is typically sufficient information to determine the running state of child rules, so no further state will generally need to be maintained. More accurately, the child rules take care of their own state at all times, and the parent only needs to react to changes in the child state. Since no child state change occurs across a Save/Load operation, the parent does not need to become involved.&lt;br /&gt;
&lt;br /&gt;
For rules which derive ConditionalScenarioBehavior, the majority of load/save logic is handled automatically. The only state information that such a rule should typically preserve is the instance-specific configuration data. The condition-monitor thread will be automatically restarted as required, and there is generally no need to distinguish between a first-startup and any subsequent startup.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Spurious Events =&lt;br /&gt;
There are various events (typically script messages) that a rule may listen for in order to detect state changes. It is important to note that spurious events are often possible, and that an event handler should often be coupled with a condition check. As a specific example, the &amp;quot;ScenarioBehavior&amp;quot;, &amp;quot;Touch&amp;quot; message typically indicates that a child state has changed, but the message may in fact be sent at any time. This message should prompt the rule to evaluate whether any state changes are necessary, but the rule should not simply assume that a state change is necessary without performing an evaluation.&lt;br /&gt;
&lt;br /&gt;
Similarly, calls to a function such as Pause() may in some cases have no effect. For example, if a rule is already executing and its parent calls Pause(false), the rule should not pause, reset, or change state in any way at all. Similarly, if a rule is already paused and its parent calls Pause(true), the rule should not unpause, reset, fire any events, or otherwise change state in any way at all.&lt;br /&gt;
&lt;br /&gt;
The short version is: do not assume that every event and every method call is supposed to achieve something meaningful. Check first, and if the event is meaningless to you then do nothing at all.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Future Considerations =&lt;br /&gt;
Rules should base their functionality on the state flags such as the PAUSED state, rather than attempting to detect and vary their functionality based on the state of the game.&lt;br /&gt;
&lt;br /&gt;
For example, we currently (in development builds) expose the rules editor in Driver for debugging purposes. This, or some mechanism like it, is likely to be included in public builds in the future. Rules should not assume that it is impossible to be reconfigured during gameplay. This will of course introduce some side effects, such as when an unpaused rule is modified during execution. It is the rule&#039;s responsibility to ensure that these side effects do not lead to script exceptions or to leaked state. For example, if a single thread is supposed to be running, reconfiguring the rule should not cause a second thread to run simultaneously. If a rule sniffs a target vehicle, and the target vehicle is redefined, then the rule should unsniff the original vehicle rather than now sniffing two vehicles.&lt;br /&gt;
&lt;br /&gt;
Likewise, we may in future allow some form of partial state swap between Driver and Surveyor. Rules should not assume that it is impossible to change from any one game state or module to any other game state or module, just because it is not possible at the current time. APIs already exist to detect such state changes where necessary, and in most cases it&#039;s simply not necessary to care whether your rule is in Surveyor or Driver - you should act based on the PAUSED state instead. Rules should deal with the game state as they find it rather than assuming that certain states will not ever occur.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Gotchas =&lt;br /&gt;
There are a few potential gotchas in the script environment that are worth considering when writing any non-trivial rule.&lt;br /&gt;
&lt;br /&gt;
== Response Latency ==&lt;br /&gt;
Scripts tend to rely heavily on message passing and threading. In both cases, there is a delay between triggering a certain behavior (eg. posting an event, or calling a threaded function) and having the receiving code react. Other code may execute during this delay.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
// Calling this might be expected to start and then stop the thread; in reality it&lt;br /&gt;
// will likely simply start the thread and leave it running, because the message&lt;br /&gt;
// is sent prior to the wait() statement starting.&lt;br /&gt;
void DemonstrateBug1(void)&lt;br /&gt;
{&lt;br /&gt;
  Pause(false);&lt;br /&gt;
  Pause(true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// In this case, we use a Sleep() statement to &amp;quot;ensure&amp;quot; that the thread has&lt;br /&gt;
// finished starting. This isn&#039;t actually reliable, but it works as long as the&lt;br /&gt;
// system isn&#039;t under too much load. We follow this up with a rapid pause-&lt;br /&gt;
// unpause sequence. As above, this doesn&#039;t work - the message is sent,&lt;br /&gt;
// then the function immediately checks whether the thread is still running&lt;br /&gt;
// (which it is) and thus the thread isn&#039;t restarted. The function completes,&lt;br /&gt;
// and finally the thread receives the message and exits.&lt;br /&gt;
void DemonstrateBug2(void)&lt;br /&gt;
{&lt;br /&gt;
  Pause(false);&lt;br /&gt;
  Sleep(1.0);&lt;br /&gt;
  Pause(true);&lt;br /&gt;
  Pause(false);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Helper code for the above functions.&lt;br /&gt;
void Pause(bool bIsPaused)&lt;br /&gt;
{&lt;br /&gt;
  if (bIsPaused)&lt;br /&gt;
  {&lt;br /&gt;
    PostMessage(me, &amp;quot;ThisRule&amp;quot;, &amp;quot;Pause&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  else if (!m_bIsThreadRunning)&lt;br /&gt;
  {&lt;br /&gt;
    m_bIsThreadRunning = true;&lt;br /&gt;
    StartThread();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
thread void StartThread(void)&lt;br /&gt;
{&lt;br /&gt;
  while (true)&lt;br /&gt;
  {&lt;br /&gt;
    wait ()&lt;br /&gt;
    {&lt;br /&gt;
    on &amp;quot;ThisRule&amp;quot;, &amp;quot;Pause&amp;quot;:&lt;br /&gt;
      break;&lt;br /&gt;
     ...&lt;br /&gt;
  }&lt;br /&gt;
  m_bIsThreadRunning = false;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Multiple Messages in Flight ==&lt;br /&gt;
It&#039;s possible to post multiple identical messages. This can be useful, but if you&#039;re expecting only one then it can be a source of errors.&lt;br /&gt;
&lt;br /&gt;
In the following pseudocode, each call to SetProperties() will place an additional &amp;quot;Timer&amp;quot;, &amp;quot;Tick&amp;quot; message into the cycle, effectively increasing the rate at which the IdleFunction is called. This will seem to be working for a single call to SetProperties(), which may be all that is called during a trivial testcase. It will probably give reasonable results for a few calls to SetProperties(), although if the function is time-sensitive then the results might be different to expectations. After a larger number of calls to SetProperties(), the object&#039;s message queue may become full, causing it to lose messages at random (perhaps the tick messages, or perhaps other unrelated messages that are more problematic).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
void Init(void)&lt;br /&gt;
{&lt;br /&gt;
  inherited();&lt;br /&gt;
  &lt;br /&gt;
  AddHandler(me, &amp;quot;Timer&amp;quot;, &amp;quot;Tick&amp;quot;, &amp;quot;IdleFunction&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void EnterIdleState(void)&lt;br /&gt;
{&lt;br /&gt;
  IdleFunction();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void IdleFunction(void)&lt;br /&gt;
{&lt;br /&gt;
  PostMessage(me, &amp;quot;Timer&amp;quot;, &amp;quot;Tick&amp;quot;, 1.0);&lt;br /&gt;
  .. do something here ..&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void SetProperties(Soup soup)&lt;br /&gt;
{&lt;br /&gt;
  inherited(soup);&lt;br /&gt;
  &lt;br /&gt;
  EnterIdleState();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A similar problem can occur if you start new threads rather than post new messages.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Thread Guard Variables ==&lt;br /&gt;
It&#039;s common to prevent a singleton thread from being started twice by using a boolean guard variable. Care must be taken to ensure that the guard variable is set and cleared at the correct locations, or they may be ineffective.&lt;br /&gt;
&lt;br /&gt;
The following pseudocode demonstrates one such correct usage. The key points to note are:&lt;br /&gt;
* We set &#039;m_bIsThreadedFunctionRunning&#039; prior to calling the threaded function. Setting it within the threaded function is too late; multiple threads might have already been started before the first thread reaches that point.&lt;br /&gt;
* We don&#039;t confuse whether the thread is actually running with whether we want the thread to be running. Once we ask a thread to start, we can&#039;t stop it starting. If we change our minds and want to stop it again, we must inform it in a way that it will realise after it finishes starting. In the worst-case scenario, we might flipflop on this multiple times before the thread actually starts.&lt;br /&gt;
* Similarly, we don&#039;t rely on messages to control the thread. Enqueuing a separate start or stop message with each StartThread()/StopThread() call might be possible, and we could clear any unwanted prior messages from the object&#039;s queue, but if the thread hasn&#039;t finished starting then it won&#039;t receive the messages anyway.&lt;br /&gt;
* We do rely on messages to wake the thread if it&#039;s waiting on messages, but we don&#039;t use those messages to imply any state - we just have it recheck the current state boolean to get the very latest info.&lt;br /&gt;
* We clear &#039;m_bIsThreadedFunctionRunning&#039; once the decision to exit has become unconditional. At this point, even though the thread is technically still running, we&#039;ll have to start a new thread if we want the thread to continue running.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
bool m_bIsThreadedFunctionRunning = false;&lt;br /&gt;
bool m_bWantThreadedFunctionRunning = false;&lt;br /&gt;
&lt;br /&gt;
void StartThread(void)&lt;br /&gt;
{&lt;br /&gt;
  m_bWantThreadedFunctionRunning = true;&lt;br /&gt;
  &lt;br /&gt;
  if (m_bIsThreadedFunctionRunning)&lt;br /&gt;
    return;&lt;br /&gt;
  &lt;br /&gt;
  m_bIsThreadedFunctionRunning = true;&lt;br /&gt;
  ThreadedFunction();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void StopThread(void)&lt;br /&gt;
{&lt;br /&gt;
  if (!m_bWantThreadedFunctionRunning)&lt;br /&gt;
    return;&lt;br /&gt;
  &lt;br /&gt;
  m_bWantThreadedFunctionRunning = false;&lt;br /&gt;
  PostMessage(me, &amp;quot;Thread&amp;quot;, &amp;quot;Touch&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
thread void ThreadedFunction(void)&lt;br /&gt;
{&lt;br /&gt;
  while (m_bWantThreadedFunctionRunning)&lt;br /&gt;
  {&lt;br /&gt;
    wait()&lt;br /&gt;
    {&lt;br /&gt;
      on &amp;quot;Thread&amp;quot;, &amp;quot;Touch&amp;quot;:&lt;br /&gt;
        break;&lt;br /&gt;
      .. whatever else..&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  m_bIsThreadedFunctionRunning = false;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Not Waiting For Messages ==&lt;br /&gt;
As seen above, it&#039;s possible for a thread to fail to receive posted messages because it wasn&#039;t waiting for them at the time. A more commonly problematic example follows.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
thread void MyThread(void)&lt;br /&gt;
{&lt;br /&gt;
  wait ()&lt;br /&gt;
  {&lt;br /&gt;
    on &amp;quot;Some&amp;quot;, &amp;quot;Condition&amp;quot;:&lt;br /&gt;
      HandleSomeCondition();&lt;br /&gt;
      continue;&lt;br /&gt;
    on &amp;quot;Thread&amp;quot;, &amp;quot;Exit&amp;quot;:&lt;br /&gt;
      break;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void HandleSomeCondition(void)&lt;br /&gt;
{&lt;br /&gt;
  wait ()&lt;br /&gt;
  {&lt;br /&gt;
    on &amp;quot;Some&amp;quot;, &amp;quot;End-Condition&amp;quot;:&lt;br /&gt;
      break;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In this example, the thread is waiting on both &amp;quot;Some&amp;quot;, &amp;quot;Condition&amp;quot; and also &amp;quot;Thread&amp;quot;, &amp;quot;Exit&amp;quot;. Either one will be handled correctly assuming that the thread is already running at the time they are posted. Even if multiple are posted, the thread will simply queue them and run each in turn.&lt;br /&gt;
&lt;br /&gt;
The problem occurs when HandleSomeCondition() is triggered and the thread begins waiting on &amp;quot;Some&amp;quot;, &amp;quot;End-Condition&amp;quot;. In this scenario, the thread is no longer waiting on &amp;quot;Thread&amp;quot;, &amp;quot;Exit&amp;quot;, and any attempt to post that message will simply be ignored. To reiterate: the message dispatch is NOT postponed until the function returns; the message is dropped entirely.&lt;br /&gt;
&lt;br /&gt;
In many cases, the correct behaviour is to move HandleSomeCondition() to a new thread, although that may also carry gotchas that you will need to be careful of (eg. you&#039;ll probably want to terminate the second thread at the same time as the first one, and you may need to consider whether you want multiple of the second thread to run simultaneously or not).&lt;br /&gt;
&lt;br /&gt;
== Performing Actions After Being Told to Stop ==&lt;br /&gt;
In many cases, you may wish to perform cleanup actions when stopping your rule. If your rule is threaded, this can easily become problematic.&lt;br /&gt;
&lt;br /&gt;
Consider the following pseudocode example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
void Pause(bool bIsPaused)&lt;br /&gt;
{&lt;br /&gt;
  if (!bIsPaused &amp;amp;&amp;amp; !m_bIsThreadRunning)&lt;br /&gt;
  {&lt;br /&gt;
    m_bIsThreadRunning = true;&lt;br /&gt;
    MyThread();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
thread void MyThread(void)&lt;br /&gt;
{&lt;br /&gt;
  BeginRule();&lt;br /&gt;
  while (!IsPaused())&lt;br /&gt;
  {&lt;br /&gt;
    Sleep(0.5);&lt;br /&gt;
    UpdateRule();&lt;br /&gt;
  }&lt;br /&gt;
  EndRule();&lt;br /&gt;
  m_bIsThreadRunning = false;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There are three immediately obvious problems:&lt;br /&gt;
&lt;br /&gt;
1. That BeginRule() is called when the thread starts, even if the rule has already been paused again.&lt;br /&gt;
&lt;br /&gt;
2. That UpdateRule() will be called after each sleep, even if the rule was paused during the sleep.&lt;br /&gt;
&lt;br /&gt;
3. That EndRule() will be called after the rule has been paused.&lt;br /&gt;
&lt;br /&gt;
This is very problematic because it likely violates a core principles of the rules system: that rules will not undertake any meaningful behaviour when paused. All three functions may be called while the rule is paused, so unless the rule does nothing meaningful at all, this is a guaranteed violation.&lt;br /&gt;
&lt;br /&gt;
The best approach to resolving this may depend on exactly what these functions do, but one possible solution is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
void Pause(bool bIsPaused)&lt;br /&gt;
{&lt;br /&gt;
  if (bIsPaused)&lt;br /&gt;
  {&lt;br /&gt;
    if (m_bNeedsEndRule)&lt;br /&gt;
    {&lt;br /&gt;
      m_bNeedsEndRule = false;&lt;br /&gt;
      EndRule();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  else&lt;br /&gt;
  {&lt;br /&gt;
    if (!m_bNeedsEndRule)&lt;br /&gt;
    {&lt;br /&gt;
      BeginRule();&lt;br /&gt;
      m_bNeedsEndRule = true;&lt;br /&gt;
    }&lt;br /&gt;
    if (!m_bIsThreadRunning)&lt;br /&gt;
    {&lt;br /&gt;
      m_bIsThreadRunning = true;&lt;br /&gt;
      MyThread();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
thread void MyThread(void)&lt;br /&gt;
{&lt;br /&gt;
  while (!IsPaused())&lt;br /&gt;
  {&lt;br /&gt;
    UpdateRule();&lt;br /&gt;
    Sleep(0.5);&lt;br /&gt;
  }&lt;br /&gt;
  m_bIsThreadRunning = false;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=Session_Rule_Implementation&amp;diff=16830</id>
		<title>Session Rule Implementation</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=Session_Rule_Implementation&amp;diff=16830"/>
		<updated>2018-11-27T17:05:41Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: /* Ordered Execution of Children */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page seeks to clearly define expected script behavior for [[KIND Scenariobehavior|Session Rule assets]]. This focuses specifically on correct behavior from the code perspective, rather than addressing how rules should be designed for best gameplay outcomes.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Legacy Behavior Note =&lt;br /&gt;
Please note that many existing rules do not behave correctly as defined here. This is considered a bug in the individual session rules. [[N3V Games]] has a policy of updating session rules to behave correctly even where that may lead to changes of function in existing [[session]] assets. Where reasonable to achieve, emulation of the existing (buggy) behavior may occur for existing rule instances in existing sessions, however any newly created rule instances will use the corrected behavior.&lt;br /&gt;
&lt;br /&gt;
These expectations were codified at the end of [[TS12]] development due to an increasing inability of session rules to work together resulting from the unpredictable nature of their responses to various common use-cases. The systems as a whole, including most of the core rules discussed in this document, have existed for far longer than this document. The document does not redefine any existing systems, but simply presents the only reasonable implementation approach possible if rules are to be expected to work properly in all use-cases. In some cases we also choose to mandate specific points of behavior relating to user expectations rather than technical necessities.&lt;br /&gt;
&lt;br /&gt;
Certain additional API mechanisms were introduced alongside the development of this document, to allow better communication with session authors regarding the differences in behavior between certain types of rule. The correct usage for these mechanisms is also included in this document.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= The Rule Hierarchy =&lt;br /&gt;
All rules within a given session form a simple tree structure.&lt;br /&gt;
&lt;br /&gt;
== Rule State Flags ==&lt;br /&gt;
Each rule in the tree may have certain associated state flagged, including a combination of the following:&lt;br /&gt;
&lt;br /&gt;
=== PAUSED ===&lt;br /&gt;
The rule is currently paused, meaning that it does not affect the game world in any way and does not respond to any changes in the game world. The parent rule must cause the rule to become unpaused for the rule to have any effect. It is not correct behavior for a rule to unpause itself.&lt;br /&gt;
&lt;br /&gt;
=== COMPLETE ===&lt;br /&gt;
This flag indicates that rule has fully completed its operation (including any child rule operations) and does not affect the game world in any way. This flag is set by the rule itself, not by an outside entity such as the parent. This state should not be changed while the rule is PAUSED.&lt;br /&gt;
&lt;br /&gt;
Being COMPLETE does not imply being PAUSED. In many scenarios, the parent rule may respond to a child becoming COMPLETE by causing it to also become PAUSED, however this is certainly not guaranteed in all cases, and is not guaranteed to be immediate in the cases where it does happen.&lt;br /&gt;
&lt;br /&gt;
The rule may optionally respond to specific changes in the game world by deflagging the COMPLETE status. For example, a rule which specifically implements a condition check may choose to become COMPLETE when that condition is met, but return to an incomplete state when the condition is no longer met (again, remembering that a change in either direction should only happen while the rule itself is not PAUSED).&lt;br /&gt;
&lt;br /&gt;
When a rule&#039;s COMPLETE state changes, a &amp;quot;ScenarioBehavior&amp;quot;, &amp;quot;Touch&amp;quot; message is sent &#039;&#039;&#039;(TBD: BY WHAT MECHANISM?)&#039;&#039;&#039; to its parent rule (if any), unless the parent is in the PAUSED state. This allows the parent to react to changes in its child rules&#039; states. It is important to note that the message indicates a possible change which the parent may be interested in, but it is the parent rule&#039;s responsibility to determine whether the state change is worth reacting to.&lt;br /&gt;
&lt;br /&gt;
=== WAS COMPLETE ===&lt;br /&gt;
This is typically set when a rule first becomes flagged as COMPLETE, and will stay set even if the rule later flags as incomplete. This can be used by a parent which only cares that the child rule has been flagged as COMPLETE at some point, rather than caring what its current completion status is.&lt;br /&gt;
&lt;br /&gt;
=== DOES COMPLETE ===&lt;br /&gt;
This indicates whether the rule can ever reach the COMPLETE state. Its value is constant for a given rule configuration, and does not change based on the runtime rule state or other game state. Rules which are flagged as DOES COMPLETE are expected to become complete after some discreet operations are completed. Rules which are not flagged are expected to run indefinitely unless PAUSED by an external agent (such as the parent rule).&lt;br /&gt;
&lt;br /&gt;
== Initial State ==&lt;br /&gt;
All rules are initially in the PAUSED state when in [[Surveyor]], and only become unpaused after gameplay begins in a [[Driver]] session. Since a PAUSED rule is not permitted to unpause itself, this is a stable state which will persist until the native code takes step to begin program flow.&lt;br /&gt;
&lt;br /&gt;
== Top Level Rules ==&lt;br /&gt;
All rules at the top level (ie. rules which are not a child of any other rule) simultaneously become unpaused after the session has loaded into Driver. Some of these rules may take initial setup steps and then become COMPLETE. Some of these rules may begin monitoring for specific game conditions before taking any further action. Some of these rules may begin taking action immediately. The rules are not sequenced against each other in any way, and it is the session author&#039;s responsibility to ensure that this does not cause any conflicts.&lt;br /&gt;
&lt;br /&gt;
== Scheduling ==&lt;br /&gt;
Since the script VM is a cooperatively-threaded environment, it is technically true that rule evaluation will occur in an ordered manner rather than truly simultaneously. However, no guarantees are made regarding the order in which the simultaneously-running rules will perform their checks or outcomes. Since rules may wait internally rather than fulfilling their entire purpose in an atomic operation, it is also not guaranteed that a first-running rule will fully complete before some other simultaneously-executing rule begins completion. In short, if order-of-execution is critical to the correct behavior of a session, then the order should be enforced by the session creator using the rule hierarchy rather than by making assumptions about execution order of simultaneously-running rules.&lt;br /&gt;
&lt;br /&gt;
(Note: with the introduction of [[Asynchronous Route Streaming]], this is even more true than previously. What may have been a near-instantaneous operation in older builds may now require a wait of several seconds while the necessary data is streamed in.)&lt;br /&gt;
&lt;br /&gt;
It is important to note that some conditional rules may partially or completely rely on a polling behavior to evaluate their conditions. (An example of partial reliance is a rule which waits for an event, but then evaluates a condition to clarify whether the event should be acted upon.) In these cases, it is possible that the condition can rapidly become true and then become false again without the rule responding. This results in an uncertainty as to whether the conditional rule will correctly detect a given instance of the condition. This type of scenario should be avoided completely where possible, and should most definitely be limited to outcomes that do not significantly affect gameplay.&lt;br /&gt;
&lt;br /&gt;
For a hypothetical example, if the player&#039;s train speeds for 0.5sec, and a speeding check rule was implemented that polled every second, then the overspeed event may or may not trigger on any given occurrence. A session creator should not use this outcome as a failure condition, since some players may be able to speed without penalty, whereas other players would be penalised on the first attempt. A sensible solution in this case might be to increment a counter while speeding is detected, and only take action if the counter reaches a certain threshold. If the only penalty was a warning to the player which had no actual gameplay impact, then it might be acceptable to forgo this check and simply accept that some players will receive a warning where others may not.&lt;br /&gt;
&lt;br /&gt;
==Child Rules==&lt;br /&gt;
As with all other rules, child rules (ie. those that have parent rules in the hierarchy) start out in the PAUSED state. They do not become unpaused until the parent is ready for the children to start operating. Exactly when this occurs depends on the specific parent rule, but the general flow is the same for all rules:&lt;br /&gt;
&lt;br /&gt;
1. Parent rule becomes unpaused and begins operation.&lt;br /&gt;
&lt;br /&gt;
2. Parent rule configures any necessary world state changes.&lt;br /&gt;
&lt;br /&gt;
3. Parent rule optionally waits for a specific condition to occur.&lt;br /&gt;
&lt;br /&gt;
4. Parent rule begins executing its children. This involves unpausing one or more of the children (as discussed below in &amp;quot;Parent Rule Styles&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
5. Parent waits for its children to complete (as discussed below in &amp;quot;Parent Rule Styles&amp;quot;) and then pauses the children.&lt;br /&gt;
&lt;br /&gt;
6. Parent flags itself as COMPLETE.&lt;br /&gt;
&lt;br /&gt;
This process allows program control flow to pass from a top-level rule, to its immediate children, to their immediate children, and so on. As the bottom-level children become complete, completion flows back to the higher level children until finally the top-level rules become COMPLETE.&lt;br /&gt;
&lt;br /&gt;
It is worth noting that there is nothing special about a top-level rule being flagged as COMPLETE. This does not indicate an end-of-session or any other fundamental gameplay mode change. Since the pausing of rules on completion is handled by the parent rule (see step 5 above), the top-level rules never become PAUSED on completion.&lt;br /&gt;
&lt;br /&gt;
==Parent Rule Styles==&lt;br /&gt;
There are a few common techniques with which parent rules interact with their children. Rules should always fit one of these descriptions. The vast majority of rules should follow either the &amp;quot;Does Not Support Children&amp;quot; style, or the &amp;quot;Ordered Execution of Children&amp;quot; style.&lt;br /&gt;
&lt;br /&gt;
=== Does Not Support Children ===&lt;br /&gt;
The rule is incapable of supporting children and will always ignore them.&lt;br /&gt;
&lt;br /&gt;
This is used for trivial rules which perform a set function and then become permanently COMPLETE. Such rules are not conditional and do not wait for any world state changes except those which they initiate internally.&lt;br /&gt;
The rule should be configured to validate and/or enforce that no child rules can be added.&lt;br /&gt;
&lt;br /&gt;
=== Simultaneous Execution of Children ===&lt;br /&gt;
When the rule is ready to begin executing children, it unpauses all children simultaneously. The rule then waits for all children to flag as WAS COMPLETE. Once this is detected, the rule pauses all children and flags itself as COMPLETE.&lt;br /&gt;
This is used for rules which have a specific need to simultaneously execute children, such as the &amp;quot;Simultaneous List&amp;quot; rule.&lt;br /&gt;
&lt;br /&gt;
The rule editor interface should be explicit that child rules will be executed simultaneously. Child rules should be tagged appropriately in the rule editor list to denote unordered execution.&lt;br /&gt;
&lt;br /&gt;
=== Ordered Execution of Children ===&lt;br /&gt;
When the rule is ready to begin executing children, it iterates through the children in top-to-bottom order. If the child is flagged as WAS COMPLETE, the child is paused and iteration continues. If the child is not flagged as WAS COMPLETE, the child is unpaused and iteration ends. Whenever a child state change is detected, this process is repeated from the start. Once iteration passes over all children without leaving any child unpaused, the rule flags itself as COMPLETE.&lt;br /&gt;
&lt;br /&gt;
This style is used for all rules which do not explicitly fall under one of the other styles described here. Almost all third-party rules will follow this style. Implementing one of the other styles without there being a fundamental requirement to do so is considered a programming error.&lt;br /&gt;
&lt;br /&gt;
Rules which follow this style should derive from [[ConditionalScenarioBehavior]] in order to avoid re-implementing the control flow logic, as it is exceedingly complex to implement correctly. Any rules which do not derive from ConditionalScenarioBehavior should be accompanied by a clear explanation of the reasons that ConditionalScenarioBehavior is an unsuitable base class for the intended behavior. Rules which do derive from ConditionalScenarioBehavior should avoid complex overrides of the default logic.&lt;br /&gt;
&lt;br /&gt;
Child rules should be tagged appropriately in the rule editor list to denote execution order.&lt;br /&gt;
&lt;br /&gt;
=== Controlled Selection of a Single Child ===&lt;br /&gt;
When the rule is ready to begin executing children, it selects a single child and unpauses it. All other children remain paused. Once the selected child becomes flagged as WAS COMPLETE, the child is paused and the rule flags itself as COMPLETE.&lt;br /&gt;
&lt;br /&gt;
This style is used where complex conditional selection of child rules is required. This can be used to implement an &amp;quot;if-else&amp;quot; logic flow, a &amp;quot;switch-case&amp;quot; logic flow, or the &amp;quot;Random List&amp;quot; rule. This style should not be used to implement a simple &amp;quot;if&amp;quot; logic flow, because that would unnecessarily restrict the rule to a single child where the &amp;quot;Ordered Execution of Children&amp;quot; style would provide the same functionality while allowing multiple children.&lt;br /&gt;
The rule editor interface should be very explicit about how the child rules will be selected. Child rules should be tagged appropriately in the rule editor list to avoid the user attempting to fit a child rule into the wrong role.&lt;br /&gt;
&lt;br /&gt;
=== Custom Execution with Multiple Children ===&lt;br /&gt;
This style is used for very specific custom-purpose rules, such as a passenger station stop handler. Such rules should give a clear and complete explanation of their operation and their interaction with any child rules in the rule editor interface.&lt;br /&gt;
&lt;br /&gt;
Individual child rules may be executed in an ad-hoc manner by the rule in response to changes in game state. Child rules may or may not be executed simultaneously and may or may not be executed repeatedly depending on the rule; any limitations or gotchas deriving from this should be carefully explained in the rule editor interface.&lt;br /&gt;
&lt;br /&gt;
Child rules should be tagged appropriately in the rule editor list to avoid the user attempting to fit a child rule into the wrong role.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Early Termination via Pause =&lt;br /&gt;
A rule must accept being paused by its parent at any time. This should cause the rule to cease any game state monitoring or other direct effects. The rule must pause all child rules immediately.&lt;br /&gt;
&lt;br /&gt;
In cases where the rule is maintaining some reversible effect on the game world, pausing the rule should end this effect. For example, a rule which displays a message to the user should typically hide the message upon becoming paused, and a rule which causes a rain storm in a specific area should return the weather to normal upon becoming paused. Rules which make a single permanent change to the game world and then immediately flag as COMPLETE should not attempt to reverse the change upon becoming paused. Examples of these rules include configuration of the global weather conditions, or a rule which increments the player&#039;s score or penalty counter.&lt;br /&gt;
&lt;br /&gt;
It is important to note that any pause is resumable, although the parent may not choose to take advantage of this. Pausing a rule followed by unpausing it should result in the rule continuing operation where it left off. The notes on Saving and Loading Driver Sessions (below) are worth considering when evaluating techniques for implementing pause.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Early Termination via Internal Logic =&lt;br /&gt;
In some cases, a rule may begin executing child rules but then make an internal decision to abort execution. This typically occurs in conditional rules where the condition may be re-evaluated as false after it has already been evaluated as true. Such behavior should be made explicit in the rule editor interface and should usually be made optional by providing a checkbox.&lt;br /&gt;
&lt;br /&gt;
There are in fact several possible behavioral variants affecting how condition-deflag is interpreted:&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules and no further evaluation is performed. The rule eventually flags itself as COMPLETE and does not later deflag this.&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules. If the condition becomes deflagged, the child rules are paused. If the condition becomes flagged again, the child rules are continued. Once the child rules have fully completed execution, the rule flags itself as COMPLETE and does not later deflag this.&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules. If the condition becomes deflagged, the child rules are paused. If the condition becomes flagged again, the children are reset and execution starts anew. The rule flags itself as COMPLETE if all children successfully complete, but it will deflag if the condition deflags.&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules. If the condition becomes deflagged, the child rules continue executing. If the condition becomes flagged again, the children are reset and execution starts anew. The rule will flag as COMPLETE if all children successfully complete, but it will deflag if the condition deflags.&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules. The child rules continue execution with no regard for whether the condition changes between flagged or deflagged in either direction. If the condition transitions from deflagged to flagged again after the children have completed, the children are reset and execution starts anew. The rule will flag as COMPLETE if all children successfully complete, but it will deflag itself if the condition deflags. &lt;br /&gt;
&lt;br /&gt;
The complexity here derives from the fact that it is not possible to use the same set of rules multiple times concurrently for different trigger conditions. For example, if a set of rules is used to give demerit points and provide user notifications, and those rules live under a single conditional check which determines whether a train is speeding, it may be difficult to define what should happen if two trains are detected as speeding at the same time, or if a train stops speeding while the notification process is still in progress. It is not always possible to achieve a perfect solution to tracking multiple objects using a single set of rules, but correct selection from the above behaviors can minimise the possibility of serious side-effects.&lt;br /&gt;
&lt;br /&gt;
It is important to note that these behaviors describe how the rule reacts to internal condition checks. The rule&#039;s reaction to being paused by its parent is discussed above under &amp;quot;Early Termination via Pause&amp;quot; and is not affected by the description here.&lt;br /&gt;
&lt;br /&gt;
In short, there are many ways of handling this, and the important thing is for your (parent) rule to clearly explain which approach it is going to use.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Rule Reset =&lt;br /&gt;
A rule may be &#039;&#039;reset&#039;&#039; by its parent. This causes both the COMPLETE and WAS COMPLETE states to be deflagged. Individual rules may also react to the reset by modifying their internal state to forget past or present actions. Parent rules must also cause their children to be reset in turn.&lt;br /&gt;
&lt;br /&gt;
This mechanism is used to permit rules to be used in a repeating scenario, such as responding to a condition which can occur multiple times, or in a repeating loop. At some point after a rule has become flagged as WAS COMPLETE, it will typically become paused and will not be unpaused again. If the rule is to be included in some repeating behavior, this would normally prevent the behavior from operating successfully after the first run through. To avoid this, the parent rule responsible for implementing the repeating behavior will &#039;&#039;reset&#039;&#039; all children when a repeat occurs. This effectively cleans the rules back to their initial state ready to perform their roles again.&lt;br /&gt;
&lt;br /&gt;
It is important to note that a reset should cause the rule to return to its configured settings. For example, if a timer value is configured and is decremented during rule operation, the timer must be reset back to its initial value during rule reset.&lt;br /&gt;
&lt;br /&gt;
It is important to note that there is no requirement to pause a rule prior to resetting it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Saving and Loading Driver Sessions =&lt;br /&gt;
For better or worse, the script VM does not persist across a save/load operation. This means that each rule must correctly save both its configuration state and its runtime state, and must correctly reload those such that the state after a save/load operation is indistinguishable from the original state. The following aspects of the script state must be considered:&lt;br /&gt;
&lt;br /&gt;
* Member variables in the Rule instance.&lt;br /&gt;
* Which threads are running on the Rule instance, and where they are up to in the code flow.&lt;br /&gt;
* Local variables on the stack of each running thread.&lt;br /&gt;
* Non-persistent changes made to the state of other script objects (such as active &#039;sniff&#039; statements).&lt;br /&gt;
* Script Messages which might be in flight at the time of save (these are not persisted, so the net effect is that they are simply deleted between the save and the load.)&lt;br /&gt;
&lt;br /&gt;
Since the game state continues normal operation after a Save, no code flow or other behavioral changes should result from the Save operation itself. Instead, the Save operation (and the design of the rule as a whole) is responsible for ensuring that sufficient data is persisted in the save file such that the Load operation is able to restore to the correct running state.&lt;br /&gt;
&lt;br /&gt;
The rule base class, ScenarioBehavior, is responsible for saving and loading the rule state flags (COMPLETE, PAUSED, WAS COMPLETE, etc.) A rule which was paused at Save time will still be paused after the Load. A rule which was complete at Save time will still be complete after the Load. During a Load operation, the rule should inherit the parent class&#039; SetProperties() method so that these flags are correctly configured, then honor the paused state during the rest of the loading process.&lt;br /&gt;
&lt;br /&gt;
It is rarely appropriate for an unpaused rule to simply restart execution from the beginning. Care must be taken to ensure that execution resumes from the point that it left off at the time of saving. This process can be simplified by keeping as much state as possible in the rule member variables at all times, and only keeping reconstructible temporary values on the stack. If the member variables are correctly stored and restored, this approach will allow the loading process to detect the runtime state of the rule and resume any necessary threads, which will in turn be able to jump forward to the correct area of the code based on the stored state.&lt;br /&gt;
&lt;br /&gt;
Finally, the COMPLETE, WAS COMPLETE, and PAUSED flags on child rules should be honored. This is typically sufficient information to determine the running state of child rules, so no further state will generally need to be maintained. More accurately, the child rules take care of their own state at all times, and the parent only needs to react to changes in the child state. Since no child state change occurs across a Save/Load operation, the parent does not need to become involved.&lt;br /&gt;
&lt;br /&gt;
For rules which derive ConditionalScenarioBehavior, the majority of load/save logic is handled automatically. The only state information that such a rule should typically preserve is the instance-specific configuration data. The condition-monitor thread will be automatically restarted as required, and there is generally no need to distinguish between a first-startup and any subsequent startup.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Spurious Events =&lt;br /&gt;
There are various events (typically script messages) that a rule may listen for in order to detect state changes. It is important to note that spurious events are often possible, and that an event handler should often be coupled with a condition check. As a specific example, the &amp;quot;ScenarioBehavior&amp;quot;, &amp;quot;Touch&amp;quot; message typically indicates that a child state has changed, but the message may in fact be sent at any time. This message should prompt the rule to evaluate whether any state changes are necessary, but the rule should not simply assume that a state change is necessary without performing an evaluation.&lt;br /&gt;
&lt;br /&gt;
Similarly, calls to a function such as Pause() may in some cases have no effect. For example, if a rule is already executing and its parent calls Pause(false), the rule should not pause, reset, or change state in any way at all. Similarly, if a rule is already paused and its parent calls Pause(true), the rule should not unpause, reset, fire any events, or otherwise change state in any way at all.&lt;br /&gt;
&lt;br /&gt;
The short version is: do not assume that every event and every method call is supposed to achieve something meaningful. Check first, and if the event is meaningless to you then do nothing at all.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Future Considerations =&lt;br /&gt;
Rules should base their functionality on the state flags such as the PAUSED state, rather than attempting to detect and vary their functionality based on the state of the game.&lt;br /&gt;
&lt;br /&gt;
For example, we currently (in development builds) expose the rules editor in Driver for debugging purposes. This, or some mechanism like it, is likely to be included in public builds in the future. Rules should not assume that it is impossible to be reconfigured during gameplay. This will of course introduce some side effects, such as when an unpaused rule is modified during execution. It is the rule&#039;s responsibility to ensure that these side effects do not lead to script exceptions or to leaked state. For example, if a single thread is supposed to be running, reconfiguring the rule should not cause a second thread to run simultaneously. If a rule sniffs a target vehicle, and the target vehicle is redefined, then the rule should unsniff the original vehicle rather than now sniffing two vehicles.&lt;br /&gt;
&lt;br /&gt;
Likewise, we may in future allow some form of partial state swap between Driver and Surveyor. Rules should not assume that it is impossible to change from any one game state or module to any other game state or module, just because it is not possible at the current time. APIs already exist to detect such state changes where necessary, and in most cases it&#039;s simply not necessary to care whether your rule is in Surveyor or Driver - you should act based on the PAUSED state instead. Rules should deal with the game state as they find it rather than assuming that certain states will not ever occur.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Gotchas =&lt;br /&gt;
There are a few potential gotchas in the script environment that are worth considering when writing any non-trivial rule.&lt;br /&gt;
&lt;br /&gt;
== Response Latency ==&lt;br /&gt;
Scripts tend to rely heavily on message passing and threading. In both cases, there is a delay between triggering a certain behavior (eg. posting an event, or calling a threaded function) and having the receiving code react. Other code may execute during this delay.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
// Calling this might be expected to start and then stop the thread; in reality it&lt;br /&gt;
// will likely simply start the thread and leave it running, because the message&lt;br /&gt;
// is sent prior to the wait() statement starting.&lt;br /&gt;
void DemonstrateBug1(void)&lt;br /&gt;
{&lt;br /&gt;
  Pause(false);&lt;br /&gt;
  Pause(true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// In this case, we use a Sleep() statement to &amp;quot;ensure&amp;quot; that the thread has&lt;br /&gt;
// finished starting. This isn&#039;t actually reliable, but it works as long as the&lt;br /&gt;
// system isn&#039;t under too much load. We follow this up with a rapid pause-&lt;br /&gt;
// unpause sequence. As above, this doesn&#039;t work - the message is sent,&lt;br /&gt;
// then the function immediately checks whether the thread is still running&lt;br /&gt;
// (which it is) and thus the thread isn&#039;t restarted. The function completes,&lt;br /&gt;
// and finally the thread receives the message and exits.&lt;br /&gt;
void DemonstrateBug2(void)&lt;br /&gt;
{&lt;br /&gt;
  Pause(false);&lt;br /&gt;
  Sleep(1.0);&lt;br /&gt;
  Pause(true);&lt;br /&gt;
  Pause(false);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Helper code for the above functions.&lt;br /&gt;
void Pause(bool bIsPaused)&lt;br /&gt;
{&lt;br /&gt;
  if (bIsPaused)&lt;br /&gt;
  {&lt;br /&gt;
    PostMessage(me, &amp;quot;ThisRule&amp;quot;, &amp;quot;Pause&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  else if (!m_bIsThreadRunning)&lt;br /&gt;
  {&lt;br /&gt;
    m_bIsThreadRunning = true;&lt;br /&gt;
    StartThread();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
thread void StartThread(void)&lt;br /&gt;
{&lt;br /&gt;
  while (true)&lt;br /&gt;
  {&lt;br /&gt;
    wait ()&lt;br /&gt;
    {&lt;br /&gt;
    on &amp;quot;ThisRule&amp;quot;, &amp;quot;Pause&amp;quot;:&lt;br /&gt;
      break;&lt;br /&gt;
     ...&lt;br /&gt;
  }&lt;br /&gt;
  m_bIsThreadRunning = false;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Multiple Messages in Flight ==&lt;br /&gt;
It&#039;s possible to post multiple identical messages. This can be useful, but if you&#039;re expecting only one then it can be a source of errors.&lt;br /&gt;
&lt;br /&gt;
In the following pseudocode, each call to SetProperties() will place an additional &amp;quot;Timer&amp;quot;, &amp;quot;Tick&amp;quot; message into the cycle, effectively increasing the rate at which the IdleFunction is called. This will seem to be working for a single call to SetProperties(), which may be all that is called during a trivial testcase. It will probably give reasonable results for a few calls to SetProperties(), although if the function is time-sensitive then the results might be different to expectations. After a larger number of calls to SetProperties(), the object&#039;s message queue may become full, causing it to lose messages at random (perhaps the tick messages, or perhaps other unrelated messages that are more problematic).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
void Init(void)&lt;br /&gt;
{&lt;br /&gt;
  inherited();&lt;br /&gt;
  &lt;br /&gt;
  AddHandler(me, &amp;quot;Timer&amp;quot;, &amp;quot;Tick&amp;quot;, &amp;quot;IdleFunction&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void EnterIdleState(void)&lt;br /&gt;
{&lt;br /&gt;
  IdleFunction();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void IdleFunction(void)&lt;br /&gt;
{&lt;br /&gt;
  PostMessage(me, &amp;quot;Timer&amp;quot;, &amp;quot;Tick&amp;quot;, 1.0);&lt;br /&gt;
  .. do something here ..&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void SetProperties(Soup soup)&lt;br /&gt;
{&lt;br /&gt;
  inherited(soup);&lt;br /&gt;
  &lt;br /&gt;
  EnterIdleState();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A similar problem can occur if you start new threads rather than post new messages.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Thread Guard Variables ==&lt;br /&gt;
It&#039;s common to prevent a singleton thread from being started twice by using a boolean guard variable. Care must be taken to ensure that the guard variable is set and cleared at the correct locations, or they may be ineffective.&lt;br /&gt;
&lt;br /&gt;
The following pseudocode demonstrates one such correct usage. The key points to note are:&lt;br /&gt;
* We set &#039;m_bIsThreadedFunctionRunning&#039; prior to calling the threaded function. Setting it within the threaded function is too late; multiple threads might have already been started before the first thread reaches that point.&lt;br /&gt;
* We don&#039;t confuse whether the thread is actually running with whether we want the thread to be running. Once we ask a thread to start, we can&#039;t stop it starting. If we change our minds and want to stop it again, we must inform it in a way that it will realise after it finishes starting. In the worst-case scenario, we might flipflop on this multiple times before the thread actually starts.&lt;br /&gt;
* Similarly, we don&#039;t rely on messages to control the thread. Enqueuing a separate start or stop message with each StartThread()/StopThread() call might be possible, and we could clear any unwanted prior messages from the object&#039;s queue, but if the thread hasn&#039;t finished starting then it won&#039;t receive the messages anyway.&lt;br /&gt;
* We do rely on messages to wake the thread if it&#039;s waiting on messages, but we don&#039;t use those messages to imply any state - we just have it recheck the current state boolean to get the very latest info.&lt;br /&gt;
* We clear &#039;m_bIsThreadedFunctionRunning&#039; once the decision to exit has become unconditional. At this point, even though the thread is technically still running, we&#039;ll have to start a new thread if we want the thread to continue running.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
bool m_bIsThreadedFunctionRunning = false;&lt;br /&gt;
bool m_bWantThreadedFunctionRunning = false;&lt;br /&gt;
&lt;br /&gt;
void StartThread(void)&lt;br /&gt;
{&lt;br /&gt;
  m_bWantThreadedFunctionRunning = true;&lt;br /&gt;
  &lt;br /&gt;
  if (m_bIsThreadedFunctionRunning)&lt;br /&gt;
    return;&lt;br /&gt;
  &lt;br /&gt;
  m_bIsThreadedFunctionRunning = true;&lt;br /&gt;
  ThreadedFunction();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void StopThread(void)&lt;br /&gt;
{&lt;br /&gt;
  if (!m_bWantThreadedFunctionRunning)&lt;br /&gt;
    return;&lt;br /&gt;
  &lt;br /&gt;
  m_bWantThreadedFunctionRunning = false;&lt;br /&gt;
  PostMessage(me, &amp;quot;Thread&amp;quot;, &amp;quot;Touch&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
thread void ThreadedFunction(void)&lt;br /&gt;
{&lt;br /&gt;
  while (m_bWantThreadedFunctionRunning)&lt;br /&gt;
  {&lt;br /&gt;
    wait()&lt;br /&gt;
    {&lt;br /&gt;
      on &amp;quot;Thread&amp;quot;, &amp;quot;Touch&amp;quot;:&lt;br /&gt;
        break;&lt;br /&gt;
      .. whatever else..&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  m_bIsThreadedFunctionRunning = false;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Not Waiting For Messages ==&lt;br /&gt;
As seen above, it&#039;s possible for a thread to fail to receive posted messages because it wasn&#039;t waiting for them at the time. A more commonly problematic example follows.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
thread void MyThread(void)&lt;br /&gt;
{&lt;br /&gt;
  wait ()&lt;br /&gt;
  {&lt;br /&gt;
    on &amp;quot;Some&amp;quot;, &amp;quot;Condition&amp;quot;:&lt;br /&gt;
      HandleSomeCondition();&lt;br /&gt;
      continue;&lt;br /&gt;
    on &amp;quot;Thread&amp;quot;, &amp;quot;Exit&amp;quot;:&lt;br /&gt;
      break;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void HandleSomeCondition(void)&lt;br /&gt;
{&lt;br /&gt;
  wait ()&lt;br /&gt;
  {&lt;br /&gt;
    on &amp;quot;Some&amp;quot;, &amp;quot;End-Condition&amp;quot;:&lt;br /&gt;
      break;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In this example, the thread is waiting on both &amp;quot;Some&amp;quot;, &amp;quot;Condition&amp;quot; and also &amp;quot;Thread&amp;quot;, &amp;quot;Exit&amp;quot;. Either one will be handled correctly assuming that the thread is already running at the time they are posted. Even if multiple are posted, the thread will simply queue them and run each in turn.&lt;br /&gt;
&lt;br /&gt;
The problem occurs when HandleSomeCondition() is triggered and the thread begins waiting on &amp;quot;Some&amp;quot;, &amp;quot;End-Condition&amp;quot;. In this scenario, the thread is no longer waiting on &amp;quot;Thread&amp;quot;, &amp;quot;Exit&amp;quot;, and any attempt to post that message will simply be ignored. To reiterate: the message dispatch is NOT postponed until the function returns; the message is dropped entirely.&lt;br /&gt;
&lt;br /&gt;
In many cases, the correct behaviour is to move HandleSomeCondition() to a new thread, although that may also carry gotchas that you will need to be careful of (eg. you&#039;ll probably want to terminate the second thread at the same time as the first one, and you may need to consider whether you want multiple of the second thread to run simultaneously or not).&lt;br /&gt;
&lt;br /&gt;
== Performing Actions After Being Told to Stop ==&lt;br /&gt;
In many cases, you may wish to perform cleanup actions when stopping your rule. If your rule is threaded, this can easily become problematic.&lt;br /&gt;
&lt;br /&gt;
Consider the following pseudocode example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
void Pause(bool bIsPaused)&lt;br /&gt;
{&lt;br /&gt;
  if (!bIsPaused &amp;amp;&amp;amp; !m_bIsThreadRunning)&lt;br /&gt;
  {&lt;br /&gt;
    m_bIsThreadRunning = true;&lt;br /&gt;
    MyThread();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
thread void MyThread(void)&lt;br /&gt;
{&lt;br /&gt;
  BeginRule();&lt;br /&gt;
  while (!IsPaused())&lt;br /&gt;
  {&lt;br /&gt;
    Sleep(0.5);&lt;br /&gt;
    UpdateRule();&lt;br /&gt;
  }&lt;br /&gt;
  EndRule();&lt;br /&gt;
  m_bIsThreadRunning = false;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There are three immediately obvious problems:&lt;br /&gt;
&lt;br /&gt;
1. That BeginRule() is called when the thread starts, even if the rule has already been paused again.&lt;br /&gt;
&lt;br /&gt;
2. That UpdateRule() will be called after each sleep, even if the rule was paused during the sleep.&lt;br /&gt;
&lt;br /&gt;
3. That EndRule() will be called after the rule has been paused.&lt;br /&gt;
&lt;br /&gt;
This is very problematic because it likely violates a core principles of the rules system: that rules will not undertake any meaningful behaviour when paused. All three functions may be called while the rule is paused, so unless the rule does nothing meaningful at all, this is a guaranteed violation.&lt;br /&gt;
&lt;br /&gt;
The best approach to resolving this may depend on exactly what these functions do, but one possible solution is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
void Pause(bool bIsPaused)&lt;br /&gt;
{&lt;br /&gt;
  if (bIsPaused)&lt;br /&gt;
  {&lt;br /&gt;
    if (m_bNeedsEndRule)&lt;br /&gt;
    {&lt;br /&gt;
      m_bNeedsEndRule = false;&lt;br /&gt;
      EndRule();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  else&lt;br /&gt;
  {&lt;br /&gt;
    if (!m_bNeedsEndRule)&lt;br /&gt;
    {&lt;br /&gt;
      BeginRule();&lt;br /&gt;
      m_bNeedsEndRule = true;&lt;br /&gt;
    }&lt;br /&gt;
    if (!m_bIsThreadRunning)&lt;br /&gt;
    {&lt;br /&gt;
      m_bIsThreadRunning = true;&lt;br /&gt;
      MyThread();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
thread void MyThread(void)&lt;br /&gt;
{&lt;br /&gt;
  while (!IsPaused())&lt;br /&gt;
  {&lt;br /&gt;
    UpdateRule();&lt;br /&gt;
    Sleep(0.5);&lt;br /&gt;
  }&lt;br /&gt;
  m_bIsThreadRunning = false;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=Session_Rule_Implementation&amp;diff=16829</id>
		<title>Session Rule Implementation</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=Session_Rule_Implementation&amp;diff=16829"/>
		<updated>2018-11-27T17:04:47Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: /* Child Rules */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page seeks to clearly define expected script behavior for [[KIND Scenariobehavior|Session Rule assets]]. This focuses specifically on correct behavior from the code perspective, rather than addressing how rules should be designed for best gameplay outcomes.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Legacy Behavior Note =&lt;br /&gt;
Please note that many existing rules do not behave correctly as defined here. This is considered a bug in the individual session rules. [[N3V Games]] has a policy of updating session rules to behave correctly even where that may lead to changes of function in existing [[session]] assets. Where reasonable to achieve, emulation of the existing (buggy) behavior may occur for existing rule instances in existing sessions, however any newly created rule instances will use the corrected behavior.&lt;br /&gt;
&lt;br /&gt;
These expectations were codified at the end of [[TS12]] development due to an increasing inability of session rules to work together resulting from the unpredictable nature of their responses to various common use-cases. The systems as a whole, including most of the core rules discussed in this document, have existed for far longer than this document. The document does not redefine any existing systems, but simply presents the only reasonable implementation approach possible if rules are to be expected to work properly in all use-cases. In some cases we also choose to mandate specific points of behavior relating to user expectations rather than technical necessities.&lt;br /&gt;
&lt;br /&gt;
Certain additional API mechanisms were introduced alongside the development of this document, to allow better communication with session authors regarding the differences in behavior between certain types of rule. The correct usage for these mechanisms is also included in this document.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= The Rule Hierarchy =&lt;br /&gt;
All rules within a given session form a simple tree structure.&lt;br /&gt;
&lt;br /&gt;
== Rule State Flags ==&lt;br /&gt;
Each rule in the tree may have certain associated state flagged, including a combination of the following:&lt;br /&gt;
&lt;br /&gt;
=== PAUSED ===&lt;br /&gt;
The rule is currently paused, meaning that it does not affect the game world in any way and does not respond to any changes in the game world. The parent rule must cause the rule to become unpaused for the rule to have any effect. It is not correct behavior for a rule to unpause itself.&lt;br /&gt;
&lt;br /&gt;
=== COMPLETE ===&lt;br /&gt;
This flag indicates that rule has fully completed its operation (including any child rule operations) and does not affect the game world in any way. This flag is set by the rule itself, not by an outside entity such as the parent. This state should not be changed while the rule is PAUSED.&lt;br /&gt;
&lt;br /&gt;
Being COMPLETE does not imply being PAUSED. In many scenarios, the parent rule may respond to a child becoming COMPLETE by causing it to also become PAUSED, however this is certainly not guaranteed in all cases, and is not guaranteed to be immediate in the cases where it does happen.&lt;br /&gt;
&lt;br /&gt;
The rule may optionally respond to specific changes in the game world by deflagging the COMPLETE status. For example, a rule which specifically implements a condition check may choose to become COMPLETE when that condition is met, but return to an incomplete state when the condition is no longer met (again, remembering that a change in either direction should only happen while the rule itself is not PAUSED).&lt;br /&gt;
&lt;br /&gt;
When a rule&#039;s COMPLETE state changes, a &amp;quot;ScenarioBehavior&amp;quot;, &amp;quot;Touch&amp;quot; message is sent &#039;&#039;&#039;(TBD: BY WHAT MECHANISM?)&#039;&#039;&#039; to its parent rule (if any), unless the parent is in the PAUSED state. This allows the parent to react to changes in its child rules&#039; states. It is important to note that the message indicates a possible change which the parent may be interested in, but it is the parent rule&#039;s responsibility to determine whether the state change is worth reacting to.&lt;br /&gt;
&lt;br /&gt;
=== WAS COMPLETE ===&lt;br /&gt;
This is typically set when a rule first becomes flagged as COMPLETE, and will stay set even if the rule later flags as incomplete. This can be used by a parent which only cares that the child rule has been flagged as COMPLETE at some point, rather than caring what its current completion status is.&lt;br /&gt;
&lt;br /&gt;
=== DOES COMPLETE ===&lt;br /&gt;
This indicates whether the rule can ever reach the COMPLETE state. Its value is constant for a given rule configuration, and does not change based on the runtime rule state or other game state. Rules which are flagged as DOES COMPLETE are expected to become complete after some discreet operations are completed. Rules which are not flagged are expected to run indefinitely unless PAUSED by an external agent (such as the parent rule).&lt;br /&gt;
&lt;br /&gt;
== Initial State ==&lt;br /&gt;
All rules are initially in the PAUSED state when in [[Surveyor]], and only become unpaused after gameplay begins in a [[Driver]] session. Since a PAUSED rule is not permitted to unpause itself, this is a stable state which will persist until the native code takes step to begin program flow.&lt;br /&gt;
&lt;br /&gt;
== Top Level Rules ==&lt;br /&gt;
All rules at the top level (ie. rules which are not a child of any other rule) simultaneously become unpaused after the session has loaded into Driver. Some of these rules may take initial setup steps and then become COMPLETE. Some of these rules may begin monitoring for specific game conditions before taking any further action. Some of these rules may begin taking action immediately. The rules are not sequenced against each other in any way, and it is the session author&#039;s responsibility to ensure that this does not cause any conflicts.&lt;br /&gt;
&lt;br /&gt;
== Scheduling ==&lt;br /&gt;
Since the script VM is a cooperatively-threaded environment, it is technically true that rule evaluation will occur in an ordered manner rather than truly simultaneously. However, no guarantees are made regarding the order in which the simultaneously-running rules will perform their checks or outcomes. Since rules may wait internally rather than fulfilling their entire purpose in an atomic operation, it is also not guaranteed that a first-running rule will fully complete before some other simultaneously-executing rule begins completion. In short, if order-of-execution is critical to the correct behavior of a session, then the order should be enforced by the session creator using the rule hierarchy rather than by making assumptions about execution order of simultaneously-running rules.&lt;br /&gt;
&lt;br /&gt;
(Note: with the introduction of [[Asynchronous Route Streaming]], this is even more true than previously. What may have been a near-instantaneous operation in older builds may now require a wait of several seconds while the necessary data is streamed in.)&lt;br /&gt;
&lt;br /&gt;
It is important to note that some conditional rules may partially or completely rely on a polling behavior to evaluate their conditions. (An example of partial reliance is a rule which waits for an event, but then evaluates a condition to clarify whether the event should be acted upon.) In these cases, it is possible that the condition can rapidly become true and then become false again without the rule responding. This results in an uncertainty as to whether the conditional rule will correctly detect a given instance of the condition. This type of scenario should be avoided completely where possible, and should most definitely be limited to outcomes that do not significantly affect gameplay.&lt;br /&gt;
&lt;br /&gt;
For a hypothetical example, if the player&#039;s train speeds for 0.5sec, and a speeding check rule was implemented that polled every second, then the overspeed event may or may not trigger on any given occurrence. A session creator should not use this outcome as a failure condition, since some players may be able to speed without penalty, whereas other players would be penalised on the first attempt. A sensible solution in this case might be to increment a counter while speeding is detected, and only take action if the counter reaches a certain threshold. If the only penalty was a warning to the player which had no actual gameplay impact, then it might be acceptable to forgo this check and simply accept that some players will receive a warning where others may not.&lt;br /&gt;
&lt;br /&gt;
==Child Rules==&lt;br /&gt;
As with all other rules, child rules (ie. those that have parent rules in the hierarchy) start out in the PAUSED state. They do not become unpaused until the parent is ready for the children to start operating. Exactly when this occurs depends on the specific parent rule, but the general flow is the same for all rules:&lt;br /&gt;
&lt;br /&gt;
1. Parent rule becomes unpaused and begins operation.&lt;br /&gt;
&lt;br /&gt;
2. Parent rule configures any necessary world state changes.&lt;br /&gt;
&lt;br /&gt;
3. Parent rule optionally waits for a specific condition to occur.&lt;br /&gt;
&lt;br /&gt;
4. Parent rule begins executing its children. This involves unpausing one or more of the children (as discussed below in &amp;quot;Parent Rule Styles&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
5. Parent waits for its children to complete (as discussed below in &amp;quot;Parent Rule Styles&amp;quot;) and then pauses the children.&lt;br /&gt;
&lt;br /&gt;
6. Parent flags itself as COMPLETE.&lt;br /&gt;
&lt;br /&gt;
This process allows program control flow to pass from a top-level rule, to its immediate children, to their immediate children, and so on. As the bottom-level children become complete, completion flows back to the higher level children until finally the top-level rules become COMPLETE.&lt;br /&gt;
&lt;br /&gt;
It is worth noting that there is nothing special about a top-level rule being flagged as COMPLETE. This does not indicate an end-of-session or any other fundamental gameplay mode change. Since the pausing of rules on completion is handled by the parent rule (see step 5 above), the top-level rules never become PAUSED on completion.&lt;br /&gt;
&lt;br /&gt;
==Parent Rule Styles==&lt;br /&gt;
There are a few common techniques with which parent rules interact with their children. Rules should always fit one of these descriptions. The vast majority of rules should follow either the &amp;quot;Does Not Support Children&amp;quot; style, or the &amp;quot;Ordered Execution of Children&amp;quot; style.&lt;br /&gt;
&lt;br /&gt;
=== Does Not Support Children ===&lt;br /&gt;
The rule is incapable of supporting children and will always ignore them.&lt;br /&gt;
&lt;br /&gt;
This is used for trivial rules which perform a set function and then become permanently COMPLETE. Such rules are not conditional and do not wait for any world state changes except those which they initiate internally.&lt;br /&gt;
The rule should be configured to validate and/or enforce that no child rules can be added.&lt;br /&gt;
&lt;br /&gt;
=== Simultaneous Execution of Children ===&lt;br /&gt;
When the rule is ready to begin executing children, it unpauses all children simultaneously. The rule then waits for all children to flag as WAS COMPLETE. Once this is detected, the rule pauses all children and flags itself as COMPLETE.&lt;br /&gt;
This is used for rules which have a specific need to simultaneously execute children, such as the &amp;quot;Simultaneous List&amp;quot; rule.&lt;br /&gt;
&lt;br /&gt;
The rule editor interface should be explicit that child rules will be executed simultaneously. Child rules should be tagged appropriately in the rule editor list to denote unordered execution.&lt;br /&gt;
&lt;br /&gt;
=== Ordered Execution of Children ===&lt;br /&gt;
When the rule is ready to begin executing children, it iterates through the children in top-to-bottom order. If the child is flagged as WAS COMPLETE, the child is paused and iteration continues. If the child is not flagged as WAS COMPLETE, the child is unpaused and iteration ends. Whenever a child state change is detected, this process is repeated from the start. Once iteration passes over all children without leaving any child unpaused, the rule flags itself as COMPLETE.&lt;br /&gt;
&lt;br /&gt;
This style is used for all rules which do not explicitly fall under one of the other styles described here. Almost all third-party rules will follow this style. Implementing one of the other styles without there being a fundamental requirement to do so is considered a programming error.&lt;br /&gt;
&lt;br /&gt;
Rules which follow this style should derive from ConditionalScenarioBehavior in order to avoid re-implementing the control flow logic, as it is exceedingly complex to implement correctly. Any rules which do not derive from ConditionalScenarioBehavior should be accompanied by a clear explanation of the reasons that ConditionalScenarioBehavior is an unsuitable base class for the intended behavior. Rules which do derive from ConditionalScenarioBehavior should avoid complex overrides of the default logic.&lt;br /&gt;
&lt;br /&gt;
Child rules should be tagged appropriately in the rule editor list to denote execution order.&lt;br /&gt;
&lt;br /&gt;
=== Controlled Selection of a Single Child ===&lt;br /&gt;
When the rule is ready to begin executing children, it selects a single child and unpauses it. All other children remain paused. Once the selected child becomes flagged as WAS COMPLETE, the child is paused and the rule flags itself as COMPLETE.&lt;br /&gt;
&lt;br /&gt;
This style is used where complex conditional selection of child rules is required. This can be used to implement an &amp;quot;if-else&amp;quot; logic flow, a &amp;quot;switch-case&amp;quot; logic flow, or the &amp;quot;Random List&amp;quot; rule. This style should not be used to implement a simple &amp;quot;if&amp;quot; logic flow, because that would unnecessarily restrict the rule to a single child where the &amp;quot;Ordered Execution of Children&amp;quot; style would provide the same functionality while allowing multiple children.&lt;br /&gt;
The rule editor interface should be very explicit about how the child rules will be selected. Child rules should be tagged appropriately in the rule editor list to avoid the user attempting to fit a child rule into the wrong role.&lt;br /&gt;
&lt;br /&gt;
=== Custom Execution with Multiple Children ===&lt;br /&gt;
This style is used for very specific custom-purpose rules, such as a passenger station stop handler. Such rules should give a clear and complete explanation of their operation and their interaction with any child rules in the rule editor interface.&lt;br /&gt;
&lt;br /&gt;
Individual child rules may be executed in an ad-hoc manner by the rule in response to changes in game state. Child rules may or may not be executed simultaneously and may or may not be executed repeatedly depending on the rule; any limitations or gotchas deriving from this should be carefully explained in the rule editor interface.&lt;br /&gt;
&lt;br /&gt;
Child rules should be tagged appropriately in the rule editor list to avoid the user attempting to fit a child rule into the wrong role.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Early Termination via Pause =&lt;br /&gt;
A rule must accept being paused by its parent at any time. This should cause the rule to cease any game state monitoring or other direct effects. The rule must pause all child rules immediately.&lt;br /&gt;
&lt;br /&gt;
In cases where the rule is maintaining some reversible effect on the game world, pausing the rule should end this effect. For example, a rule which displays a message to the user should typically hide the message upon becoming paused, and a rule which causes a rain storm in a specific area should return the weather to normal upon becoming paused. Rules which make a single permanent change to the game world and then immediately flag as COMPLETE should not attempt to reverse the change upon becoming paused. Examples of these rules include configuration of the global weather conditions, or a rule which increments the player&#039;s score or penalty counter.&lt;br /&gt;
&lt;br /&gt;
It is important to note that any pause is resumable, although the parent may not choose to take advantage of this. Pausing a rule followed by unpausing it should result in the rule continuing operation where it left off. The notes on Saving and Loading Driver Sessions (below) are worth considering when evaluating techniques for implementing pause.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Early Termination via Internal Logic =&lt;br /&gt;
In some cases, a rule may begin executing child rules but then make an internal decision to abort execution. This typically occurs in conditional rules where the condition may be re-evaluated as false after it has already been evaluated as true. Such behavior should be made explicit in the rule editor interface and should usually be made optional by providing a checkbox.&lt;br /&gt;
&lt;br /&gt;
There are in fact several possible behavioral variants affecting how condition-deflag is interpreted:&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules and no further evaluation is performed. The rule eventually flags itself as COMPLETE and does not later deflag this.&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules. If the condition becomes deflagged, the child rules are paused. If the condition becomes flagged again, the child rules are continued. Once the child rules have fully completed execution, the rule flags itself as COMPLETE and does not later deflag this.&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules. If the condition becomes deflagged, the child rules are paused. If the condition becomes flagged again, the children are reset and execution starts anew. The rule flags itself as COMPLETE if all children successfully complete, but it will deflag if the condition deflags.&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules. If the condition becomes deflagged, the child rules continue executing. If the condition becomes flagged again, the children are reset and execution starts anew. The rule will flag as COMPLETE if all children successfully complete, but it will deflag if the condition deflags.&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules. The child rules continue execution with no regard for whether the condition changes between flagged or deflagged in either direction. If the condition transitions from deflagged to flagged again after the children have completed, the children are reset and execution starts anew. The rule will flag as COMPLETE if all children successfully complete, but it will deflag itself if the condition deflags. &lt;br /&gt;
&lt;br /&gt;
The complexity here derives from the fact that it is not possible to use the same set of rules multiple times concurrently for different trigger conditions. For example, if a set of rules is used to give demerit points and provide user notifications, and those rules live under a single conditional check which determines whether a train is speeding, it may be difficult to define what should happen if two trains are detected as speeding at the same time, or if a train stops speeding while the notification process is still in progress. It is not always possible to achieve a perfect solution to tracking multiple objects using a single set of rules, but correct selection from the above behaviors can minimise the possibility of serious side-effects.&lt;br /&gt;
&lt;br /&gt;
It is important to note that these behaviors describe how the rule reacts to internal condition checks. The rule&#039;s reaction to being paused by its parent is discussed above under &amp;quot;Early Termination via Pause&amp;quot; and is not affected by the description here.&lt;br /&gt;
&lt;br /&gt;
In short, there are many ways of handling this, and the important thing is for your (parent) rule to clearly explain which approach it is going to use.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Rule Reset =&lt;br /&gt;
A rule may be &#039;&#039;reset&#039;&#039; by its parent. This causes both the COMPLETE and WAS COMPLETE states to be deflagged. Individual rules may also react to the reset by modifying their internal state to forget past or present actions. Parent rules must also cause their children to be reset in turn.&lt;br /&gt;
&lt;br /&gt;
This mechanism is used to permit rules to be used in a repeating scenario, such as responding to a condition which can occur multiple times, or in a repeating loop. At some point after a rule has become flagged as WAS COMPLETE, it will typically become paused and will not be unpaused again. If the rule is to be included in some repeating behavior, this would normally prevent the behavior from operating successfully after the first run through. To avoid this, the parent rule responsible for implementing the repeating behavior will &#039;&#039;reset&#039;&#039; all children when a repeat occurs. This effectively cleans the rules back to their initial state ready to perform their roles again.&lt;br /&gt;
&lt;br /&gt;
It is important to note that a reset should cause the rule to return to its configured settings. For example, if a timer value is configured and is decremented during rule operation, the timer must be reset back to its initial value during rule reset.&lt;br /&gt;
&lt;br /&gt;
It is important to note that there is no requirement to pause a rule prior to resetting it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Saving and Loading Driver Sessions =&lt;br /&gt;
For better or worse, the script VM does not persist across a save/load operation. This means that each rule must correctly save both its configuration state and its runtime state, and must correctly reload those such that the state after a save/load operation is indistinguishable from the original state. The following aspects of the script state must be considered:&lt;br /&gt;
&lt;br /&gt;
* Member variables in the Rule instance.&lt;br /&gt;
* Which threads are running on the Rule instance, and where they are up to in the code flow.&lt;br /&gt;
* Local variables on the stack of each running thread.&lt;br /&gt;
* Non-persistent changes made to the state of other script objects (such as active &#039;sniff&#039; statements).&lt;br /&gt;
* Script Messages which might be in flight at the time of save (these are not persisted, so the net effect is that they are simply deleted between the save and the load.)&lt;br /&gt;
&lt;br /&gt;
Since the game state continues normal operation after a Save, no code flow or other behavioral changes should result from the Save operation itself. Instead, the Save operation (and the design of the rule as a whole) is responsible for ensuring that sufficient data is persisted in the save file such that the Load operation is able to restore to the correct running state.&lt;br /&gt;
&lt;br /&gt;
The rule base class, ScenarioBehavior, is responsible for saving and loading the rule state flags (COMPLETE, PAUSED, WAS COMPLETE, etc.) A rule which was paused at Save time will still be paused after the Load. A rule which was complete at Save time will still be complete after the Load. During a Load operation, the rule should inherit the parent class&#039; SetProperties() method so that these flags are correctly configured, then honor the paused state during the rest of the loading process.&lt;br /&gt;
&lt;br /&gt;
It is rarely appropriate for an unpaused rule to simply restart execution from the beginning. Care must be taken to ensure that execution resumes from the point that it left off at the time of saving. This process can be simplified by keeping as much state as possible in the rule member variables at all times, and only keeping reconstructible temporary values on the stack. If the member variables are correctly stored and restored, this approach will allow the loading process to detect the runtime state of the rule and resume any necessary threads, which will in turn be able to jump forward to the correct area of the code based on the stored state.&lt;br /&gt;
&lt;br /&gt;
Finally, the COMPLETE, WAS COMPLETE, and PAUSED flags on child rules should be honored. This is typically sufficient information to determine the running state of child rules, so no further state will generally need to be maintained. More accurately, the child rules take care of their own state at all times, and the parent only needs to react to changes in the child state. Since no child state change occurs across a Save/Load operation, the parent does not need to become involved.&lt;br /&gt;
&lt;br /&gt;
For rules which derive ConditionalScenarioBehavior, the majority of load/save logic is handled automatically. The only state information that such a rule should typically preserve is the instance-specific configuration data. The condition-monitor thread will be automatically restarted as required, and there is generally no need to distinguish between a first-startup and any subsequent startup.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Spurious Events =&lt;br /&gt;
There are various events (typically script messages) that a rule may listen for in order to detect state changes. It is important to note that spurious events are often possible, and that an event handler should often be coupled with a condition check. As a specific example, the &amp;quot;ScenarioBehavior&amp;quot;, &amp;quot;Touch&amp;quot; message typically indicates that a child state has changed, but the message may in fact be sent at any time. This message should prompt the rule to evaluate whether any state changes are necessary, but the rule should not simply assume that a state change is necessary without performing an evaluation.&lt;br /&gt;
&lt;br /&gt;
Similarly, calls to a function such as Pause() may in some cases have no effect. For example, if a rule is already executing and its parent calls Pause(false), the rule should not pause, reset, or change state in any way at all. Similarly, if a rule is already paused and its parent calls Pause(true), the rule should not unpause, reset, fire any events, or otherwise change state in any way at all.&lt;br /&gt;
&lt;br /&gt;
The short version is: do not assume that every event and every method call is supposed to achieve something meaningful. Check first, and if the event is meaningless to you then do nothing at all.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Future Considerations =&lt;br /&gt;
Rules should base their functionality on the state flags such as the PAUSED state, rather than attempting to detect and vary their functionality based on the state of the game.&lt;br /&gt;
&lt;br /&gt;
For example, we currently (in development builds) expose the rules editor in Driver for debugging purposes. This, or some mechanism like it, is likely to be included in public builds in the future. Rules should not assume that it is impossible to be reconfigured during gameplay. This will of course introduce some side effects, such as when an unpaused rule is modified during execution. It is the rule&#039;s responsibility to ensure that these side effects do not lead to script exceptions or to leaked state. For example, if a single thread is supposed to be running, reconfiguring the rule should not cause a second thread to run simultaneously. If a rule sniffs a target vehicle, and the target vehicle is redefined, then the rule should unsniff the original vehicle rather than now sniffing two vehicles.&lt;br /&gt;
&lt;br /&gt;
Likewise, we may in future allow some form of partial state swap between Driver and Surveyor. Rules should not assume that it is impossible to change from any one game state or module to any other game state or module, just because it is not possible at the current time. APIs already exist to detect such state changes where necessary, and in most cases it&#039;s simply not necessary to care whether your rule is in Surveyor or Driver - you should act based on the PAUSED state instead. Rules should deal with the game state as they find it rather than assuming that certain states will not ever occur.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Gotchas =&lt;br /&gt;
There are a few potential gotchas in the script environment that are worth considering when writing any non-trivial rule.&lt;br /&gt;
&lt;br /&gt;
== Response Latency ==&lt;br /&gt;
Scripts tend to rely heavily on message passing and threading. In both cases, there is a delay between triggering a certain behavior (eg. posting an event, or calling a threaded function) and having the receiving code react. Other code may execute during this delay.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
// Calling this might be expected to start and then stop the thread; in reality it&lt;br /&gt;
// will likely simply start the thread and leave it running, because the message&lt;br /&gt;
// is sent prior to the wait() statement starting.&lt;br /&gt;
void DemonstrateBug1(void)&lt;br /&gt;
{&lt;br /&gt;
  Pause(false);&lt;br /&gt;
  Pause(true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// In this case, we use a Sleep() statement to &amp;quot;ensure&amp;quot; that the thread has&lt;br /&gt;
// finished starting. This isn&#039;t actually reliable, but it works as long as the&lt;br /&gt;
// system isn&#039;t under too much load. We follow this up with a rapid pause-&lt;br /&gt;
// unpause sequence. As above, this doesn&#039;t work - the message is sent,&lt;br /&gt;
// then the function immediately checks whether the thread is still running&lt;br /&gt;
// (which it is) and thus the thread isn&#039;t restarted. The function completes,&lt;br /&gt;
// and finally the thread receives the message and exits.&lt;br /&gt;
void DemonstrateBug2(void)&lt;br /&gt;
{&lt;br /&gt;
  Pause(false);&lt;br /&gt;
  Sleep(1.0);&lt;br /&gt;
  Pause(true);&lt;br /&gt;
  Pause(false);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Helper code for the above functions.&lt;br /&gt;
void Pause(bool bIsPaused)&lt;br /&gt;
{&lt;br /&gt;
  if (bIsPaused)&lt;br /&gt;
  {&lt;br /&gt;
    PostMessage(me, &amp;quot;ThisRule&amp;quot;, &amp;quot;Pause&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  else if (!m_bIsThreadRunning)&lt;br /&gt;
  {&lt;br /&gt;
    m_bIsThreadRunning = true;&lt;br /&gt;
    StartThread();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
thread void StartThread(void)&lt;br /&gt;
{&lt;br /&gt;
  while (true)&lt;br /&gt;
  {&lt;br /&gt;
    wait ()&lt;br /&gt;
    {&lt;br /&gt;
    on &amp;quot;ThisRule&amp;quot;, &amp;quot;Pause&amp;quot;:&lt;br /&gt;
      break;&lt;br /&gt;
     ...&lt;br /&gt;
  }&lt;br /&gt;
  m_bIsThreadRunning = false;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Multiple Messages in Flight ==&lt;br /&gt;
It&#039;s possible to post multiple identical messages. This can be useful, but if you&#039;re expecting only one then it can be a source of errors.&lt;br /&gt;
&lt;br /&gt;
In the following pseudocode, each call to SetProperties() will place an additional &amp;quot;Timer&amp;quot;, &amp;quot;Tick&amp;quot; message into the cycle, effectively increasing the rate at which the IdleFunction is called. This will seem to be working for a single call to SetProperties(), which may be all that is called during a trivial testcase. It will probably give reasonable results for a few calls to SetProperties(), although if the function is time-sensitive then the results might be different to expectations. After a larger number of calls to SetProperties(), the object&#039;s message queue may become full, causing it to lose messages at random (perhaps the tick messages, or perhaps other unrelated messages that are more problematic).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
void Init(void)&lt;br /&gt;
{&lt;br /&gt;
  inherited();&lt;br /&gt;
  &lt;br /&gt;
  AddHandler(me, &amp;quot;Timer&amp;quot;, &amp;quot;Tick&amp;quot;, &amp;quot;IdleFunction&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void EnterIdleState(void)&lt;br /&gt;
{&lt;br /&gt;
  IdleFunction();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void IdleFunction(void)&lt;br /&gt;
{&lt;br /&gt;
  PostMessage(me, &amp;quot;Timer&amp;quot;, &amp;quot;Tick&amp;quot;, 1.0);&lt;br /&gt;
  .. do something here ..&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void SetProperties(Soup soup)&lt;br /&gt;
{&lt;br /&gt;
  inherited(soup);&lt;br /&gt;
  &lt;br /&gt;
  EnterIdleState();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A similar problem can occur if you start new threads rather than post new messages.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Thread Guard Variables ==&lt;br /&gt;
It&#039;s common to prevent a singleton thread from being started twice by using a boolean guard variable. Care must be taken to ensure that the guard variable is set and cleared at the correct locations, or they may be ineffective.&lt;br /&gt;
&lt;br /&gt;
The following pseudocode demonstrates one such correct usage. The key points to note are:&lt;br /&gt;
* We set &#039;m_bIsThreadedFunctionRunning&#039; prior to calling the threaded function. Setting it within the threaded function is too late; multiple threads might have already been started before the first thread reaches that point.&lt;br /&gt;
* We don&#039;t confuse whether the thread is actually running with whether we want the thread to be running. Once we ask a thread to start, we can&#039;t stop it starting. If we change our minds and want to stop it again, we must inform it in a way that it will realise after it finishes starting. In the worst-case scenario, we might flipflop on this multiple times before the thread actually starts.&lt;br /&gt;
* Similarly, we don&#039;t rely on messages to control the thread. Enqueuing a separate start or stop message with each StartThread()/StopThread() call might be possible, and we could clear any unwanted prior messages from the object&#039;s queue, but if the thread hasn&#039;t finished starting then it won&#039;t receive the messages anyway.&lt;br /&gt;
* We do rely on messages to wake the thread if it&#039;s waiting on messages, but we don&#039;t use those messages to imply any state - we just have it recheck the current state boolean to get the very latest info.&lt;br /&gt;
* We clear &#039;m_bIsThreadedFunctionRunning&#039; once the decision to exit has become unconditional. At this point, even though the thread is technically still running, we&#039;ll have to start a new thread if we want the thread to continue running.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
bool m_bIsThreadedFunctionRunning = false;&lt;br /&gt;
bool m_bWantThreadedFunctionRunning = false;&lt;br /&gt;
&lt;br /&gt;
void StartThread(void)&lt;br /&gt;
{&lt;br /&gt;
  m_bWantThreadedFunctionRunning = true;&lt;br /&gt;
  &lt;br /&gt;
  if (m_bIsThreadedFunctionRunning)&lt;br /&gt;
    return;&lt;br /&gt;
  &lt;br /&gt;
  m_bIsThreadedFunctionRunning = true;&lt;br /&gt;
  ThreadedFunction();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void StopThread(void)&lt;br /&gt;
{&lt;br /&gt;
  if (!m_bWantThreadedFunctionRunning)&lt;br /&gt;
    return;&lt;br /&gt;
  &lt;br /&gt;
  m_bWantThreadedFunctionRunning = false;&lt;br /&gt;
  PostMessage(me, &amp;quot;Thread&amp;quot;, &amp;quot;Touch&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
thread void ThreadedFunction(void)&lt;br /&gt;
{&lt;br /&gt;
  while (m_bWantThreadedFunctionRunning)&lt;br /&gt;
  {&lt;br /&gt;
    wait()&lt;br /&gt;
    {&lt;br /&gt;
      on &amp;quot;Thread&amp;quot;, &amp;quot;Touch&amp;quot;:&lt;br /&gt;
        break;&lt;br /&gt;
      .. whatever else..&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  m_bIsThreadedFunctionRunning = false;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Not Waiting For Messages ==&lt;br /&gt;
As seen above, it&#039;s possible for a thread to fail to receive posted messages because it wasn&#039;t waiting for them at the time. A more commonly problematic example follows.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
thread void MyThread(void)&lt;br /&gt;
{&lt;br /&gt;
  wait ()&lt;br /&gt;
  {&lt;br /&gt;
    on &amp;quot;Some&amp;quot;, &amp;quot;Condition&amp;quot;:&lt;br /&gt;
      HandleSomeCondition();&lt;br /&gt;
      continue;&lt;br /&gt;
    on &amp;quot;Thread&amp;quot;, &amp;quot;Exit&amp;quot;:&lt;br /&gt;
      break;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void HandleSomeCondition(void)&lt;br /&gt;
{&lt;br /&gt;
  wait ()&lt;br /&gt;
  {&lt;br /&gt;
    on &amp;quot;Some&amp;quot;, &amp;quot;End-Condition&amp;quot;:&lt;br /&gt;
      break;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In this example, the thread is waiting on both &amp;quot;Some&amp;quot;, &amp;quot;Condition&amp;quot; and also &amp;quot;Thread&amp;quot;, &amp;quot;Exit&amp;quot;. Either one will be handled correctly assuming that the thread is already running at the time they are posted. Even if multiple are posted, the thread will simply queue them and run each in turn.&lt;br /&gt;
&lt;br /&gt;
The problem occurs when HandleSomeCondition() is triggered and the thread begins waiting on &amp;quot;Some&amp;quot;, &amp;quot;End-Condition&amp;quot;. In this scenario, the thread is no longer waiting on &amp;quot;Thread&amp;quot;, &amp;quot;Exit&amp;quot;, and any attempt to post that message will simply be ignored. To reiterate: the message dispatch is NOT postponed until the function returns; the message is dropped entirely.&lt;br /&gt;
&lt;br /&gt;
In many cases, the correct behaviour is to move HandleSomeCondition() to a new thread, although that may also carry gotchas that you will need to be careful of (eg. you&#039;ll probably want to terminate the second thread at the same time as the first one, and you may need to consider whether you want multiple of the second thread to run simultaneously or not).&lt;br /&gt;
&lt;br /&gt;
== Performing Actions After Being Told to Stop ==&lt;br /&gt;
In many cases, you may wish to perform cleanup actions when stopping your rule. If your rule is threaded, this can easily become problematic.&lt;br /&gt;
&lt;br /&gt;
Consider the following pseudocode example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
void Pause(bool bIsPaused)&lt;br /&gt;
{&lt;br /&gt;
  if (!bIsPaused &amp;amp;&amp;amp; !m_bIsThreadRunning)&lt;br /&gt;
  {&lt;br /&gt;
    m_bIsThreadRunning = true;&lt;br /&gt;
    MyThread();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
thread void MyThread(void)&lt;br /&gt;
{&lt;br /&gt;
  BeginRule();&lt;br /&gt;
  while (!IsPaused())&lt;br /&gt;
  {&lt;br /&gt;
    Sleep(0.5);&lt;br /&gt;
    UpdateRule();&lt;br /&gt;
  }&lt;br /&gt;
  EndRule();&lt;br /&gt;
  m_bIsThreadRunning = false;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There are three immediately obvious problems:&lt;br /&gt;
&lt;br /&gt;
1. That BeginRule() is called when the thread starts, even if the rule has already been paused again.&lt;br /&gt;
&lt;br /&gt;
2. That UpdateRule() will be called after each sleep, even if the rule was paused during the sleep.&lt;br /&gt;
&lt;br /&gt;
3. That EndRule() will be called after the rule has been paused.&lt;br /&gt;
&lt;br /&gt;
This is very problematic because it likely violates a core principles of the rules system: that rules will not undertake any meaningful behaviour when paused. All three functions may be called while the rule is paused, so unless the rule does nothing meaningful at all, this is a guaranteed violation.&lt;br /&gt;
&lt;br /&gt;
The best approach to resolving this may depend on exactly what these functions do, but one possible solution is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
void Pause(bool bIsPaused)&lt;br /&gt;
{&lt;br /&gt;
  if (bIsPaused)&lt;br /&gt;
  {&lt;br /&gt;
    if (m_bNeedsEndRule)&lt;br /&gt;
    {&lt;br /&gt;
      m_bNeedsEndRule = false;&lt;br /&gt;
      EndRule();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  else&lt;br /&gt;
  {&lt;br /&gt;
    if (!m_bNeedsEndRule)&lt;br /&gt;
    {&lt;br /&gt;
      BeginRule();&lt;br /&gt;
      m_bNeedsEndRule = true;&lt;br /&gt;
    }&lt;br /&gt;
    if (!m_bIsThreadRunning)&lt;br /&gt;
    {&lt;br /&gt;
      m_bIsThreadRunning = true;&lt;br /&gt;
      MyThread();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
thread void MyThread(void)&lt;br /&gt;
{&lt;br /&gt;
  while (!IsPaused())&lt;br /&gt;
  {&lt;br /&gt;
    UpdateRule();&lt;br /&gt;
    Sleep(0.5);&lt;br /&gt;
  }&lt;br /&gt;
  m_bIsThreadRunning = false;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=Session_Rule_Implementation&amp;diff=16828</id>
		<title>Session Rule Implementation</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=Session_Rule_Implementation&amp;diff=16828"/>
		<updated>2018-11-27T17:03:39Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: /* Performing Actions After Being Told to Stop */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page seeks to clearly define expected script behavior for [[KIND Scenariobehavior|Session Rule assets]]. This focuses specifically on correct behavior from the code perspective, rather than addressing how rules should be designed for best gameplay outcomes.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Legacy Behavior Note =&lt;br /&gt;
Please note that many existing rules do not behave correctly as defined here. This is considered a bug in the individual session rules. [[N3V Games]] has a policy of updating session rules to behave correctly even where that may lead to changes of function in existing [[session]] assets. Where reasonable to achieve, emulation of the existing (buggy) behavior may occur for existing rule instances in existing sessions, however any newly created rule instances will use the corrected behavior.&lt;br /&gt;
&lt;br /&gt;
These expectations were codified at the end of [[TS12]] development due to an increasing inability of session rules to work together resulting from the unpredictable nature of their responses to various common use-cases. The systems as a whole, including most of the core rules discussed in this document, have existed for far longer than this document. The document does not redefine any existing systems, but simply presents the only reasonable implementation approach possible if rules are to be expected to work properly in all use-cases. In some cases we also choose to mandate specific points of behavior relating to user expectations rather than technical necessities.&lt;br /&gt;
&lt;br /&gt;
Certain additional API mechanisms were introduced alongside the development of this document, to allow better communication with session authors regarding the differences in behavior between certain types of rule. The correct usage for these mechanisms is also included in this document.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= The Rule Hierarchy =&lt;br /&gt;
All rules within a given session form a simple tree structure.&lt;br /&gt;
&lt;br /&gt;
== Rule State Flags ==&lt;br /&gt;
Each rule in the tree may have certain associated state flagged, including a combination of the following:&lt;br /&gt;
&lt;br /&gt;
=== PAUSED ===&lt;br /&gt;
The rule is currently paused, meaning that it does not affect the game world in any way and does not respond to any changes in the game world. The parent rule must cause the rule to become unpaused for the rule to have any effect. It is not correct behavior for a rule to unpause itself.&lt;br /&gt;
&lt;br /&gt;
=== COMPLETE ===&lt;br /&gt;
This flag indicates that rule has fully completed its operation (including any child rule operations) and does not affect the game world in any way. This flag is set by the rule itself, not by an outside entity such as the parent. This state should not be changed while the rule is PAUSED.&lt;br /&gt;
&lt;br /&gt;
Being COMPLETE does not imply being PAUSED. In many scenarios, the parent rule may respond to a child becoming COMPLETE by causing it to also become PAUSED, however this is certainly not guaranteed in all cases, and is not guaranteed to be immediate in the cases where it does happen.&lt;br /&gt;
&lt;br /&gt;
The rule may optionally respond to specific changes in the game world by deflagging the COMPLETE status. For example, a rule which specifically implements a condition check may choose to become COMPLETE when that condition is met, but return to an incomplete state when the condition is no longer met (again, remembering that a change in either direction should only happen while the rule itself is not PAUSED).&lt;br /&gt;
&lt;br /&gt;
When a rule&#039;s COMPLETE state changes, a &amp;quot;ScenarioBehavior&amp;quot;, &amp;quot;Touch&amp;quot; message is sent &#039;&#039;&#039;(TBD: BY WHAT MECHANISM?)&#039;&#039;&#039; to its parent rule (if any), unless the parent is in the PAUSED state. This allows the parent to react to changes in its child rules&#039; states. It is important to note that the message indicates a possible change which the parent may be interested in, but it is the parent rule&#039;s responsibility to determine whether the state change is worth reacting to.&lt;br /&gt;
&lt;br /&gt;
=== WAS COMPLETE ===&lt;br /&gt;
This is typically set when a rule first becomes flagged as COMPLETE, and will stay set even if the rule later flags as incomplete. This can be used by a parent which only cares that the child rule has been flagged as COMPLETE at some point, rather than caring what its current completion status is.&lt;br /&gt;
&lt;br /&gt;
=== DOES COMPLETE ===&lt;br /&gt;
This indicates whether the rule can ever reach the COMPLETE state. Its value is constant for a given rule configuration, and does not change based on the runtime rule state or other game state. Rules which are flagged as DOES COMPLETE are expected to become complete after some discreet operations are completed. Rules which are not flagged are expected to run indefinitely unless PAUSED by an external agent (such as the parent rule).&lt;br /&gt;
&lt;br /&gt;
== Initial State ==&lt;br /&gt;
All rules are initially in the PAUSED state when in [[Surveyor]], and only become unpaused after gameplay begins in a [[Driver]] session. Since a PAUSED rule is not permitted to unpause itself, this is a stable state which will persist until the native code takes step to begin program flow.&lt;br /&gt;
&lt;br /&gt;
== Top Level Rules ==&lt;br /&gt;
All rules at the top level (ie. rules which are not a child of any other rule) simultaneously become unpaused after the session has loaded into Driver. Some of these rules may take initial setup steps and then become COMPLETE. Some of these rules may begin monitoring for specific game conditions before taking any further action. Some of these rules may begin taking action immediately. The rules are not sequenced against each other in any way, and it is the session author&#039;s responsibility to ensure that this does not cause any conflicts.&lt;br /&gt;
&lt;br /&gt;
== Scheduling ==&lt;br /&gt;
Since the script VM is a cooperatively-threaded environment, it is technically true that rule evaluation will occur in an ordered manner rather than truly simultaneously. However, no guarantees are made regarding the order in which the simultaneously-running rules will perform their checks or outcomes. Since rules may wait internally rather than fulfilling their entire purpose in an atomic operation, it is also not guaranteed that a first-running rule will fully complete before some other simultaneously-executing rule begins completion. In short, if order-of-execution is critical to the correct behavior of a session, then the order should be enforced by the session creator using the rule hierarchy rather than by making assumptions about execution order of simultaneously-running rules.&lt;br /&gt;
&lt;br /&gt;
(Note: with the introduction of [[Asynchronous Route Streaming]], this is even more true than previously. What may have been a near-instantaneous operation in older builds may now require a wait of several seconds while the necessary data is streamed in.)&lt;br /&gt;
&lt;br /&gt;
It is important to note that some conditional rules may partially or completely rely on a polling behavior to evaluate their conditions. (An example of partial reliance is a rule which waits for an event, but then evaluates a condition to clarify whether the event should be acted upon.) In these cases, it is possible that the condition can rapidly become true and then become false again without the rule responding. This results in an uncertainty as to whether the conditional rule will correctly detect a given instance of the condition. This type of scenario should be avoided completely where possible, and should most definitely be limited to outcomes that do not significantly affect gameplay.&lt;br /&gt;
&lt;br /&gt;
For a hypothetical example, if the player&#039;s train speeds for 0.5sec, and a speeding check rule was implemented that polled every second, then the overspeed event may or may not trigger on any given occurrence. A session creator should not use this outcome as a failure condition, since some players may be able to speed without penalty, whereas other players would be penalised on the first attempt. A sensible solution in this case might be to increment a counter while speeding is detected, and only take action if the counter reaches a certain threshold. If the only penalty was a warning to the player which had no actual gameplay impact, then it might be acceptable to forgo this check and simply accept that some players will receive a warning where others may not.&lt;br /&gt;
&lt;br /&gt;
==Child Rules==&lt;br /&gt;
As with all other rules, child rules (ie. those that have parent rules in the hierarchy) start out in the PAUSED state. They do not become unpaused until the parent is ready for the children to start operating. Exactly when this occurs depends on the specific parent rule, but the general flow is the same for all rules:&lt;br /&gt;
&lt;br /&gt;
1. Parent rule becomes unpaused and begins operation.&lt;br /&gt;
2. Parent rule configures any necessary world state changes.&lt;br /&gt;
3. Parent rule optionally waits for a specific condition to occur.&lt;br /&gt;
4. Parent rule begins executing its children. This involves unpausing one or more of the children (as discussed below in &amp;quot;Parent Rule Styles&amp;quot;).&lt;br /&gt;
5. Parent waits for its children to complete (as discussed below in &amp;quot;Parent Rule Styles&amp;quot;) and then pauses the children.&lt;br /&gt;
6. Parent flags itself as COMPLETE.&lt;br /&gt;
&lt;br /&gt;
This process allows program control flow to pass from a top-level rule, to its immediate children, to their immediate children, and so on. As the bottom-level children become complete, completion flows back to the higher level children until finally the top-level rules become COMPLETE.&lt;br /&gt;
&lt;br /&gt;
It is worth noting that there is nothing special about a top-level rule being flagged as COMPLETE. This does not indicate an end-of-session or any other fundamental gameplay mode change. Since the pausing of rules on completion is handled by the parent rule (see step 5 above), the top-level rules never become PAUSED on completion.&lt;br /&gt;
&lt;br /&gt;
==Parent Rule Styles==&lt;br /&gt;
There are a few common techniques with which parent rules interact with their children. Rules should always fit one of these descriptions. The vast majority of rules should follow either the &amp;quot;Does Not Support Children&amp;quot; style, or the &amp;quot;Ordered Execution of Children&amp;quot; style.&lt;br /&gt;
&lt;br /&gt;
=== Does Not Support Children ===&lt;br /&gt;
The rule is incapable of supporting children and will always ignore them.&lt;br /&gt;
&lt;br /&gt;
This is used for trivial rules which perform a set function and then become permanently COMPLETE. Such rules are not conditional and do not wait for any world state changes except those which they initiate internally.&lt;br /&gt;
The rule should be configured to validate and/or enforce that no child rules can be added.&lt;br /&gt;
&lt;br /&gt;
=== Simultaneous Execution of Children ===&lt;br /&gt;
When the rule is ready to begin executing children, it unpauses all children simultaneously. The rule then waits for all children to flag as WAS COMPLETE. Once this is detected, the rule pauses all children and flags itself as COMPLETE.&lt;br /&gt;
This is used for rules which have a specific need to simultaneously execute children, such as the &amp;quot;Simultaneous List&amp;quot; rule.&lt;br /&gt;
&lt;br /&gt;
The rule editor interface should be explicit that child rules will be executed simultaneously. Child rules should be tagged appropriately in the rule editor list to denote unordered execution.&lt;br /&gt;
&lt;br /&gt;
=== Ordered Execution of Children ===&lt;br /&gt;
When the rule is ready to begin executing children, it iterates through the children in top-to-bottom order. If the child is flagged as WAS COMPLETE, the child is paused and iteration continues. If the child is not flagged as WAS COMPLETE, the child is unpaused and iteration ends. Whenever a child state change is detected, this process is repeated from the start. Once iteration passes over all children without leaving any child unpaused, the rule flags itself as COMPLETE.&lt;br /&gt;
&lt;br /&gt;
This style is used for all rules which do not explicitly fall under one of the other styles described here. Almost all third-party rules will follow this style. Implementing one of the other styles without there being a fundamental requirement to do so is considered a programming error.&lt;br /&gt;
&lt;br /&gt;
Rules which follow this style should derive from ConditionalScenarioBehavior in order to avoid re-implementing the control flow logic, as it is exceedingly complex to implement correctly. Any rules which do not derive from ConditionalScenarioBehavior should be accompanied by a clear explanation of the reasons that ConditionalScenarioBehavior is an unsuitable base class for the intended behavior. Rules which do derive from ConditionalScenarioBehavior should avoid complex overrides of the default logic.&lt;br /&gt;
&lt;br /&gt;
Child rules should be tagged appropriately in the rule editor list to denote execution order.&lt;br /&gt;
&lt;br /&gt;
=== Controlled Selection of a Single Child ===&lt;br /&gt;
When the rule is ready to begin executing children, it selects a single child and unpauses it. All other children remain paused. Once the selected child becomes flagged as WAS COMPLETE, the child is paused and the rule flags itself as COMPLETE.&lt;br /&gt;
&lt;br /&gt;
This style is used where complex conditional selection of child rules is required. This can be used to implement an &amp;quot;if-else&amp;quot; logic flow, a &amp;quot;switch-case&amp;quot; logic flow, or the &amp;quot;Random List&amp;quot; rule. This style should not be used to implement a simple &amp;quot;if&amp;quot; logic flow, because that would unnecessarily restrict the rule to a single child where the &amp;quot;Ordered Execution of Children&amp;quot; style would provide the same functionality while allowing multiple children.&lt;br /&gt;
The rule editor interface should be very explicit about how the child rules will be selected. Child rules should be tagged appropriately in the rule editor list to avoid the user attempting to fit a child rule into the wrong role.&lt;br /&gt;
&lt;br /&gt;
=== Custom Execution with Multiple Children ===&lt;br /&gt;
This style is used for very specific custom-purpose rules, such as a passenger station stop handler. Such rules should give a clear and complete explanation of their operation and their interaction with any child rules in the rule editor interface.&lt;br /&gt;
&lt;br /&gt;
Individual child rules may be executed in an ad-hoc manner by the rule in response to changes in game state. Child rules may or may not be executed simultaneously and may or may not be executed repeatedly depending on the rule; any limitations or gotchas deriving from this should be carefully explained in the rule editor interface.&lt;br /&gt;
&lt;br /&gt;
Child rules should be tagged appropriately in the rule editor list to avoid the user attempting to fit a child rule into the wrong role.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Early Termination via Pause =&lt;br /&gt;
A rule must accept being paused by its parent at any time. This should cause the rule to cease any game state monitoring or other direct effects. The rule must pause all child rules immediately.&lt;br /&gt;
&lt;br /&gt;
In cases where the rule is maintaining some reversible effect on the game world, pausing the rule should end this effect. For example, a rule which displays a message to the user should typically hide the message upon becoming paused, and a rule which causes a rain storm in a specific area should return the weather to normal upon becoming paused. Rules which make a single permanent change to the game world and then immediately flag as COMPLETE should not attempt to reverse the change upon becoming paused. Examples of these rules include configuration of the global weather conditions, or a rule which increments the player&#039;s score or penalty counter.&lt;br /&gt;
&lt;br /&gt;
It is important to note that any pause is resumable, although the parent may not choose to take advantage of this. Pausing a rule followed by unpausing it should result in the rule continuing operation where it left off. The notes on Saving and Loading Driver Sessions (below) are worth considering when evaluating techniques for implementing pause.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Early Termination via Internal Logic =&lt;br /&gt;
In some cases, a rule may begin executing child rules but then make an internal decision to abort execution. This typically occurs in conditional rules where the condition may be re-evaluated as false after it has already been evaluated as true. Such behavior should be made explicit in the rule editor interface and should usually be made optional by providing a checkbox.&lt;br /&gt;
&lt;br /&gt;
There are in fact several possible behavioral variants affecting how condition-deflag is interpreted:&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules and no further evaluation is performed. The rule eventually flags itself as COMPLETE and does not later deflag this.&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules. If the condition becomes deflagged, the child rules are paused. If the condition becomes flagged again, the child rules are continued. Once the child rules have fully completed execution, the rule flags itself as COMPLETE and does not later deflag this.&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules. If the condition becomes deflagged, the child rules are paused. If the condition becomes flagged again, the children are reset and execution starts anew. The rule flags itself as COMPLETE if all children successfully complete, but it will deflag if the condition deflags.&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules. If the condition becomes deflagged, the child rules continue executing. If the condition becomes flagged again, the children are reset and execution starts anew. The rule will flag as COMPLETE if all children successfully complete, but it will deflag if the condition deflags.&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules. The child rules continue execution with no regard for whether the condition changes between flagged or deflagged in either direction. If the condition transitions from deflagged to flagged again after the children have completed, the children are reset and execution starts anew. The rule will flag as COMPLETE if all children successfully complete, but it will deflag itself if the condition deflags. &lt;br /&gt;
&lt;br /&gt;
The complexity here derives from the fact that it is not possible to use the same set of rules multiple times concurrently for different trigger conditions. For example, if a set of rules is used to give demerit points and provide user notifications, and those rules live under a single conditional check which determines whether a train is speeding, it may be difficult to define what should happen if two trains are detected as speeding at the same time, or if a train stops speeding while the notification process is still in progress. It is not always possible to achieve a perfect solution to tracking multiple objects using a single set of rules, but correct selection from the above behaviors can minimise the possibility of serious side-effects.&lt;br /&gt;
&lt;br /&gt;
It is important to note that these behaviors describe how the rule reacts to internal condition checks. The rule&#039;s reaction to being paused by its parent is discussed above under &amp;quot;Early Termination via Pause&amp;quot; and is not affected by the description here.&lt;br /&gt;
&lt;br /&gt;
In short, there are many ways of handling this, and the important thing is for your (parent) rule to clearly explain which approach it is going to use.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Rule Reset =&lt;br /&gt;
A rule may be &#039;&#039;reset&#039;&#039; by its parent. This causes both the COMPLETE and WAS COMPLETE states to be deflagged. Individual rules may also react to the reset by modifying their internal state to forget past or present actions. Parent rules must also cause their children to be reset in turn.&lt;br /&gt;
&lt;br /&gt;
This mechanism is used to permit rules to be used in a repeating scenario, such as responding to a condition which can occur multiple times, or in a repeating loop. At some point after a rule has become flagged as WAS COMPLETE, it will typically become paused and will not be unpaused again. If the rule is to be included in some repeating behavior, this would normally prevent the behavior from operating successfully after the first run through. To avoid this, the parent rule responsible for implementing the repeating behavior will &#039;&#039;reset&#039;&#039; all children when a repeat occurs. This effectively cleans the rules back to their initial state ready to perform their roles again.&lt;br /&gt;
&lt;br /&gt;
It is important to note that a reset should cause the rule to return to its configured settings. For example, if a timer value is configured and is decremented during rule operation, the timer must be reset back to its initial value during rule reset.&lt;br /&gt;
&lt;br /&gt;
It is important to note that there is no requirement to pause a rule prior to resetting it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Saving and Loading Driver Sessions =&lt;br /&gt;
For better or worse, the script VM does not persist across a save/load operation. This means that each rule must correctly save both its configuration state and its runtime state, and must correctly reload those such that the state after a save/load operation is indistinguishable from the original state. The following aspects of the script state must be considered:&lt;br /&gt;
&lt;br /&gt;
* Member variables in the Rule instance.&lt;br /&gt;
* Which threads are running on the Rule instance, and where they are up to in the code flow.&lt;br /&gt;
* Local variables on the stack of each running thread.&lt;br /&gt;
* Non-persistent changes made to the state of other script objects (such as active &#039;sniff&#039; statements).&lt;br /&gt;
* Script Messages which might be in flight at the time of save (these are not persisted, so the net effect is that they are simply deleted between the save and the load.)&lt;br /&gt;
&lt;br /&gt;
Since the game state continues normal operation after a Save, no code flow or other behavioral changes should result from the Save operation itself. Instead, the Save operation (and the design of the rule as a whole) is responsible for ensuring that sufficient data is persisted in the save file such that the Load operation is able to restore to the correct running state.&lt;br /&gt;
&lt;br /&gt;
The rule base class, ScenarioBehavior, is responsible for saving and loading the rule state flags (COMPLETE, PAUSED, WAS COMPLETE, etc.) A rule which was paused at Save time will still be paused after the Load. A rule which was complete at Save time will still be complete after the Load. During a Load operation, the rule should inherit the parent class&#039; SetProperties() method so that these flags are correctly configured, then honor the paused state during the rest of the loading process.&lt;br /&gt;
&lt;br /&gt;
It is rarely appropriate for an unpaused rule to simply restart execution from the beginning. Care must be taken to ensure that execution resumes from the point that it left off at the time of saving. This process can be simplified by keeping as much state as possible in the rule member variables at all times, and only keeping reconstructible temporary values on the stack. If the member variables are correctly stored and restored, this approach will allow the loading process to detect the runtime state of the rule and resume any necessary threads, which will in turn be able to jump forward to the correct area of the code based on the stored state.&lt;br /&gt;
&lt;br /&gt;
Finally, the COMPLETE, WAS COMPLETE, and PAUSED flags on child rules should be honored. This is typically sufficient information to determine the running state of child rules, so no further state will generally need to be maintained. More accurately, the child rules take care of their own state at all times, and the parent only needs to react to changes in the child state. Since no child state change occurs across a Save/Load operation, the parent does not need to become involved.&lt;br /&gt;
&lt;br /&gt;
For rules which derive ConditionalScenarioBehavior, the majority of load/save logic is handled automatically. The only state information that such a rule should typically preserve is the instance-specific configuration data. The condition-monitor thread will be automatically restarted as required, and there is generally no need to distinguish between a first-startup and any subsequent startup.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Spurious Events =&lt;br /&gt;
There are various events (typically script messages) that a rule may listen for in order to detect state changes. It is important to note that spurious events are often possible, and that an event handler should often be coupled with a condition check. As a specific example, the &amp;quot;ScenarioBehavior&amp;quot;, &amp;quot;Touch&amp;quot; message typically indicates that a child state has changed, but the message may in fact be sent at any time. This message should prompt the rule to evaluate whether any state changes are necessary, but the rule should not simply assume that a state change is necessary without performing an evaluation.&lt;br /&gt;
&lt;br /&gt;
Similarly, calls to a function such as Pause() may in some cases have no effect. For example, if a rule is already executing and its parent calls Pause(false), the rule should not pause, reset, or change state in any way at all. Similarly, if a rule is already paused and its parent calls Pause(true), the rule should not unpause, reset, fire any events, or otherwise change state in any way at all.&lt;br /&gt;
&lt;br /&gt;
The short version is: do not assume that every event and every method call is supposed to achieve something meaningful. Check first, and if the event is meaningless to you then do nothing at all.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Future Considerations =&lt;br /&gt;
Rules should base their functionality on the state flags such as the PAUSED state, rather than attempting to detect and vary their functionality based on the state of the game.&lt;br /&gt;
&lt;br /&gt;
For example, we currently (in development builds) expose the rules editor in Driver for debugging purposes. This, or some mechanism like it, is likely to be included in public builds in the future. Rules should not assume that it is impossible to be reconfigured during gameplay. This will of course introduce some side effects, such as when an unpaused rule is modified during execution. It is the rule&#039;s responsibility to ensure that these side effects do not lead to script exceptions or to leaked state. For example, if a single thread is supposed to be running, reconfiguring the rule should not cause a second thread to run simultaneously. If a rule sniffs a target vehicle, and the target vehicle is redefined, then the rule should unsniff the original vehicle rather than now sniffing two vehicles.&lt;br /&gt;
&lt;br /&gt;
Likewise, we may in future allow some form of partial state swap between Driver and Surveyor. Rules should not assume that it is impossible to change from any one game state or module to any other game state or module, just because it is not possible at the current time. APIs already exist to detect such state changes where necessary, and in most cases it&#039;s simply not necessary to care whether your rule is in Surveyor or Driver - you should act based on the PAUSED state instead. Rules should deal with the game state as they find it rather than assuming that certain states will not ever occur.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Gotchas =&lt;br /&gt;
There are a few potential gotchas in the script environment that are worth considering when writing any non-trivial rule.&lt;br /&gt;
&lt;br /&gt;
== Response Latency ==&lt;br /&gt;
Scripts tend to rely heavily on message passing and threading. In both cases, there is a delay between triggering a certain behavior (eg. posting an event, or calling a threaded function) and having the receiving code react. Other code may execute during this delay.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
// Calling this might be expected to start and then stop the thread; in reality it&lt;br /&gt;
// will likely simply start the thread and leave it running, because the message&lt;br /&gt;
// is sent prior to the wait() statement starting.&lt;br /&gt;
void DemonstrateBug1(void)&lt;br /&gt;
{&lt;br /&gt;
  Pause(false);&lt;br /&gt;
  Pause(true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// In this case, we use a Sleep() statement to &amp;quot;ensure&amp;quot; that the thread has&lt;br /&gt;
// finished starting. This isn&#039;t actually reliable, but it works as long as the&lt;br /&gt;
// system isn&#039;t under too much load. We follow this up with a rapid pause-&lt;br /&gt;
// unpause sequence. As above, this doesn&#039;t work - the message is sent,&lt;br /&gt;
// then the function immediately checks whether the thread is still running&lt;br /&gt;
// (which it is) and thus the thread isn&#039;t restarted. The function completes,&lt;br /&gt;
// and finally the thread receives the message and exits.&lt;br /&gt;
void DemonstrateBug2(void)&lt;br /&gt;
{&lt;br /&gt;
  Pause(false);&lt;br /&gt;
  Sleep(1.0);&lt;br /&gt;
  Pause(true);&lt;br /&gt;
  Pause(false);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Helper code for the above functions.&lt;br /&gt;
void Pause(bool bIsPaused)&lt;br /&gt;
{&lt;br /&gt;
  if (bIsPaused)&lt;br /&gt;
  {&lt;br /&gt;
    PostMessage(me, &amp;quot;ThisRule&amp;quot;, &amp;quot;Pause&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  else if (!m_bIsThreadRunning)&lt;br /&gt;
  {&lt;br /&gt;
    m_bIsThreadRunning = true;&lt;br /&gt;
    StartThread();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
thread void StartThread(void)&lt;br /&gt;
{&lt;br /&gt;
  while (true)&lt;br /&gt;
  {&lt;br /&gt;
    wait ()&lt;br /&gt;
    {&lt;br /&gt;
    on &amp;quot;ThisRule&amp;quot;, &amp;quot;Pause&amp;quot;:&lt;br /&gt;
      break;&lt;br /&gt;
     ...&lt;br /&gt;
  }&lt;br /&gt;
  m_bIsThreadRunning = false;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Multiple Messages in Flight ==&lt;br /&gt;
It&#039;s possible to post multiple identical messages. This can be useful, but if you&#039;re expecting only one then it can be a source of errors.&lt;br /&gt;
&lt;br /&gt;
In the following pseudocode, each call to SetProperties() will place an additional &amp;quot;Timer&amp;quot;, &amp;quot;Tick&amp;quot; message into the cycle, effectively increasing the rate at which the IdleFunction is called. This will seem to be working for a single call to SetProperties(), which may be all that is called during a trivial testcase. It will probably give reasonable results for a few calls to SetProperties(), although if the function is time-sensitive then the results might be different to expectations. After a larger number of calls to SetProperties(), the object&#039;s message queue may become full, causing it to lose messages at random (perhaps the tick messages, or perhaps other unrelated messages that are more problematic).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
void Init(void)&lt;br /&gt;
{&lt;br /&gt;
  inherited();&lt;br /&gt;
  &lt;br /&gt;
  AddHandler(me, &amp;quot;Timer&amp;quot;, &amp;quot;Tick&amp;quot;, &amp;quot;IdleFunction&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void EnterIdleState(void)&lt;br /&gt;
{&lt;br /&gt;
  IdleFunction();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void IdleFunction(void)&lt;br /&gt;
{&lt;br /&gt;
  PostMessage(me, &amp;quot;Timer&amp;quot;, &amp;quot;Tick&amp;quot;, 1.0);&lt;br /&gt;
  .. do something here ..&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void SetProperties(Soup soup)&lt;br /&gt;
{&lt;br /&gt;
  inherited(soup);&lt;br /&gt;
  &lt;br /&gt;
  EnterIdleState();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A similar problem can occur if you start new threads rather than post new messages.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Thread Guard Variables ==&lt;br /&gt;
It&#039;s common to prevent a singleton thread from being started twice by using a boolean guard variable. Care must be taken to ensure that the guard variable is set and cleared at the correct locations, or they may be ineffective.&lt;br /&gt;
&lt;br /&gt;
The following pseudocode demonstrates one such correct usage. The key points to note are:&lt;br /&gt;
* We set &#039;m_bIsThreadedFunctionRunning&#039; prior to calling the threaded function. Setting it within the threaded function is too late; multiple threads might have already been started before the first thread reaches that point.&lt;br /&gt;
* We don&#039;t confuse whether the thread is actually running with whether we want the thread to be running. Once we ask a thread to start, we can&#039;t stop it starting. If we change our minds and want to stop it again, we must inform it in a way that it will realise after it finishes starting. In the worst-case scenario, we might flipflop on this multiple times before the thread actually starts.&lt;br /&gt;
* Similarly, we don&#039;t rely on messages to control the thread. Enqueuing a separate start or stop message with each StartThread()/StopThread() call might be possible, and we could clear any unwanted prior messages from the object&#039;s queue, but if the thread hasn&#039;t finished starting then it won&#039;t receive the messages anyway.&lt;br /&gt;
* We do rely on messages to wake the thread if it&#039;s waiting on messages, but we don&#039;t use those messages to imply any state - we just have it recheck the current state boolean to get the very latest info.&lt;br /&gt;
* We clear &#039;m_bIsThreadedFunctionRunning&#039; once the decision to exit has become unconditional. At this point, even though the thread is technically still running, we&#039;ll have to start a new thread if we want the thread to continue running.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
bool m_bIsThreadedFunctionRunning = false;&lt;br /&gt;
bool m_bWantThreadedFunctionRunning = false;&lt;br /&gt;
&lt;br /&gt;
void StartThread(void)&lt;br /&gt;
{&lt;br /&gt;
  m_bWantThreadedFunctionRunning = true;&lt;br /&gt;
  &lt;br /&gt;
  if (m_bIsThreadedFunctionRunning)&lt;br /&gt;
    return;&lt;br /&gt;
  &lt;br /&gt;
  m_bIsThreadedFunctionRunning = true;&lt;br /&gt;
  ThreadedFunction();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void StopThread(void)&lt;br /&gt;
{&lt;br /&gt;
  if (!m_bWantThreadedFunctionRunning)&lt;br /&gt;
    return;&lt;br /&gt;
  &lt;br /&gt;
  m_bWantThreadedFunctionRunning = false;&lt;br /&gt;
  PostMessage(me, &amp;quot;Thread&amp;quot;, &amp;quot;Touch&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
thread void ThreadedFunction(void)&lt;br /&gt;
{&lt;br /&gt;
  while (m_bWantThreadedFunctionRunning)&lt;br /&gt;
  {&lt;br /&gt;
    wait()&lt;br /&gt;
    {&lt;br /&gt;
      on &amp;quot;Thread&amp;quot;, &amp;quot;Touch&amp;quot;:&lt;br /&gt;
        break;&lt;br /&gt;
      .. whatever else..&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  m_bIsThreadedFunctionRunning = false;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Not Waiting For Messages ==&lt;br /&gt;
As seen above, it&#039;s possible for a thread to fail to receive posted messages because it wasn&#039;t waiting for them at the time. A more commonly problematic example follows.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
thread void MyThread(void)&lt;br /&gt;
{&lt;br /&gt;
  wait ()&lt;br /&gt;
  {&lt;br /&gt;
    on &amp;quot;Some&amp;quot;, &amp;quot;Condition&amp;quot;:&lt;br /&gt;
      HandleSomeCondition();&lt;br /&gt;
      continue;&lt;br /&gt;
    on &amp;quot;Thread&amp;quot;, &amp;quot;Exit&amp;quot;:&lt;br /&gt;
      break;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void HandleSomeCondition(void)&lt;br /&gt;
{&lt;br /&gt;
  wait ()&lt;br /&gt;
  {&lt;br /&gt;
    on &amp;quot;Some&amp;quot;, &amp;quot;End-Condition&amp;quot;:&lt;br /&gt;
      break;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In this example, the thread is waiting on both &amp;quot;Some&amp;quot;, &amp;quot;Condition&amp;quot; and also &amp;quot;Thread&amp;quot;, &amp;quot;Exit&amp;quot;. Either one will be handled correctly assuming that the thread is already running at the time they are posted. Even if multiple are posted, the thread will simply queue them and run each in turn.&lt;br /&gt;
&lt;br /&gt;
The problem occurs when HandleSomeCondition() is triggered and the thread begins waiting on &amp;quot;Some&amp;quot;, &amp;quot;End-Condition&amp;quot;. In this scenario, the thread is no longer waiting on &amp;quot;Thread&amp;quot;, &amp;quot;Exit&amp;quot;, and any attempt to post that message will simply be ignored. To reiterate: the message dispatch is NOT postponed until the function returns; the message is dropped entirely.&lt;br /&gt;
&lt;br /&gt;
In many cases, the correct behaviour is to move HandleSomeCondition() to a new thread, although that may also carry gotchas that you will need to be careful of (eg. you&#039;ll probably want to terminate the second thread at the same time as the first one, and you may need to consider whether you want multiple of the second thread to run simultaneously or not).&lt;br /&gt;
&lt;br /&gt;
== Performing Actions After Being Told to Stop ==&lt;br /&gt;
In many cases, you may wish to perform cleanup actions when stopping your rule. If your rule is threaded, this can easily become problematic.&lt;br /&gt;
&lt;br /&gt;
Consider the following pseudocode example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
void Pause(bool bIsPaused)&lt;br /&gt;
{&lt;br /&gt;
  if (!bIsPaused &amp;amp;&amp;amp; !m_bIsThreadRunning)&lt;br /&gt;
  {&lt;br /&gt;
    m_bIsThreadRunning = true;&lt;br /&gt;
    MyThread();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
thread void MyThread(void)&lt;br /&gt;
{&lt;br /&gt;
  BeginRule();&lt;br /&gt;
  while (!IsPaused())&lt;br /&gt;
  {&lt;br /&gt;
    Sleep(0.5);&lt;br /&gt;
    UpdateRule();&lt;br /&gt;
  }&lt;br /&gt;
  EndRule();&lt;br /&gt;
  m_bIsThreadRunning = false;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There are three immediately obvious problems:&lt;br /&gt;
&lt;br /&gt;
1. That BeginRule() is called when the thread starts, even if the rule has already been paused again.&lt;br /&gt;
&lt;br /&gt;
2. That UpdateRule() will be called after each sleep, even if the rule was paused during the sleep.&lt;br /&gt;
&lt;br /&gt;
3. That EndRule() will be called after the rule has been paused.&lt;br /&gt;
&lt;br /&gt;
This is very problematic because it likely violates a core principles of the rules system: that rules will not undertake any meaningful behaviour when paused. All three functions may be called while the rule is paused, so unless the rule does nothing meaningful at all, this is a guaranteed violation.&lt;br /&gt;
&lt;br /&gt;
The best approach to resolving this may depend on exactly what these functions do, but one possible solution is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
void Pause(bool bIsPaused)&lt;br /&gt;
{&lt;br /&gt;
  if (bIsPaused)&lt;br /&gt;
  {&lt;br /&gt;
    if (m_bNeedsEndRule)&lt;br /&gt;
    {&lt;br /&gt;
      m_bNeedsEndRule = false;&lt;br /&gt;
      EndRule();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  else&lt;br /&gt;
  {&lt;br /&gt;
    if (!m_bNeedsEndRule)&lt;br /&gt;
    {&lt;br /&gt;
      BeginRule();&lt;br /&gt;
      m_bNeedsEndRule = true;&lt;br /&gt;
    }&lt;br /&gt;
    if (!m_bIsThreadRunning)&lt;br /&gt;
    {&lt;br /&gt;
      m_bIsThreadRunning = true;&lt;br /&gt;
      MyThread();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
thread void MyThread(void)&lt;br /&gt;
{&lt;br /&gt;
  while (!IsPaused())&lt;br /&gt;
  {&lt;br /&gt;
    UpdateRule();&lt;br /&gt;
    Sleep(0.5);&lt;br /&gt;
  }&lt;br /&gt;
  m_bIsThreadRunning = false;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=Session_Rule_Implementation&amp;diff=16827</id>
		<title>Session Rule Implementation</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=Session_Rule_Implementation&amp;diff=16827"/>
		<updated>2018-11-27T17:03:15Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: /* Performing Actions After Being Told to Stop */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page seeks to clearly define expected script behavior for [[KIND Scenariobehavior|Session Rule assets]]. This focuses specifically on correct behavior from the code perspective, rather than addressing how rules should be designed for best gameplay outcomes.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Legacy Behavior Note =&lt;br /&gt;
Please note that many existing rules do not behave correctly as defined here. This is considered a bug in the individual session rules. [[N3V Games]] has a policy of updating session rules to behave correctly even where that may lead to changes of function in existing [[session]] assets. Where reasonable to achieve, emulation of the existing (buggy) behavior may occur for existing rule instances in existing sessions, however any newly created rule instances will use the corrected behavior.&lt;br /&gt;
&lt;br /&gt;
These expectations were codified at the end of [[TS12]] development due to an increasing inability of session rules to work together resulting from the unpredictable nature of their responses to various common use-cases. The systems as a whole, including most of the core rules discussed in this document, have existed for far longer than this document. The document does not redefine any existing systems, but simply presents the only reasonable implementation approach possible if rules are to be expected to work properly in all use-cases. In some cases we also choose to mandate specific points of behavior relating to user expectations rather than technical necessities.&lt;br /&gt;
&lt;br /&gt;
Certain additional API mechanisms were introduced alongside the development of this document, to allow better communication with session authors regarding the differences in behavior between certain types of rule. The correct usage for these mechanisms is also included in this document.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= The Rule Hierarchy =&lt;br /&gt;
All rules within a given session form a simple tree structure.&lt;br /&gt;
&lt;br /&gt;
== Rule State Flags ==&lt;br /&gt;
Each rule in the tree may have certain associated state flagged, including a combination of the following:&lt;br /&gt;
&lt;br /&gt;
=== PAUSED ===&lt;br /&gt;
The rule is currently paused, meaning that it does not affect the game world in any way and does not respond to any changes in the game world. The parent rule must cause the rule to become unpaused for the rule to have any effect. It is not correct behavior for a rule to unpause itself.&lt;br /&gt;
&lt;br /&gt;
=== COMPLETE ===&lt;br /&gt;
This flag indicates that rule has fully completed its operation (including any child rule operations) and does not affect the game world in any way. This flag is set by the rule itself, not by an outside entity such as the parent. This state should not be changed while the rule is PAUSED.&lt;br /&gt;
&lt;br /&gt;
Being COMPLETE does not imply being PAUSED. In many scenarios, the parent rule may respond to a child becoming COMPLETE by causing it to also become PAUSED, however this is certainly not guaranteed in all cases, and is not guaranteed to be immediate in the cases where it does happen.&lt;br /&gt;
&lt;br /&gt;
The rule may optionally respond to specific changes in the game world by deflagging the COMPLETE status. For example, a rule which specifically implements a condition check may choose to become COMPLETE when that condition is met, but return to an incomplete state when the condition is no longer met (again, remembering that a change in either direction should only happen while the rule itself is not PAUSED).&lt;br /&gt;
&lt;br /&gt;
When a rule&#039;s COMPLETE state changes, a &amp;quot;ScenarioBehavior&amp;quot;, &amp;quot;Touch&amp;quot; message is sent &#039;&#039;&#039;(TBD: BY WHAT MECHANISM?)&#039;&#039;&#039; to its parent rule (if any), unless the parent is in the PAUSED state. This allows the parent to react to changes in its child rules&#039; states. It is important to note that the message indicates a possible change which the parent may be interested in, but it is the parent rule&#039;s responsibility to determine whether the state change is worth reacting to.&lt;br /&gt;
&lt;br /&gt;
=== WAS COMPLETE ===&lt;br /&gt;
This is typically set when a rule first becomes flagged as COMPLETE, and will stay set even if the rule later flags as incomplete. This can be used by a parent which only cares that the child rule has been flagged as COMPLETE at some point, rather than caring what its current completion status is.&lt;br /&gt;
&lt;br /&gt;
=== DOES COMPLETE ===&lt;br /&gt;
This indicates whether the rule can ever reach the COMPLETE state. Its value is constant for a given rule configuration, and does not change based on the runtime rule state or other game state. Rules which are flagged as DOES COMPLETE are expected to become complete after some discreet operations are completed. Rules which are not flagged are expected to run indefinitely unless PAUSED by an external agent (such as the parent rule).&lt;br /&gt;
&lt;br /&gt;
== Initial State ==&lt;br /&gt;
All rules are initially in the PAUSED state when in [[Surveyor]], and only become unpaused after gameplay begins in a [[Driver]] session. Since a PAUSED rule is not permitted to unpause itself, this is a stable state which will persist until the native code takes step to begin program flow.&lt;br /&gt;
&lt;br /&gt;
== Top Level Rules ==&lt;br /&gt;
All rules at the top level (ie. rules which are not a child of any other rule) simultaneously become unpaused after the session has loaded into Driver. Some of these rules may take initial setup steps and then become COMPLETE. Some of these rules may begin monitoring for specific game conditions before taking any further action. Some of these rules may begin taking action immediately. The rules are not sequenced against each other in any way, and it is the session author&#039;s responsibility to ensure that this does not cause any conflicts.&lt;br /&gt;
&lt;br /&gt;
== Scheduling ==&lt;br /&gt;
Since the script VM is a cooperatively-threaded environment, it is technically true that rule evaluation will occur in an ordered manner rather than truly simultaneously. However, no guarantees are made regarding the order in which the simultaneously-running rules will perform their checks or outcomes. Since rules may wait internally rather than fulfilling their entire purpose in an atomic operation, it is also not guaranteed that a first-running rule will fully complete before some other simultaneously-executing rule begins completion. In short, if order-of-execution is critical to the correct behavior of a session, then the order should be enforced by the session creator using the rule hierarchy rather than by making assumptions about execution order of simultaneously-running rules.&lt;br /&gt;
&lt;br /&gt;
(Note: with the introduction of [[Asynchronous Route Streaming]], this is even more true than previously. What may have been a near-instantaneous operation in older builds may now require a wait of several seconds while the necessary data is streamed in.)&lt;br /&gt;
&lt;br /&gt;
It is important to note that some conditional rules may partially or completely rely on a polling behavior to evaluate their conditions. (An example of partial reliance is a rule which waits for an event, but then evaluates a condition to clarify whether the event should be acted upon.) In these cases, it is possible that the condition can rapidly become true and then become false again without the rule responding. This results in an uncertainty as to whether the conditional rule will correctly detect a given instance of the condition. This type of scenario should be avoided completely where possible, and should most definitely be limited to outcomes that do not significantly affect gameplay.&lt;br /&gt;
&lt;br /&gt;
For a hypothetical example, if the player&#039;s train speeds for 0.5sec, and a speeding check rule was implemented that polled every second, then the overspeed event may or may not trigger on any given occurrence. A session creator should not use this outcome as a failure condition, since some players may be able to speed without penalty, whereas other players would be penalised on the first attempt. A sensible solution in this case might be to increment a counter while speeding is detected, and only take action if the counter reaches a certain threshold. If the only penalty was a warning to the player which had no actual gameplay impact, then it might be acceptable to forgo this check and simply accept that some players will receive a warning where others may not.&lt;br /&gt;
&lt;br /&gt;
==Child Rules==&lt;br /&gt;
As with all other rules, child rules (ie. those that have parent rules in the hierarchy) start out in the PAUSED state. They do not become unpaused until the parent is ready for the children to start operating. Exactly when this occurs depends on the specific parent rule, but the general flow is the same for all rules:&lt;br /&gt;
&lt;br /&gt;
1. Parent rule becomes unpaused and begins operation.&lt;br /&gt;
2. Parent rule configures any necessary world state changes.&lt;br /&gt;
3. Parent rule optionally waits for a specific condition to occur.&lt;br /&gt;
4. Parent rule begins executing its children. This involves unpausing one or more of the children (as discussed below in &amp;quot;Parent Rule Styles&amp;quot;).&lt;br /&gt;
5. Parent waits for its children to complete (as discussed below in &amp;quot;Parent Rule Styles&amp;quot;) and then pauses the children.&lt;br /&gt;
6. Parent flags itself as COMPLETE.&lt;br /&gt;
&lt;br /&gt;
This process allows program control flow to pass from a top-level rule, to its immediate children, to their immediate children, and so on. As the bottom-level children become complete, completion flows back to the higher level children until finally the top-level rules become COMPLETE.&lt;br /&gt;
&lt;br /&gt;
It is worth noting that there is nothing special about a top-level rule being flagged as COMPLETE. This does not indicate an end-of-session or any other fundamental gameplay mode change. Since the pausing of rules on completion is handled by the parent rule (see step 5 above), the top-level rules never become PAUSED on completion.&lt;br /&gt;
&lt;br /&gt;
==Parent Rule Styles==&lt;br /&gt;
There are a few common techniques with which parent rules interact with their children. Rules should always fit one of these descriptions. The vast majority of rules should follow either the &amp;quot;Does Not Support Children&amp;quot; style, or the &amp;quot;Ordered Execution of Children&amp;quot; style.&lt;br /&gt;
&lt;br /&gt;
=== Does Not Support Children ===&lt;br /&gt;
The rule is incapable of supporting children and will always ignore them.&lt;br /&gt;
&lt;br /&gt;
This is used for trivial rules which perform a set function and then become permanently COMPLETE. Such rules are not conditional and do not wait for any world state changes except those which they initiate internally.&lt;br /&gt;
The rule should be configured to validate and/or enforce that no child rules can be added.&lt;br /&gt;
&lt;br /&gt;
=== Simultaneous Execution of Children ===&lt;br /&gt;
When the rule is ready to begin executing children, it unpauses all children simultaneously. The rule then waits for all children to flag as WAS COMPLETE. Once this is detected, the rule pauses all children and flags itself as COMPLETE.&lt;br /&gt;
This is used for rules which have a specific need to simultaneously execute children, such as the &amp;quot;Simultaneous List&amp;quot; rule.&lt;br /&gt;
&lt;br /&gt;
The rule editor interface should be explicit that child rules will be executed simultaneously. Child rules should be tagged appropriately in the rule editor list to denote unordered execution.&lt;br /&gt;
&lt;br /&gt;
=== Ordered Execution of Children ===&lt;br /&gt;
When the rule is ready to begin executing children, it iterates through the children in top-to-bottom order. If the child is flagged as WAS COMPLETE, the child is paused and iteration continues. If the child is not flagged as WAS COMPLETE, the child is unpaused and iteration ends. Whenever a child state change is detected, this process is repeated from the start. Once iteration passes over all children without leaving any child unpaused, the rule flags itself as COMPLETE.&lt;br /&gt;
&lt;br /&gt;
This style is used for all rules which do not explicitly fall under one of the other styles described here. Almost all third-party rules will follow this style. Implementing one of the other styles without there being a fundamental requirement to do so is considered a programming error.&lt;br /&gt;
&lt;br /&gt;
Rules which follow this style should derive from ConditionalScenarioBehavior in order to avoid re-implementing the control flow logic, as it is exceedingly complex to implement correctly. Any rules which do not derive from ConditionalScenarioBehavior should be accompanied by a clear explanation of the reasons that ConditionalScenarioBehavior is an unsuitable base class for the intended behavior. Rules which do derive from ConditionalScenarioBehavior should avoid complex overrides of the default logic.&lt;br /&gt;
&lt;br /&gt;
Child rules should be tagged appropriately in the rule editor list to denote execution order.&lt;br /&gt;
&lt;br /&gt;
=== Controlled Selection of a Single Child ===&lt;br /&gt;
When the rule is ready to begin executing children, it selects a single child and unpauses it. All other children remain paused. Once the selected child becomes flagged as WAS COMPLETE, the child is paused and the rule flags itself as COMPLETE.&lt;br /&gt;
&lt;br /&gt;
This style is used where complex conditional selection of child rules is required. This can be used to implement an &amp;quot;if-else&amp;quot; logic flow, a &amp;quot;switch-case&amp;quot; logic flow, or the &amp;quot;Random List&amp;quot; rule. This style should not be used to implement a simple &amp;quot;if&amp;quot; logic flow, because that would unnecessarily restrict the rule to a single child where the &amp;quot;Ordered Execution of Children&amp;quot; style would provide the same functionality while allowing multiple children.&lt;br /&gt;
The rule editor interface should be very explicit about how the child rules will be selected. Child rules should be tagged appropriately in the rule editor list to avoid the user attempting to fit a child rule into the wrong role.&lt;br /&gt;
&lt;br /&gt;
=== Custom Execution with Multiple Children ===&lt;br /&gt;
This style is used for very specific custom-purpose rules, such as a passenger station stop handler. Such rules should give a clear and complete explanation of their operation and their interaction with any child rules in the rule editor interface.&lt;br /&gt;
&lt;br /&gt;
Individual child rules may be executed in an ad-hoc manner by the rule in response to changes in game state. Child rules may or may not be executed simultaneously and may or may not be executed repeatedly depending on the rule; any limitations or gotchas deriving from this should be carefully explained in the rule editor interface.&lt;br /&gt;
&lt;br /&gt;
Child rules should be tagged appropriately in the rule editor list to avoid the user attempting to fit a child rule into the wrong role.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Early Termination via Pause =&lt;br /&gt;
A rule must accept being paused by its parent at any time. This should cause the rule to cease any game state monitoring or other direct effects. The rule must pause all child rules immediately.&lt;br /&gt;
&lt;br /&gt;
In cases where the rule is maintaining some reversible effect on the game world, pausing the rule should end this effect. For example, a rule which displays a message to the user should typically hide the message upon becoming paused, and a rule which causes a rain storm in a specific area should return the weather to normal upon becoming paused. Rules which make a single permanent change to the game world and then immediately flag as COMPLETE should not attempt to reverse the change upon becoming paused. Examples of these rules include configuration of the global weather conditions, or a rule which increments the player&#039;s score or penalty counter.&lt;br /&gt;
&lt;br /&gt;
It is important to note that any pause is resumable, although the parent may not choose to take advantage of this. Pausing a rule followed by unpausing it should result in the rule continuing operation where it left off. The notes on Saving and Loading Driver Sessions (below) are worth considering when evaluating techniques for implementing pause.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Early Termination via Internal Logic =&lt;br /&gt;
In some cases, a rule may begin executing child rules but then make an internal decision to abort execution. This typically occurs in conditional rules where the condition may be re-evaluated as false after it has already been evaluated as true. Such behavior should be made explicit in the rule editor interface and should usually be made optional by providing a checkbox.&lt;br /&gt;
&lt;br /&gt;
There are in fact several possible behavioral variants affecting how condition-deflag is interpreted:&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules and no further evaluation is performed. The rule eventually flags itself as COMPLETE and does not later deflag this.&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules. If the condition becomes deflagged, the child rules are paused. If the condition becomes flagged again, the child rules are continued. Once the child rules have fully completed execution, the rule flags itself as COMPLETE and does not later deflag this.&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules. If the condition becomes deflagged, the child rules are paused. If the condition becomes flagged again, the children are reset and execution starts anew. The rule flags itself as COMPLETE if all children successfully complete, but it will deflag if the condition deflags.&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules. If the condition becomes deflagged, the child rules continue executing. If the condition becomes flagged again, the children are reset and execution starts anew. The rule will flag as COMPLETE if all children successfully complete, but it will deflag if the condition deflags.&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules. The child rules continue execution with no regard for whether the condition changes between flagged or deflagged in either direction. If the condition transitions from deflagged to flagged again after the children have completed, the children are reset and execution starts anew. The rule will flag as COMPLETE if all children successfully complete, but it will deflag itself if the condition deflags. &lt;br /&gt;
&lt;br /&gt;
The complexity here derives from the fact that it is not possible to use the same set of rules multiple times concurrently for different trigger conditions. For example, if a set of rules is used to give demerit points and provide user notifications, and those rules live under a single conditional check which determines whether a train is speeding, it may be difficult to define what should happen if two trains are detected as speeding at the same time, or if a train stops speeding while the notification process is still in progress. It is not always possible to achieve a perfect solution to tracking multiple objects using a single set of rules, but correct selection from the above behaviors can minimise the possibility of serious side-effects.&lt;br /&gt;
&lt;br /&gt;
It is important to note that these behaviors describe how the rule reacts to internal condition checks. The rule&#039;s reaction to being paused by its parent is discussed above under &amp;quot;Early Termination via Pause&amp;quot; and is not affected by the description here.&lt;br /&gt;
&lt;br /&gt;
In short, there are many ways of handling this, and the important thing is for your (parent) rule to clearly explain which approach it is going to use.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Rule Reset =&lt;br /&gt;
A rule may be &#039;&#039;reset&#039;&#039; by its parent. This causes both the COMPLETE and WAS COMPLETE states to be deflagged. Individual rules may also react to the reset by modifying their internal state to forget past or present actions. Parent rules must also cause their children to be reset in turn.&lt;br /&gt;
&lt;br /&gt;
This mechanism is used to permit rules to be used in a repeating scenario, such as responding to a condition which can occur multiple times, or in a repeating loop. At some point after a rule has become flagged as WAS COMPLETE, it will typically become paused and will not be unpaused again. If the rule is to be included in some repeating behavior, this would normally prevent the behavior from operating successfully after the first run through. To avoid this, the parent rule responsible for implementing the repeating behavior will &#039;&#039;reset&#039;&#039; all children when a repeat occurs. This effectively cleans the rules back to their initial state ready to perform their roles again.&lt;br /&gt;
&lt;br /&gt;
It is important to note that a reset should cause the rule to return to its configured settings. For example, if a timer value is configured and is decremented during rule operation, the timer must be reset back to its initial value during rule reset.&lt;br /&gt;
&lt;br /&gt;
It is important to note that there is no requirement to pause a rule prior to resetting it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Saving and Loading Driver Sessions =&lt;br /&gt;
For better or worse, the script VM does not persist across a save/load operation. This means that each rule must correctly save both its configuration state and its runtime state, and must correctly reload those such that the state after a save/load operation is indistinguishable from the original state. The following aspects of the script state must be considered:&lt;br /&gt;
&lt;br /&gt;
* Member variables in the Rule instance.&lt;br /&gt;
* Which threads are running on the Rule instance, and where they are up to in the code flow.&lt;br /&gt;
* Local variables on the stack of each running thread.&lt;br /&gt;
* Non-persistent changes made to the state of other script objects (such as active &#039;sniff&#039; statements).&lt;br /&gt;
* Script Messages which might be in flight at the time of save (these are not persisted, so the net effect is that they are simply deleted between the save and the load.)&lt;br /&gt;
&lt;br /&gt;
Since the game state continues normal operation after a Save, no code flow or other behavioral changes should result from the Save operation itself. Instead, the Save operation (and the design of the rule as a whole) is responsible for ensuring that sufficient data is persisted in the save file such that the Load operation is able to restore to the correct running state.&lt;br /&gt;
&lt;br /&gt;
The rule base class, ScenarioBehavior, is responsible for saving and loading the rule state flags (COMPLETE, PAUSED, WAS COMPLETE, etc.) A rule which was paused at Save time will still be paused after the Load. A rule which was complete at Save time will still be complete after the Load. During a Load operation, the rule should inherit the parent class&#039; SetProperties() method so that these flags are correctly configured, then honor the paused state during the rest of the loading process.&lt;br /&gt;
&lt;br /&gt;
It is rarely appropriate for an unpaused rule to simply restart execution from the beginning. Care must be taken to ensure that execution resumes from the point that it left off at the time of saving. This process can be simplified by keeping as much state as possible in the rule member variables at all times, and only keeping reconstructible temporary values on the stack. If the member variables are correctly stored and restored, this approach will allow the loading process to detect the runtime state of the rule and resume any necessary threads, which will in turn be able to jump forward to the correct area of the code based on the stored state.&lt;br /&gt;
&lt;br /&gt;
Finally, the COMPLETE, WAS COMPLETE, and PAUSED flags on child rules should be honored. This is typically sufficient information to determine the running state of child rules, so no further state will generally need to be maintained. More accurately, the child rules take care of their own state at all times, and the parent only needs to react to changes in the child state. Since no child state change occurs across a Save/Load operation, the parent does not need to become involved.&lt;br /&gt;
&lt;br /&gt;
For rules which derive ConditionalScenarioBehavior, the majority of load/save logic is handled automatically. The only state information that such a rule should typically preserve is the instance-specific configuration data. The condition-monitor thread will be automatically restarted as required, and there is generally no need to distinguish between a first-startup and any subsequent startup.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Spurious Events =&lt;br /&gt;
There are various events (typically script messages) that a rule may listen for in order to detect state changes. It is important to note that spurious events are often possible, and that an event handler should often be coupled with a condition check. As a specific example, the &amp;quot;ScenarioBehavior&amp;quot;, &amp;quot;Touch&amp;quot; message typically indicates that a child state has changed, but the message may in fact be sent at any time. This message should prompt the rule to evaluate whether any state changes are necessary, but the rule should not simply assume that a state change is necessary without performing an evaluation.&lt;br /&gt;
&lt;br /&gt;
Similarly, calls to a function such as Pause() may in some cases have no effect. For example, if a rule is already executing and its parent calls Pause(false), the rule should not pause, reset, or change state in any way at all. Similarly, if a rule is already paused and its parent calls Pause(true), the rule should not unpause, reset, fire any events, or otherwise change state in any way at all.&lt;br /&gt;
&lt;br /&gt;
The short version is: do not assume that every event and every method call is supposed to achieve something meaningful. Check first, and if the event is meaningless to you then do nothing at all.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Future Considerations =&lt;br /&gt;
Rules should base their functionality on the state flags such as the PAUSED state, rather than attempting to detect and vary their functionality based on the state of the game.&lt;br /&gt;
&lt;br /&gt;
For example, we currently (in development builds) expose the rules editor in Driver for debugging purposes. This, or some mechanism like it, is likely to be included in public builds in the future. Rules should not assume that it is impossible to be reconfigured during gameplay. This will of course introduce some side effects, such as when an unpaused rule is modified during execution. It is the rule&#039;s responsibility to ensure that these side effects do not lead to script exceptions or to leaked state. For example, if a single thread is supposed to be running, reconfiguring the rule should not cause a second thread to run simultaneously. If a rule sniffs a target vehicle, and the target vehicle is redefined, then the rule should unsniff the original vehicle rather than now sniffing two vehicles.&lt;br /&gt;
&lt;br /&gt;
Likewise, we may in future allow some form of partial state swap between Driver and Surveyor. Rules should not assume that it is impossible to change from any one game state or module to any other game state or module, just because it is not possible at the current time. APIs already exist to detect such state changes where necessary, and in most cases it&#039;s simply not necessary to care whether your rule is in Surveyor or Driver - you should act based on the PAUSED state instead. Rules should deal with the game state as they find it rather than assuming that certain states will not ever occur.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Gotchas =&lt;br /&gt;
There are a few potential gotchas in the script environment that are worth considering when writing any non-trivial rule.&lt;br /&gt;
&lt;br /&gt;
== Response Latency ==&lt;br /&gt;
Scripts tend to rely heavily on message passing and threading. In both cases, there is a delay between triggering a certain behavior (eg. posting an event, or calling a threaded function) and having the receiving code react. Other code may execute during this delay.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
// Calling this might be expected to start and then stop the thread; in reality it&lt;br /&gt;
// will likely simply start the thread and leave it running, because the message&lt;br /&gt;
// is sent prior to the wait() statement starting.&lt;br /&gt;
void DemonstrateBug1(void)&lt;br /&gt;
{&lt;br /&gt;
  Pause(false);&lt;br /&gt;
  Pause(true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// In this case, we use a Sleep() statement to &amp;quot;ensure&amp;quot; that the thread has&lt;br /&gt;
// finished starting. This isn&#039;t actually reliable, but it works as long as the&lt;br /&gt;
// system isn&#039;t under too much load. We follow this up with a rapid pause-&lt;br /&gt;
// unpause sequence. As above, this doesn&#039;t work - the message is sent,&lt;br /&gt;
// then the function immediately checks whether the thread is still running&lt;br /&gt;
// (which it is) and thus the thread isn&#039;t restarted. The function completes,&lt;br /&gt;
// and finally the thread receives the message and exits.&lt;br /&gt;
void DemonstrateBug2(void)&lt;br /&gt;
{&lt;br /&gt;
  Pause(false);&lt;br /&gt;
  Sleep(1.0);&lt;br /&gt;
  Pause(true);&lt;br /&gt;
  Pause(false);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Helper code for the above functions.&lt;br /&gt;
void Pause(bool bIsPaused)&lt;br /&gt;
{&lt;br /&gt;
  if (bIsPaused)&lt;br /&gt;
  {&lt;br /&gt;
    PostMessage(me, &amp;quot;ThisRule&amp;quot;, &amp;quot;Pause&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  else if (!m_bIsThreadRunning)&lt;br /&gt;
  {&lt;br /&gt;
    m_bIsThreadRunning = true;&lt;br /&gt;
    StartThread();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
thread void StartThread(void)&lt;br /&gt;
{&lt;br /&gt;
  while (true)&lt;br /&gt;
  {&lt;br /&gt;
    wait ()&lt;br /&gt;
    {&lt;br /&gt;
    on &amp;quot;ThisRule&amp;quot;, &amp;quot;Pause&amp;quot;:&lt;br /&gt;
      break;&lt;br /&gt;
     ...&lt;br /&gt;
  }&lt;br /&gt;
  m_bIsThreadRunning = false;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Multiple Messages in Flight ==&lt;br /&gt;
It&#039;s possible to post multiple identical messages. This can be useful, but if you&#039;re expecting only one then it can be a source of errors.&lt;br /&gt;
&lt;br /&gt;
In the following pseudocode, each call to SetProperties() will place an additional &amp;quot;Timer&amp;quot;, &amp;quot;Tick&amp;quot; message into the cycle, effectively increasing the rate at which the IdleFunction is called. This will seem to be working for a single call to SetProperties(), which may be all that is called during a trivial testcase. It will probably give reasonable results for a few calls to SetProperties(), although if the function is time-sensitive then the results might be different to expectations. After a larger number of calls to SetProperties(), the object&#039;s message queue may become full, causing it to lose messages at random (perhaps the tick messages, or perhaps other unrelated messages that are more problematic).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
void Init(void)&lt;br /&gt;
{&lt;br /&gt;
  inherited();&lt;br /&gt;
  &lt;br /&gt;
  AddHandler(me, &amp;quot;Timer&amp;quot;, &amp;quot;Tick&amp;quot;, &amp;quot;IdleFunction&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void EnterIdleState(void)&lt;br /&gt;
{&lt;br /&gt;
  IdleFunction();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void IdleFunction(void)&lt;br /&gt;
{&lt;br /&gt;
  PostMessage(me, &amp;quot;Timer&amp;quot;, &amp;quot;Tick&amp;quot;, 1.0);&lt;br /&gt;
  .. do something here ..&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void SetProperties(Soup soup)&lt;br /&gt;
{&lt;br /&gt;
  inherited(soup);&lt;br /&gt;
  &lt;br /&gt;
  EnterIdleState();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A similar problem can occur if you start new threads rather than post new messages.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Thread Guard Variables ==&lt;br /&gt;
It&#039;s common to prevent a singleton thread from being started twice by using a boolean guard variable. Care must be taken to ensure that the guard variable is set and cleared at the correct locations, or they may be ineffective.&lt;br /&gt;
&lt;br /&gt;
The following pseudocode demonstrates one such correct usage. The key points to note are:&lt;br /&gt;
* We set &#039;m_bIsThreadedFunctionRunning&#039; prior to calling the threaded function. Setting it within the threaded function is too late; multiple threads might have already been started before the first thread reaches that point.&lt;br /&gt;
* We don&#039;t confuse whether the thread is actually running with whether we want the thread to be running. Once we ask a thread to start, we can&#039;t stop it starting. If we change our minds and want to stop it again, we must inform it in a way that it will realise after it finishes starting. In the worst-case scenario, we might flipflop on this multiple times before the thread actually starts.&lt;br /&gt;
* Similarly, we don&#039;t rely on messages to control the thread. Enqueuing a separate start or stop message with each StartThread()/StopThread() call might be possible, and we could clear any unwanted prior messages from the object&#039;s queue, but if the thread hasn&#039;t finished starting then it won&#039;t receive the messages anyway.&lt;br /&gt;
* We do rely on messages to wake the thread if it&#039;s waiting on messages, but we don&#039;t use those messages to imply any state - we just have it recheck the current state boolean to get the very latest info.&lt;br /&gt;
* We clear &#039;m_bIsThreadedFunctionRunning&#039; once the decision to exit has become unconditional. At this point, even though the thread is technically still running, we&#039;ll have to start a new thread if we want the thread to continue running.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
bool m_bIsThreadedFunctionRunning = false;&lt;br /&gt;
bool m_bWantThreadedFunctionRunning = false;&lt;br /&gt;
&lt;br /&gt;
void StartThread(void)&lt;br /&gt;
{&lt;br /&gt;
  m_bWantThreadedFunctionRunning = true;&lt;br /&gt;
  &lt;br /&gt;
  if (m_bIsThreadedFunctionRunning)&lt;br /&gt;
    return;&lt;br /&gt;
  &lt;br /&gt;
  m_bIsThreadedFunctionRunning = true;&lt;br /&gt;
  ThreadedFunction();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void StopThread(void)&lt;br /&gt;
{&lt;br /&gt;
  if (!m_bWantThreadedFunctionRunning)&lt;br /&gt;
    return;&lt;br /&gt;
  &lt;br /&gt;
  m_bWantThreadedFunctionRunning = false;&lt;br /&gt;
  PostMessage(me, &amp;quot;Thread&amp;quot;, &amp;quot;Touch&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
thread void ThreadedFunction(void)&lt;br /&gt;
{&lt;br /&gt;
  while (m_bWantThreadedFunctionRunning)&lt;br /&gt;
  {&lt;br /&gt;
    wait()&lt;br /&gt;
    {&lt;br /&gt;
      on &amp;quot;Thread&amp;quot;, &amp;quot;Touch&amp;quot;:&lt;br /&gt;
        break;&lt;br /&gt;
      .. whatever else..&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  m_bIsThreadedFunctionRunning = false;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Not Waiting For Messages ==&lt;br /&gt;
As seen above, it&#039;s possible for a thread to fail to receive posted messages because it wasn&#039;t waiting for them at the time. A more commonly problematic example follows.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
thread void MyThread(void)&lt;br /&gt;
{&lt;br /&gt;
  wait ()&lt;br /&gt;
  {&lt;br /&gt;
    on &amp;quot;Some&amp;quot;, &amp;quot;Condition&amp;quot;:&lt;br /&gt;
      HandleSomeCondition();&lt;br /&gt;
      continue;&lt;br /&gt;
    on &amp;quot;Thread&amp;quot;, &amp;quot;Exit&amp;quot;:&lt;br /&gt;
      break;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void HandleSomeCondition(void)&lt;br /&gt;
{&lt;br /&gt;
  wait ()&lt;br /&gt;
  {&lt;br /&gt;
    on &amp;quot;Some&amp;quot;, &amp;quot;End-Condition&amp;quot;:&lt;br /&gt;
      break;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In this example, the thread is waiting on both &amp;quot;Some&amp;quot;, &amp;quot;Condition&amp;quot; and also &amp;quot;Thread&amp;quot;, &amp;quot;Exit&amp;quot;. Either one will be handled correctly assuming that the thread is already running at the time they are posted. Even if multiple are posted, the thread will simply queue them and run each in turn.&lt;br /&gt;
&lt;br /&gt;
The problem occurs when HandleSomeCondition() is triggered and the thread begins waiting on &amp;quot;Some&amp;quot;, &amp;quot;End-Condition&amp;quot;. In this scenario, the thread is no longer waiting on &amp;quot;Thread&amp;quot;, &amp;quot;Exit&amp;quot;, and any attempt to post that message will simply be ignored. To reiterate: the message dispatch is NOT postponed until the function returns; the message is dropped entirely.&lt;br /&gt;
&lt;br /&gt;
In many cases, the correct behaviour is to move HandleSomeCondition() to a new thread, although that may also carry gotchas that you will need to be careful of (eg. you&#039;ll probably want to terminate the second thread at the same time as the first one, and you may need to consider whether you want multiple of the second thread to run simultaneously or not).&lt;br /&gt;
&lt;br /&gt;
== Performing Actions After Being Told to Stop ==&lt;br /&gt;
In many cases, you may wish to perform cleanup actions when stopping your rule. If your rule is threaded, this can easily become problematic.&lt;br /&gt;
&lt;br /&gt;
Consider the following pseudocode example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
void Pause(bool bIsPaused)&lt;br /&gt;
{&lt;br /&gt;
  if (!bIsPaused &amp;amp;&amp;amp; !m_bIsThreadRunning)&lt;br /&gt;
  {&lt;br /&gt;
    m_bIsThreadRunning = true;&lt;br /&gt;
    MyThread();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
thread void MyThread(void)&lt;br /&gt;
{&lt;br /&gt;
  BeginRule();&lt;br /&gt;
  while (!IsPaused())&lt;br /&gt;
  {&lt;br /&gt;
    Sleep(0.5);&lt;br /&gt;
    UpdateRule();&lt;br /&gt;
  }&lt;br /&gt;
  EndRule();&lt;br /&gt;
  m_bIsThreadRunning = false;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There are three immediately obvious problems:&lt;br /&gt;
&lt;br /&gt;
1. That BeginRule() is called when the thread starts, even if the rule has already been paused again.&lt;br /&gt;
2. That UpdateRule() will be called after each sleep, even if the rule was paused during the sleep.&lt;br /&gt;
3. That EndRule() will be called after the rule has been paused.&lt;br /&gt;
&lt;br /&gt;
This is very problematic because it likely violates a core principles of the rules system: that rules will not undertake any meaningful behaviour when paused. All three functions may be called while the rule is paused, so unless the rule does nothing meaningful at all, this is a guaranteed violation.&lt;br /&gt;
&lt;br /&gt;
The best approach to resolving this may depend on exactly what these functions do, but one possible solution is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
void Pause(bool bIsPaused)&lt;br /&gt;
{&lt;br /&gt;
  if (bIsPaused)&lt;br /&gt;
  {&lt;br /&gt;
    if (m_bNeedsEndRule)&lt;br /&gt;
    {&lt;br /&gt;
      m_bNeedsEndRule = false;&lt;br /&gt;
      EndRule();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  else&lt;br /&gt;
  {&lt;br /&gt;
    if (!m_bNeedsEndRule)&lt;br /&gt;
    {&lt;br /&gt;
      BeginRule();&lt;br /&gt;
      m_bNeedsEndRule = true;&lt;br /&gt;
    }&lt;br /&gt;
    if (!m_bIsThreadRunning)&lt;br /&gt;
    {&lt;br /&gt;
      m_bIsThreadRunning = true;&lt;br /&gt;
      MyThread();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
thread void MyThread(void)&lt;br /&gt;
{&lt;br /&gt;
  while (!IsPaused())&lt;br /&gt;
  {&lt;br /&gt;
    UpdateRule();&lt;br /&gt;
    Sleep(0.5);&lt;br /&gt;
  }&lt;br /&gt;
  m_bIsThreadRunning = false;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=Session_Rule_Implementation&amp;diff=16826</id>
		<title>Session Rule Implementation</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=Session_Rule_Implementation&amp;diff=16826"/>
		<updated>2018-11-27T17:02:39Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page seeks to clearly define expected script behavior for [[KIND Scenariobehavior|Session Rule assets]]. This focuses specifically on correct behavior from the code perspective, rather than addressing how rules should be designed for best gameplay outcomes.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Legacy Behavior Note =&lt;br /&gt;
Please note that many existing rules do not behave correctly as defined here. This is considered a bug in the individual session rules. [[N3V Games]] has a policy of updating session rules to behave correctly even where that may lead to changes of function in existing [[session]] assets. Where reasonable to achieve, emulation of the existing (buggy) behavior may occur for existing rule instances in existing sessions, however any newly created rule instances will use the corrected behavior.&lt;br /&gt;
&lt;br /&gt;
These expectations were codified at the end of [[TS12]] development due to an increasing inability of session rules to work together resulting from the unpredictable nature of their responses to various common use-cases. The systems as a whole, including most of the core rules discussed in this document, have existed for far longer than this document. The document does not redefine any existing systems, but simply presents the only reasonable implementation approach possible if rules are to be expected to work properly in all use-cases. In some cases we also choose to mandate specific points of behavior relating to user expectations rather than technical necessities.&lt;br /&gt;
&lt;br /&gt;
Certain additional API mechanisms were introduced alongside the development of this document, to allow better communication with session authors regarding the differences in behavior between certain types of rule. The correct usage for these mechanisms is also included in this document.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= The Rule Hierarchy =&lt;br /&gt;
All rules within a given session form a simple tree structure.&lt;br /&gt;
&lt;br /&gt;
== Rule State Flags ==&lt;br /&gt;
Each rule in the tree may have certain associated state flagged, including a combination of the following:&lt;br /&gt;
&lt;br /&gt;
=== PAUSED ===&lt;br /&gt;
The rule is currently paused, meaning that it does not affect the game world in any way and does not respond to any changes in the game world. The parent rule must cause the rule to become unpaused for the rule to have any effect. It is not correct behavior for a rule to unpause itself.&lt;br /&gt;
&lt;br /&gt;
=== COMPLETE ===&lt;br /&gt;
This flag indicates that rule has fully completed its operation (including any child rule operations) and does not affect the game world in any way. This flag is set by the rule itself, not by an outside entity such as the parent. This state should not be changed while the rule is PAUSED.&lt;br /&gt;
&lt;br /&gt;
Being COMPLETE does not imply being PAUSED. In many scenarios, the parent rule may respond to a child becoming COMPLETE by causing it to also become PAUSED, however this is certainly not guaranteed in all cases, and is not guaranteed to be immediate in the cases where it does happen.&lt;br /&gt;
&lt;br /&gt;
The rule may optionally respond to specific changes in the game world by deflagging the COMPLETE status. For example, a rule which specifically implements a condition check may choose to become COMPLETE when that condition is met, but return to an incomplete state when the condition is no longer met (again, remembering that a change in either direction should only happen while the rule itself is not PAUSED).&lt;br /&gt;
&lt;br /&gt;
When a rule&#039;s COMPLETE state changes, a &amp;quot;ScenarioBehavior&amp;quot;, &amp;quot;Touch&amp;quot; message is sent &#039;&#039;&#039;(TBD: BY WHAT MECHANISM?)&#039;&#039;&#039; to its parent rule (if any), unless the parent is in the PAUSED state. This allows the parent to react to changes in its child rules&#039; states. It is important to note that the message indicates a possible change which the parent may be interested in, but it is the parent rule&#039;s responsibility to determine whether the state change is worth reacting to.&lt;br /&gt;
&lt;br /&gt;
=== WAS COMPLETE ===&lt;br /&gt;
This is typically set when a rule first becomes flagged as COMPLETE, and will stay set even if the rule later flags as incomplete. This can be used by a parent which only cares that the child rule has been flagged as COMPLETE at some point, rather than caring what its current completion status is.&lt;br /&gt;
&lt;br /&gt;
=== DOES COMPLETE ===&lt;br /&gt;
This indicates whether the rule can ever reach the COMPLETE state. Its value is constant for a given rule configuration, and does not change based on the runtime rule state or other game state. Rules which are flagged as DOES COMPLETE are expected to become complete after some discreet operations are completed. Rules which are not flagged are expected to run indefinitely unless PAUSED by an external agent (such as the parent rule).&lt;br /&gt;
&lt;br /&gt;
== Initial State ==&lt;br /&gt;
All rules are initially in the PAUSED state when in [[Surveyor]], and only become unpaused after gameplay begins in a [[Driver]] session. Since a PAUSED rule is not permitted to unpause itself, this is a stable state which will persist until the native code takes step to begin program flow.&lt;br /&gt;
&lt;br /&gt;
== Top Level Rules ==&lt;br /&gt;
All rules at the top level (ie. rules which are not a child of any other rule) simultaneously become unpaused after the session has loaded into Driver. Some of these rules may take initial setup steps and then become COMPLETE. Some of these rules may begin monitoring for specific game conditions before taking any further action. Some of these rules may begin taking action immediately. The rules are not sequenced against each other in any way, and it is the session author&#039;s responsibility to ensure that this does not cause any conflicts.&lt;br /&gt;
&lt;br /&gt;
== Scheduling ==&lt;br /&gt;
Since the script VM is a cooperatively-threaded environment, it is technically true that rule evaluation will occur in an ordered manner rather than truly simultaneously. However, no guarantees are made regarding the order in which the simultaneously-running rules will perform their checks or outcomes. Since rules may wait internally rather than fulfilling their entire purpose in an atomic operation, it is also not guaranteed that a first-running rule will fully complete before some other simultaneously-executing rule begins completion. In short, if order-of-execution is critical to the correct behavior of a session, then the order should be enforced by the session creator using the rule hierarchy rather than by making assumptions about execution order of simultaneously-running rules.&lt;br /&gt;
&lt;br /&gt;
(Note: with the introduction of [[Asynchronous Route Streaming]], this is even more true than previously. What may have been a near-instantaneous operation in older builds may now require a wait of several seconds while the necessary data is streamed in.)&lt;br /&gt;
&lt;br /&gt;
It is important to note that some conditional rules may partially or completely rely on a polling behavior to evaluate their conditions. (An example of partial reliance is a rule which waits for an event, but then evaluates a condition to clarify whether the event should be acted upon.) In these cases, it is possible that the condition can rapidly become true and then become false again without the rule responding. This results in an uncertainty as to whether the conditional rule will correctly detect a given instance of the condition. This type of scenario should be avoided completely where possible, and should most definitely be limited to outcomes that do not significantly affect gameplay.&lt;br /&gt;
&lt;br /&gt;
For a hypothetical example, if the player&#039;s train speeds for 0.5sec, and a speeding check rule was implemented that polled every second, then the overspeed event may or may not trigger on any given occurrence. A session creator should not use this outcome as a failure condition, since some players may be able to speed without penalty, whereas other players would be penalised on the first attempt. A sensible solution in this case might be to increment a counter while speeding is detected, and only take action if the counter reaches a certain threshold. If the only penalty was a warning to the player which had no actual gameplay impact, then it might be acceptable to forgo this check and simply accept that some players will receive a warning where others may not.&lt;br /&gt;
&lt;br /&gt;
==Child Rules==&lt;br /&gt;
As with all other rules, child rules (ie. those that have parent rules in the hierarchy) start out in the PAUSED state. They do not become unpaused until the parent is ready for the children to start operating. Exactly when this occurs depends on the specific parent rule, but the general flow is the same for all rules:&lt;br /&gt;
&lt;br /&gt;
1. Parent rule becomes unpaused and begins operation.&lt;br /&gt;
2. Parent rule configures any necessary world state changes.&lt;br /&gt;
3. Parent rule optionally waits for a specific condition to occur.&lt;br /&gt;
4. Parent rule begins executing its children. This involves unpausing one or more of the children (as discussed below in &amp;quot;Parent Rule Styles&amp;quot;).&lt;br /&gt;
5. Parent waits for its children to complete (as discussed below in &amp;quot;Parent Rule Styles&amp;quot;) and then pauses the children.&lt;br /&gt;
6. Parent flags itself as COMPLETE.&lt;br /&gt;
&lt;br /&gt;
This process allows program control flow to pass from a top-level rule, to its immediate children, to their immediate children, and so on. As the bottom-level children become complete, completion flows back to the higher level children until finally the top-level rules become COMPLETE.&lt;br /&gt;
&lt;br /&gt;
It is worth noting that there is nothing special about a top-level rule being flagged as COMPLETE. This does not indicate an end-of-session or any other fundamental gameplay mode change. Since the pausing of rules on completion is handled by the parent rule (see step 5 above), the top-level rules never become PAUSED on completion.&lt;br /&gt;
&lt;br /&gt;
==Parent Rule Styles==&lt;br /&gt;
There are a few common techniques with which parent rules interact with their children. Rules should always fit one of these descriptions. The vast majority of rules should follow either the &amp;quot;Does Not Support Children&amp;quot; style, or the &amp;quot;Ordered Execution of Children&amp;quot; style.&lt;br /&gt;
&lt;br /&gt;
=== Does Not Support Children ===&lt;br /&gt;
The rule is incapable of supporting children and will always ignore them.&lt;br /&gt;
&lt;br /&gt;
This is used for trivial rules which perform a set function and then become permanently COMPLETE. Such rules are not conditional and do not wait for any world state changes except those which they initiate internally.&lt;br /&gt;
The rule should be configured to validate and/or enforce that no child rules can be added.&lt;br /&gt;
&lt;br /&gt;
=== Simultaneous Execution of Children ===&lt;br /&gt;
When the rule is ready to begin executing children, it unpauses all children simultaneously. The rule then waits for all children to flag as WAS COMPLETE. Once this is detected, the rule pauses all children and flags itself as COMPLETE.&lt;br /&gt;
This is used for rules which have a specific need to simultaneously execute children, such as the &amp;quot;Simultaneous List&amp;quot; rule.&lt;br /&gt;
&lt;br /&gt;
The rule editor interface should be explicit that child rules will be executed simultaneously. Child rules should be tagged appropriately in the rule editor list to denote unordered execution.&lt;br /&gt;
&lt;br /&gt;
=== Ordered Execution of Children ===&lt;br /&gt;
When the rule is ready to begin executing children, it iterates through the children in top-to-bottom order. If the child is flagged as WAS COMPLETE, the child is paused and iteration continues. If the child is not flagged as WAS COMPLETE, the child is unpaused and iteration ends. Whenever a child state change is detected, this process is repeated from the start. Once iteration passes over all children without leaving any child unpaused, the rule flags itself as COMPLETE.&lt;br /&gt;
&lt;br /&gt;
This style is used for all rules which do not explicitly fall under one of the other styles described here. Almost all third-party rules will follow this style. Implementing one of the other styles without there being a fundamental requirement to do so is considered a programming error.&lt;br /&gt;
&lt;br /&gt;
Rules which follow this style should derive from ConditionalScenarioBehavior in order to avoid re-implementing the control flow logic, as it is exceedingly complex to implement correctly. Any rules which do not derive from ConditionalScenarioBehavior should be accompanied by a clear explanation of the reasons that ConditionalScenarioBehavior is an unsuitable base class for the intended behavior. Rules which do derive from ConditionalScenarioBehavior should avoid complex overrides of the default logic.&lt;br /&gt;
&lt;br /&gt;
Child rules should be tagged appropriately in the rule editor list to denote execution order.&lt;br /&gt;
&lt;br /&gt;
=== Controlled Selection of a Single Child ===&lt;br /&gt;
When the rule is ready to begin executing children, it selects a single child and unpauses it. All other children remain paused. Once the selected child becomes flagged as WAS COMPLETE, the child is paused and the rule flags itself as COMPLETE.&lt;br /&gt;
&lt;br /&gt;
This style is used where complex conditional selection of child rules is required. This can be used to implement an &amp;quot;if-else&amp;quot; logic flow, a &amp;quot;switch-case&amp;quot; logic flow, or the &amp;quot;Random List&amp;quot; rule. This style should not be used to implement a simple &amp;quot;if&amp;quot; logic flow, because that would unnecessarily restrict the rule to a single child where the &amp;quot;Ordered Execution of Children&amp;quot; style would provide the same functionality while allowing multiple children.&lt;br /&gt;
The rule editor interface should be very explicit about how the child rules will be selected. Child rules should be tagged appropriately in the rule editor list to avoid the user attempting to fit a child rule into the wrong role.&lt;br /&gt;
&lt;br /&gt;
=== Custom Execution with Multiple Children ===&lt;br /&gt;
This style is used for very specific custom-purpose rules, such as a passenger station stop handler. Such rules should give a clear and complete explanation of their operation and their interaction with any child rules in the rule editor interface.&lt;br /&gt;
&lt;br /&gt;
Individual child rules may be executed in an ad-hoc manner by the rule in response to changes in game state. Child rules may or may not be executed simultaneously and may or may not be executed repeatedly depending on the rule; any limitations or gotchas deriving from this should be carefully explained in the rule editor interface.&lt;br /&gt;
&lt;br /&gt;
Child rules should be tagged appropriately in the rule editor list to avoid the user attempting to fit a child rule into the wrong role.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Early Termination via Pause =&lt;br /&gt;
A rule must accept being paused by its parent at any time. This should cause the rule to cease any game state monitoring or other direct effects. The rule must pause all child rules immediately.&lt;br /&gt;
&lt;br /&gt;
In cases where the rule is maintaining some reversible effect on the game world, pausing the rule should end this effect. For example, a rule which displays a message to the user should typically hide the message upon becoming paused, and a rule which causes a rain storm in a specific area should return the weather to normal upon becoming paused. Rules which make a single permanent change to the game world and then immediately flag as COMPLETE should not attempt to reverse the change upon becoming paused. Examples of these rules include configuration of the global weather conditions, or a rule which increments the player&#039;s score or penalty counter.&lt;br /&gt;
&lt;br /&gt;
It is important to note that any pause is resumable, although the parent may not choose to take advantage of this. Pausing a rule followed by unpausing it should result in the rule continuing operation where it left off. The notes on Saving and Loading Driver Sessions (below) are worth considering when evaluating techniques for implementing pause.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Early Termination via Internal Logic =&lt;br /&gt;
In some cases, a rule may begin executing child rules but then make an internal decision to abort execution. This typically occurs in conditional rules where the condition may be re-evaluated as false after it has already been evaluated as true. Such behavior should be made explicit in the rule editor interface and should usually be made optional by providing a checkbox.&lt;br /&gt;
&lt;br /&gt;
There are in fact several possible behavioral variants affecting how condition-deflag is interpreted:&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules and no further evaluation is performed. The rule eventually flags itself as COMPLETE and does not later deflag this.&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules. If the condition becomes deflagged, the child rules are paused. If the condition becomes flagged again, the child rules are continued. Once the child rules have fully completed execution, the rule flags itself as COMPLETE and does not later deflag this.&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules. If the condition becomes deflagged, the child rules are paused. If the condition becomes flagged again, the children are reset and execution starts anew. The rule flags itself as COMPLETE if all children successfully complete, but it will deflag if the condition deflags.&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules. If the condition becomes deflagged, the child rules continue executing. If the condition becomes flagged again, the children are reset and execution starts anew. The rule will flag as COMPLETE if all children successfully complete, but it will deflag if the condition deflags.&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules. The child rules continue execution with no regard for whether the condition changes between flagged or deflagged in either direction. If the condition transitions from deflagged to flagged again after the children have completed, the children are reset and execution starts anew. The rule will flag as COMPLETE if all children successfully complete, but it will deflag itself if the condition deflags. &lt;br /&gt;
&lt;br /&gt;
The complexity here derives from the fact that it is not possible to use the same set of rules multiple times concurrently for different trigger conditions. For example, if a set of rules is used to give demerit points and provide user notifications, and those rules live under a single conditional check which determines whether a train is speeding, it may be difficult to define what should happen if two trains are detected as speeding at the same time, or if a train stops speeding while the notification process is still in progress. It is not always possible to achieve a perfect solution to tracking multiple objects using a single set of rules, but correct selection from the above behaviors can minimise the possibility of serious side-effects.&lt;br /&gt;
&lt;br /&gt;
It is important to note that these behaviors describe how the rule reacts to internal condition checks. The rule&#039;s reaction to being paused by its parent is discussed above under &amp;quot;Early Termination via Pause&amp;quot; and is not affected by the description here.&lt;br /&gt;
&lt;br /&gt;
In short, there are many ways of handling this, and the important thing is for your (parent) rule to clearly explain which approach it is going to use.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Rule Reset =&lt;br /&gt;
A rule may be &#039;&#039;reset&#039;&#039; by its parent. This causes both the COMPLETE and WAS COMPLETE states to be deflagged. Individual rules may also react to the reset by modifying their internal state to forget past or present actions. Parent rules must also cause their children to be reset in turn.&lt;br /&gt;
&lt;br /&gt;
This mechanism is used to permit rules to be used in a repeating scenario, such as responding to a condition which can occur multiple times, or in a repeating loop. At some point after a rule has become flagged as WAS COMPLETE, it will typically become paused and will not be unpaused again. If the rule is to be included in some repeating behavior, this would normally prevent the behavior from operating successfully after the first run through. To avoid this, the parent rule responsible for implementing the repeating behavior will &#039;&#039;reset&#039;&#039; all children when a repeat occurs. This effectively cleans the rules back to their initial state ready to perform their roles again.&lt;br /&gt;
&lt;br /&gt;
It is important to note that a reset should cause the rule to return to its configured settings. For example, if a timer value is configured and is decremented during rule operation, the timer must be reset back to its initial value during rule reset.&lt;br /&gt;
&lt;br /&gt;
It is important to note that there is no requirement to pause a rule prior to resetting it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Saving and Loading Driver Sessions =&lt;br /&gt;
For better or worse, the script VM does not persist across a save/load operation. This means that each rule must correctly save both its configuration state and its runtime state, and must correctly reload those such that the state after a save/load operation is indistinguishable from the original state. The following aspects of the script state must be considered:&lt;br /&gt;
&lt;br /&gt;
* Member variables in the Rule instance.&lt;br /&gt;
* Which threads are running on the Rule instance, and where they are up to in the code flow.&lt;br /&gt;
* Local variables on the stack of each running thread.&lt;br /&gt;
* Non-persistent changes made to the state of other script objects (such as active &#039;sniff&#039; statements).&lt;br /&gt;
* Script Messages which might be in flight at the time of save (these are not persisted, so the net effect is that they are simply deleted between the save and the load.)&lt;br /&gt;
&lt;br /&gt;
Since the game state continues normal operation after a Save, no code flow or other behavioral changes should result from the Save operation itself. Instead, the Save operation (and the design of the rule as a whole) is responsible for ensuring that sufficient data is persisted in the save file such that the Load operation is able to restore to the correct running state.&lt;br /&gt;
&lt;br /&gt;
The rule base class, ScenarioBehavior, is responsible for saving and loading the rule state flags (COMPLETE, PAUSED, WAS COMPLETE, etc.) A rule which was paused at Save time will still be paused after the Load. A rule which was complete at Save time will still be complete after the Load. During a Load operation, the rule should inherit the parent class&#039; SetProperties() method so that these flags are correctly configured, then honor the paused state during the rest of the loading process.&lt;br /&gt;
&lt;br /&gt;
It is rarely appropriate for an unpaused rule to simply restart execution from the beginning. Care must be taken to ensure that execution resumes from the point that it left off at the time of saving. This process can be simplified by keeping as much state as possible in the rule member variables at all times, and only keeping reconstructible temporary values on the stack. If the member variables are correctly stored and restored, this approach will allow the loading process to detect the runtime state of the rule and resume any necessary threads, which will in turn be able to jump forward to the correct area of the code based on the stored state.&lt;br /&gt;
&lt;br /&gt;
Finally, the COMPLETE, WAS COMPLETE, and PAUSED flags on child rules should be honored. This is typically sufficient information to determine the running state of child rules, so no further state will generally need to be maintained. More accurately, the child rules take care of their own state at all times, and the parent only needs to react to changes in the child state. Since no child state change occurs across a Save/Load operation, the parent does not need to become involved.&lt;br /&gt;
&lt;br /&gt;
For rules which derive ConditionalScenarioBehavior, the majority of load/save logic is handled automatically. The only state information that such a rule should typically preserve is the instance-specific configuration data. The condition-monitor thread will be automatically restarted as required, and there is generally no need to distinguish between a first-startup and any subsequent startup.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Spurious Events =&lt;br /&gt;
There are various events (typically script messages) that a rule may listen for in order to detect state changes. It is important to note that spurious events are often possible, and that an event handler should often be coupled with a condition check. As a specific example, the &amp;quot;ScenarioBehavior&amp;quot;, &amp;quot;Touch&amp;quot; message typically indicates that a child state has changed, but the message may in fact be sent at any time. This message should prompt the rule to evaluate whether any state changes are necessary, but the rule should not simply assume that a state change is necessary without performing an evaluation.&lt;br /&gt;
&lt;br /&gt;
Similarly, calls to a function such as Pause() may in some cases have no effect. For example, if a rule is already executing and its parent calls Pause(false), the rule should not pause, reset, or change state in any way at all. Similarly, if a rule is already paused and its parent calls Pause(true), the rule should not unpause, reset, fire any events, or otherwise change state in any way at all.&lt;br /&gt;
&lt;br /&gt;
The short version is: do not assume that every event and every method call is supposed to achieve something meaningful. Check first, and if the event is meaningless to you then do nothing at all.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Future Considerations =&lt;br /&gt;
Rules should base their functionality on the state flags such as the PAUSED state, rather than attempting to detect and vary their functionality based on the state of the game.&lt;br /&gt;
&lt;br /&gt;
For example, we currently (in development builds) expose the rules editor in Driver for debugging purposes. This, or some mechanism like it, is likely to be included in public builds in the future. Rules should not assume that it is impossible to be reconfigured during gameplay. This will of course introduce some side effects, such as when an unpaused rule is modified during execution. It is the rule&#039;s responsibility to ensure that these side effects do not lead to script exceptions or to leaked state. For example, if a single thread is supposed to be running, reconfiguring the rule should not cause a second thread to run simultaneously. If a rule sniffs a target vehicle, and the target vehicle is redefined, then the rule should unsniff the original vehicle rather than now sniffing two vehicles.&lt;br /&gt;
&lt;br /&gt;
Likewise, we may in future allow some form of partial state swap between Driver and Surveyor. Rules should not assume that it is impossible to change from any one game state or module to any other game state or module, just because it is not possible at the current time. APIs already exist to detect such state changes where necessary, and in most cases it&#039;s simply not necessary to care whether your rule is in Surveyor or Driver - you should act based on the PAUSED state instead. Rules should deal with the game state as they find it rather than assuming that certain states will not ever occur.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Gotchas =&lt;br /&gt;
There are a few potential gotchas in the script environment that are worth considering when writing any non-trivial rule.&lt;br /&gt;
&lt;br /&gt;
== Response Latency ==&lt;br /&gt;
Scripts tend to rely heavily on message passing and threading. In both cases, there is a delay between triggering a certain behavior (eg. posting an event, or calling a threaded function) and having the receiving code react. Other code may execute during this delay.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
// Calling this might be expected to start and then stop the thread; in reality it&lt;br /&gt;
// will likely simply start the thread and leave it running, because the message&lt;br /&gt;
// is sent prior to the wait() statement starting.&lt;br /&gt;
void DemonstrateBug1(void)&lt;br /&gt;
{&lt;br /&gt;
  Pause(false);&lt;br /&gt;
  Pause(true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// In this case, we use a Sleep() statement to &amp;quot;ensure&amp;quot; that the thread has&lt;br /&gt;
// finished starting. This isn&#039;t actually reliable, but it works as long as the&lt;br /&gt;
// system isn&#039;t under too much load. We follow this up with a rapid pause-&lt;br /&gt;
// unpause sequence. As above, this doesn&#039;t work - the message is sent,&lt;br /&gt;
// then the function immediately checks whether the thread is still running&lt;br /&gt;
// (which it is) and thus the thread isn&#039;t restarted. The function completes,&lt;br /&gt;
// and finally the thread receives the message and exits.&lt;br /&gt;
void DemonstrateBug2(void)&lt;br /&gt;
{&lt;br /&gt;
  Pause(false);&lt;br /&gt;
  Sleep(1.0);&lt;br /&gt;
  Pause(true);&lt;br /&gt;
  Pause(false);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Helper code for the above functions.&lt;br /&gt;
void Pause(bool bIsPaused)&lt;br /&gt;
{&lt;br /&gt;
  if (bIsPaused)&lt;br /&gt;
  {&lt;br /&gt;
    PostMessage(me, &amp;quot;ThisRule&amp;quot;, &amp;quot;Pause&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  else if (!m_bIsThreadRunning)&lt;br /&gt;
  {&lt;br /&gt;
    m_bIsThreadRunning = true;&lt;br /&gt;
    StartThread();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
thread void StartThread(void)&lt;br /&gt;
{&lt;br /&gt;
  while (true)&lt;br /&gt;
  {&lt;br /&gt;
    wait ()&lt;br /&gt;
    {&lt;br /&gt;
    on &amp;quot;ThisRule&amp;quot;, &amp;quot;Pause&amp;quot;:&lt;br /&gt;
      break;&lt;br /&gt;
     ...&lt;br /&gt;
  }&lt;br /&gt;
  m_bIsThreadRunning = false;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Multiple Messages in Flight ==&lt;br /&gt;
It&#039;s possible to post multiple identical messages. This can be useful, but if you&#039;re expecting only one then it can be a source of errors.&lt;br /&gt;
&lt;br /&gt;
In the following pseudocode, each call to SetProperties() will place an additional &amp;quot;Timer&amp;quot;, &amp;quot;Tick&amp;quot; message into the cycle, effectively increasing the rate at which the IdleFunction is called. This will seem to be working for a single call to SetProperties(), which may be all that is called during a trivial testcase. It will probably give reasonable results for a few calls to SetProperties(), although if the function is time-sensitive then the results might be different to expectations. After a larger number of calls to SetProperties(), the object&#039;s message queue may become full, causing it to lose messages at random (perhaps the tick messages, or perhaps other unrelated messages that are more problematic).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
void Init(void)&lt;br /&gt;
{&lt;br /&gt;
  inherited();&lt;br /&gt;
  &lt;br /&gt;
  AddHandler(me, &amp;quot;Timer&amp;quot;, &amp;quot;Tick&amp;quot;, &amp;quot;IdleFunction&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void EnterIdleState(void)&lt;br /&gt;
{&lt;br /&gt;
  IdleFunction();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void IdleFunction(void)&lt;br /&gt;
{&lt;br /&gt;
  PostMessage(me, &amp;quot;Timer&amp;quot;, &amp;quot;Tick&amp;quot;, 1.0);&lt;br /&gt;
  .. do something here ..&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void SetProperties(Soup soup)&lt;br /&gt;
{&lt;br /&gt;
  inherited(soup);&lt;br /&gt;
  &lt;br /&gt;
  EnterIdleState();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A similar problem can occur if you start new threads rather than post new messages.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Thread Guard Variables ==&lt;br /&gt;
It&#039;s common to prevent a singleton thread from being started twice by using a boolean guard variable. Care must be taken to ensure that the guard variable is set and cleared at the correct locations, or they may be ineffective.&lt;br /&gt;
&lt;br /&gt;
The following pseudocode demonstrates one such correct usage. The key points to note are:&lt;br /&gt;
* We set &#039;m_bIsThreadedFunctionRunning&#039; prior to calling the threaded function. Setting it within the threaded function is too late; multiple threads might have already been started before the first thread reaches that point.&lt;br /&gt;
* We don&#039;t confuse whether the thread is actually running with whether we want the thread to be running. Once we ask a thread to start, we can&#039;t stop it starting. If we change our minds and want to stop it again, we must inform it in a way that it will realise after it finishes starting. In the worst-case scenario, we might flipflop on this multiple times before the thread actually starts.&lt;br /&gt;
* Similarly, we don&#039;t rely on messages to control the thread. Enqueuing a separate start or stop message with each StartThread()/StopThread() call might be possible, and we could clear any unwanted prior messages from the object&#039;s queue, but if the thread hasn&#039;t finished starting then it won&#039;t receive the messages anyway.&lt;br /&gt;
* We do rely on messages to wake the thread if it&#039;s waiting on messages, but we don&#039;t use those messages to imply any state - we just have it recheck the current state boolean to get the very latest info.&lt;br /&gt;
* We clear &#039;m_bIsThreadedFunctionRunning&#039; once the decision to exit has become unconditional. At this point, even though the thread is technically still running, we&#039;ll have to start a new thread if we want the thread to continue running.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
bool m_bIsThreadedFunctionRunning = false;&lt;br /&gt;
bool m_bWantThreadedFunctionRunning = false;&lt;br /&gt;
&lt;br /&gt;
void StartThread(void)&lt;br /&gt;
{&lt;br /&gt;
  m_bWantThreadedFunctionRunning = true;&lt;br /&gt;
  &lt;br /&gt;
  if (m_bIsThreadedFunctionRunning)&lt;br /&gt;
    return;&lt;br /&gt;
  &lt;br /&gt;
  m_bIsThreadedFunctionRunning = true;&lt;br /&gt;
  ThreadedFunction();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void StopThread(void)&lt;br /&gt;
{&lt;br /&gt;
  if (!m_bWantThreadedFunctionRunning)&lt;br /&gt;
    return;&lt;br /&gt;
  &lt;br /&gt;
  m_bWantThreadedFunctionRunning = false;&lt;br /&gt;
  PostMessage(me, &amp;quot;Thread&amp;quot;, &amp;quot;Touch&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
thread void ThreadedFunction(void)&lt;br /&gt;
{&lt;br /&gt;
  while (m_bWantThreadedFunctionRunning)&lt;br /&gt;
  {&lt;br /&gt;
    wait()&lt;br /&gt;
    {&lt;br /&gt;
      on &amp;quot;Thread&amp;quot;, &amp;quot;Touch&amp;quot;:&lt;br /&gt;
        break;&lt;br /&gt;
      .. whatever else..&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  m_bIsThreadedFunctionRunning = false;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Not Waiting For Messages ==&lt;br /&gt;
As seen above, it&#039;s possible for a thread to fail to receive posted messages because it wasn&#039;t waiting for them at the time. A more commonly problematic example follows.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
thread void MyThread(void)&lt;br /&gt;
{&lt;br /&gt;
  wait ()&lt;br /&gt;
  {&lt;br /&gt;
    on &amp;quot;Some&amp;quot;, &amp;quot;Condition&amp;quot;:&lt;br /&gt;
      HandleSomeCondition();&lt;br /&gt;
      continue;&lt;br /&gt;
    on &amp;quot;Thread&amp;quot;, &amp;quot;Exit&amp;quot;:&lt;br /&gt;
      break;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void HandleSomeCondition(void)&lt;br /&gt;
{&lt;br /&gt;
  wait ()&lt;br /&gt;
  {&lt;br /&gt;
    on &amp;quot;Some&amp;quot;, &amp;quot;End-Condition&amp;quot;:&lt;br /&gt;
      break;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In this example, the thread is waiting on both &amp;quot;Some&amp;quot;, &amp;quot;Condition&amp;quot; and also &amp;quot;Thread&amp;quot;, &amp;quot;Exit&amp;quot;. Either one will be handled correctly assuming that the thread is already running at the time they are posted. Even if multiple are posted, the thread will simply queue them and run each in turn.&lt;br /&gt;
&lt;br /&gt;
The problem occurs when HandleSomeCondition() is triggered and the thread begins waiting on &amp;quot;Some&amp;quot;, &amp;quot;End-Condition&amp;quot;. In this scenario, the thread is no longer waiting on &amp;quot;Thread&amp;quot;, &amp;quot;Exit&amp;quot;, and any attempt to post that message will simply be ignored. To reiterate: the message dispatch is NOT postponed until the function returns; the message is dropped entirely.&lt;br /&gt;
&lt;br /&gt;
In many cases, the correct behaviour is to move HandleSomeCondition() to a new thread, although that may also carry gotchas that you will need to be careful of (eg. you&#039;ll probably want to terminate the second thread at the same time as the first one, and you may need to consider whether you want multiple of the second thread to run simultaneously or not).&lt;br /&gt;
&lt;br /&gt;
== Performing Actions After Being Told to Stop ==&lt;br /&gt;
In many cases, you may wish to perform cleanup actions when stopping your rule. If your rule is threaded, this can easily become problematic.&lt;br /&gt;
&lt;br /&gt;
Consider the following pseudocode example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
void Pause(bool bIsPaused)&lt;br /&gt;
{&lt;br /&gt;
  if (!bIsPaused &amp;amp;&amp;amp; !m_bIsThreadRunning)&lt;br /&gt;
  {&lt;br /&gt;
    m_bIsThreadRunning = true;&lt;br /&gt;
    MyThread();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
thread void MyThread(void)&lt;br /&gt;
{&lt;br /&gt;
  BeginRule();&lt;br /&gt;
  while (!IsPaused())&lt;br /&gt;
  {&lt;br /&gt;
    Sleep(0.5);&lt;br /&gt;
    UpdateRule();&lt;br /&gt;
  }&lt;br /&gt;
  EndRule();&lt;br /&gt;
  m_bIsThreadRunning = false;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There are three immediately obvious problems:&lt;br /&gt;
&lt;br /&gt;
1. That BeginRule() is called when the thread starts, even if the rule has already been paused again.&lt;br /&gt;
2. That UpdateRule() will be called after each sleep, even if the rule was paused during the sleep.&lt;br /&gt;
3. That EndRule() will be called after the rule has been paused.&lt;br /&gt;
&lt;br /&gt;
This is very problematic because it likely violates a core principles of the rules system: that rules will not undertake any meaningful behaviour when paused. All three functions may be called while the rule is paused, so unless the rule does nothing meaningful at all, this is a guaranteed violation.&lt;br /&gt;
&lt;br /&gt;
The best approach to resolving this may depend on exactly what these functions do, but one possible solution is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
void Pause(bool bIsPaused)&lt;br /&gt;
{&lt;br /&gt;
  if (bIsPaused)&lt;br /&gt;
  {&lt;br /&gt;
    if (m_bNeedsEndRule)&lt;br /&gt;
    {&lt;br /&gt;
      m_bNeedsEndRule = false;&lt;br /&gt;
      EndRule();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  else&lt;br /&gt;
  {&lt;br /&gt;
    if (!m_bNeedsEndRule)&lt;br /&gt;
    {&lt;br /&gt;
      BeginRule();&lt;br /&gt;
      m_bNeedsEndRule = true;&lt;br /&gt;
    }&lt;br /&gt;
    if (!m_bIsThreadRunning)&lt;br /&gt;
    {&lt;br /&gt;
      m_bIsThreadRunning = true;&lt;br /&gt;
      MyThread();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
thread void MyThread(void)&lt;br /&gt;
{&lt;br /&gt;
  while (!IsPaused())&lt;br /&gt;
  {&lt;br /&gt;
    UpdateRule();&lt;br /&gt;
    Sleep(0.5);&lt;br /&gt;
  }&lt;br /&gt;
  m_bIsThreadRunning = false;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=Session_Rule_Implementation&amp;diff=16825</id>
		<title>Session Rule Implementation</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=Session_Rule_Implementation&amp;diff=16825"/>
		<updated>2018-11-27T16:44:01Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page seeks to clearly define expected script behavior for [[KIND Scenariobehavior|Session Rule assets]]. This focuses specifically on correct behavior from the code perspective, rather than addressing how rules should be designed for best gameplay outcomes.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Legacy Behavior Note =&lt;br /&gt;
Please note that many existing rules do not behave correctly as defined here. This is considered a bug in the individual session rules. [[N3V Games]] has a policy of updating session rules to behave correctly even where that may lead to changes of function in existing [[session]] assets. Where reasonable to achieve, emulation of the existing (buggy) behavior may occur for existing rule instances in existing sessions, however any newly created rule instances will use the corrected behavior.&lt;br /&gt;
&lt;br /&gt;
These expectations were codified at the end of [[TS12]] development due to an increasing inability of session rules to work together resulting from the unpredictable nature of their responses to various common use-cases. The systems as a whole, including most of the core rules discussed in this document, have existed for far longer than this document. The document does not redefine any existing systems, but simply presents the only reasonable implementation approach possible if rules are to be expected to work properly in all use-cases. In some cases we also choose to mandate specific points of behavior relating to user expectations rather than technical necessities.&lt;br /&gt;
&lt;br /&gt;
Certain additional API mechanisms were introduced alongside the development of this document, to allow better communication with session authors regarding the differences in behavior between certain types of rule. The correct usage for these mechanisms is also included in this document.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= The Rule Hierarchy =&lt;br /&gt;
All rules within a given session form a simple tree structure.&lt;br /&gt;
&lt;br /&gt;
== Rule State Flags ==&lt;br /&gt;
Each rule in the tree may have certain associated state flagged, including a combination of the following:&lt;br /&gt;
&lt;br /&gt;
=== PAUSED ===&lt;br /&gt;
The rule is currently paused, meaning that it does not affect the game world in any way and does not respond to any changes in the game world. The parent rule must cause the rule to become unpaused for the rule to have any effect. It is not correct behavior for a rule to unpause itself.&lt;br /&gt;
&lt;br /&gt;
=== COMPLETE ===&lt;br /&gt;
This flag indicates that rule has fully completed its operation (including any child rule operations) and does not affect the game world in any way. This flag is set by the rule itself, not by an outside entity such as the parent. This state should not be changed while the rule is PAUSED.&lt;br /&gt;
&lt;br /&gt;
Being COMPLETE does not imply being PAUSED. In many scenarios, the parent rule may respond to a child becoming COMPLETE by causing it to also become PAUSED, however this is certainly not guaranteed in all cases, and is not guaranteed to be immediate in the cases where it does happen.&lt;br /&gt;
&lt;br /&gt;
The rule may optionally respond to specific changes in the game world by deflagging the COMPLETE status. For example, a rule which specifically implements a condition check may choose to become COMPLETE when that condition is met, but return to an incomplete state when the condition is no longer met (again, remembering that a change in either direction should only happen while the rule itself is not PAUSED).&lt;br /&gt;
&lt;br /&gt;
When a rule&#039;s COMPLETE state changes, a &amp;quot;ScenarioBehavior&amp;quot;, &amp;quot;Touch&amp;quot; message is sent &#039;&#039;&#039;(TBD: BY WHAT MECHANISM?)&#039;&#039;&#039; to its parent rule (if any), unless the parent is in the PAUSED state. This allows the parent to react to changes in its child rules&#039; states. It is important to note that the message indicates a possible change which the parent may be interested in, but it is the parent rule&#039;s responsibility to determine whether the state change is worth reacting to.&lt;br /&gt;
&lt;br /&gt;
=== WAS COMPLETE ===&lt;br /&gt;
This is typically set when a rule first becomes flagged as COMPLETE, and will stay set even if the rule later flags as incomplete. This can be used by a parent which only cares that the child rule has been flagged as COMPLETE at some point, rather than caring what its current completion status is.&lt;br /&gt;
&lt;br /&gt;
=== DOES COMPLETE ===&lt;br /&gt;
This indicates whether the rule can ever reach the COMPLETE state. Its value is constant for a given rule configuration, and does not change based on the runtime rule state or other game state. Rules which are flagged as DOES COMPLETE are expected to become complete after some discreet operations are completed. Rules which are not flagged are expected to run indefinitely unless PAUSED by an external agent (such as the parent rule).&lt;br /&gt;
&lt;br /&gt;
== Initial State ==&lt;br /&gt;
All rules are initially in the PAUSED state when in [[Surveyor]], and only become unpaused after gameplay begins in a [[Driver]] session. Since a PAUSED rule is not permitted to unpause itself, this is a stable state which will persist until the native code takes step to begin program flow.&lt;br /&gt;
&lt;br /&gt;
== Top Level Rules ==&lt;br /&gt;
All rules at the top level (ie. rules which are not a child of any other rule) simultaneously become unpaused after the session has loaded into Driver. Some of these rules may take initial setup steps and then become COMPLETE. Some of these rules may begin monitoring for specific game conditions before taking any further action. Some of these rules may begin taking action immediately. The rules are not sequenced against each other in any way, and it is the session author&#039;s responsibility to ensure that this does not cause any conflicts.&lt;br /&gt;
&lt;br /&gt;
== Scheduling ==&lt;br /&gt;
Since the script VM is a cooperatively-threaded environment, it is technically true that rule evaluation will occur in an ordered manner rather than truly simultaneously. However, no guarantees are made regarding the order in which the simultaneously-running rules will perform their checks or outcomes. Since rules may wait internally rather than fulfilling their entire purpose in an atomic operation, it is also not guaranteed that a first-running rule will fully complete before some other simultaneously-executing rule begins completion. In short, if order-of-execution is critical to the correct behavior of a session, then the order should be enforced by the session creator using the rule hierarchy rather than by making assumptions about execution order of simultaneously-running rules.&lt;br /&gt;
&lt;br /&gt;
(Note: with the introduction of [[Asynchronous Route Streaming]], this is even more true than previously. What may have been a near-instantaneous operation in older builds may now require a wait of several seconds while the necessary data is streamed in.)&lt;br /&gt;
&lt;br /&gt;
It is important to note that some conditional rules may partially or completely rely on a polling behavior to evaluate their conditions. (An example of partial reliance is a rule which waits for an event, but then evaluates a condition to clarify whether the event should be acted upon.) In these cases, it is possible that the condition can rapidly become true and then become false again without the rule responding. This results in an uncertainty as to whether the conditional rule will correctly detect a given instance of the condition. This type of scenario should be avoided completely where possible, and should most definitely be limited to outcomes that do not significantly affect gameplay.&lt;br /&gt;
&lt;br /&gt;
For a hypothetical example, if the player&#039;s train speeds for 0.5sec, and a speeding check rule was implemented that polled every second, then the overspeed event may or may not trigger on any given occurrence. A session creator should not use this outcome as a failure condition, since some players may be able to speed without penalty, whereas other players would be penalised on the first attempt. A sensible solution in this case might be to increment a counter while speeding is detected, and only take action if the counter reaches a certain threshold. If the only penalty was a warning to the player which had no actual gameplay impact, then it might be acceptable to forgo this check and simply accept that some players will receive a warning where others may not.&lt;br /&gt;
&lt;br /&gt;
==Child Rules==&lt;br /&gt;
As with all other rules, child rules (ie. those that have parent rules in the hierarchy) start out in the PAUSED state. They do not become unpaused until the parent is ready for the children to start operating. Exactly when this occurs depends on the specific parent rule, but the general flow is the same for all rules:&lt;br /&gt;
&lt;br /&gt;
1. Parent rule becomes unpaused and begins operation.&lt;br /&gt;
2. Parent rule configures any necessary world state changes.&lt;br /&gt;
3. Parent rule optionally waits for a specific condition to occur.&lt;br /&gt;
4. Parent rule begins executing its children. This involves unpausing one or more of the children (as discussed below in &amp;quot;Parent Rule Styles&amp;quot;).&lt;br /&gt;
5. Parent waits for its children to complete (as discussed below in &amp;quot;Parent Rule Styles&amp;quot;) and then pauses the children.&lt;br /&gt;
6. Parent flags itself as COMPLETE.&lt;br /&gt;
&lt;br /&gt;
This process allows program control flow to pass from a top-level rule, to its immediate children, to their immediate children, and so on. As the bottom-level children become complete, completion flows back to the higher level children until finally the top-level rules become COMPLETE.&lt;br /&gt;
&lt;br /&gt;
It is worth noting that there is nothing special about a top-level rule being flagged as COMPLETE. This does not indicate an end-of-session or any other fundamental gameplay mode change. Since the pausing of rules on completion is handled by the parent rule (see step 5 above), the top-level rules never become PAUSED on completion.&lt;br /&gt;
&lt;br /&gt;
==Parent Rule Styles==&lt;br /&gt;
There are a few common techniques with which parent rules interact with their children. Rules should always fit one of these descriptions. The vast majority of rules should follow either the &amp;quot;Does Not Support Children&amp;quot; style, or the &amp;quot;Ordered Execution of Children&amp;quot; style.&lt;br /&gt;
&lt;br /&gt;
=== Does Not Support Children ===&lt;br /&gt;
The rule is incapable of supporting children and will always ignore them.&lt;br /&gt;
&lt;br /&gt;
This is used for trivial rules which perform a set function and then become permanently COMPLETE. Such rules are not conditional and do not wait for any world state changes except those which they initiate internally.&lt;br /&gt;
The rule should be configured to validate and/or enforce that no child rules can be added.&lt;br /&gt;
&lt;br /&gt;
=== Simultaneous Execution of Children ===&lt;br /&gt;
When the rule is ready to begin executing children, it unpauses all children simultaneously. The rule then waits for all children to flag as WAS COMPLETE. Once this is detected, the rule pauses all children and flags itself as COMPLETE.&lt;br /&gt;
This is used for rules which have a specific need to simultaneously execute children, such as the &amp;quot;Simultaneous List&amp;quot; rule.&lt;br /&gt;
&lt;br /&gt;
The rule editor interface should be explicit that child rules will be executed simultaneously. Child rules should be tagged appropriately in the rule editor list to denote unordered execution.&lt;br /&gt;
&lt;br /&gt;
=== Ordered Execution of Children ===&lt;br /&gt;
When the rule is ready to begin executing children, it iterates through the children in top-to-bottom order. If the child is flagged as WAS COMPLETE, the child is paused and iteration continues. If the child is not flagged as WAS COMPLETE, the child is unpaused and iteration ends. Whenever a child state change is detected, this process is repeated from the start. Once iteration passes over all children without leaving any child unpaused, the rule flags itself as COMPLETE.&lt;br /&gt;
&lt;br /&gt;
This style is used for all rules which do not explicitly fall under one of the other styles described here. Almost all third-party rules will follow this style. Implementing one of the other styles without there being a fundamental requirement to do so is considered a programming error.&lt;br /&gt;
&lt;br /&gt;
Rules which follow this style should derive from ConditionalScenarioBehavior in order to avoid re-implementing the control flow logic, as it is exceedingly complex to implement correctly. Any rules which do not derive from ConditionalScenarioBehavior should be accompanied by a clear explanation of the reasons that ConditionalScenarioBehavior is an unsuitable base class for the intended behavior. Rules which do derive from ConditionalScenarioBehavior should avoid complex overrides of the default logic.&lt;br /&gt;
&lt;br /&gt;
Child rules should be tagged appropriately in the rule editor list to denote execution order.&lt;br /&gt;
&lt;br /&gt;
=== Controlled Selection of a Single Child ===&lt;br /&gt;
When the rule is ready to begin executing children, it selects a single child and unpauses it. All other children remain paused. Once the selected child becomes flagged as WAS COMPLETE, the child is paused and the rule flags itself as COMPLETE.&lt;br /&gt;
&lt;br /&gt;
This style is used where complex conditional selection of child rules is required. This can be used to implement an &amp;quot;if-else&amp;quot; logic flow, a &amp;quot;switch-case&amp;quot; logic flow, or the &amp;quot;Random List&amp;quot; rule. This style should not be used to implement a simple &amp;quot;if&amp;quot; logic flow, because that would unnecessarily restrict the rule to a single child where the &amp;quot;Ordered Execution of Children&amp;quot; style would provide the same functionality while allowing multiple children.&lt;br /&gt;
The rule editor interface should be very explicit about how the child rules will be selected. Child rules should be tagged appropriately in the rule editor list to avoid the user attempting to fit a child rule into the wrong role.&lt;br /&gt;
&lt;br /&gt;
=== Custom Execution with Multiple Children ===&lt;br /&gt;
This style is used for very specific custom-purpose rules, such as a passenger station stop handler. Such rules should give a clear and complete explanation of their operation and their interaction with any child rules in the rule editor interface.&lt;br /&gt;
&lt;br /&gt;
Individual child rules may be executed in an ad-hoc manner by the rule in response to changes in game state. Child rules may or may not be executed simultaneously and may or may not be executed repeatedly depending on the rule; any limitations or gotchas deriving from this should be carefully explained in the rule editor interface.&lt;br /&gt;
&lt;br /&gt;
Child rules should be tagged appropriately in the rule editor list to avoid the user attempting to fit a child rule into the wrong role.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Early Termination via Pause =&lt;br /&gt;
A rule must accept being paused by its parent at any time. This should cause the rule to cease any game state monitoring or other direct effects. The rule must pause all child rules immediately.&lt;br /&gt;
&lt;br /&gt;
In cases where the rule is maintaining some reversible effect on the game world, pausing the rule should end this effect. For example, a rule which displays a message to the user should typically hide the message upon becoming paused, and a rule which causes a rain storm in a specific area should return the weather to normal upon becoming paused. Rules which make a single permanent change to the game world and then immediately flag as COMPLETE should not attempt to reverse the change upon becoming paused. Examples of these rules include configuration of the global weather conditions, or a rule which increments the player&#039;s score or penalty counter.&lt;br /&gt;
&lt;br /&gt;
It is important to note that any pause is resumable, although the parent may not choose to take advantage of this. Pausing a rule followed by unpausing it should result in the rule continuing operation where it left off. The notes on Saving and Loading Driver Sessions (below) are worth considering when evaluating techniques for implementing pause.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Early Termination via Internal Logic =&lt;br /&gt;
In some cases, a rule may begin executing child rules but then make an internal decision to abort execution. This typically occurs in conditional rules where the condition may be re-evaluated as false after it has already been evaluated as true. Such behavior should be made explicit in the rule editor interface and should usually be made optional by providing a checkbox.&lt;br /&gt;
&lt;br /&gt;
There are in fact several possible behavioral variants affecting how condition-deflag is interpreted:&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules and no further evaluation is performed. The rule eventually flags itself as COMPLETE and does not later deflag this.&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules. If the condition becomes deflagged, the child rules are paused. If the condition becomes flagged again, the child rules are continued. Once the child rules have fully completed execution, the rule flags itself as COMPLETE and does not later deflag this.&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules. If the condition becomes deflagged, the child rules are paused. If the condition becomes flagged again, the children are reset and execution starts anew. The rule flags itself as COMPLETE if all children successfully complete, but it will deflag if the condition deflags.&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules. If the condition becomes deflagged, the child rules continue executing. If the condition becomes flagged again, the children are reset and execution starts anew. The rule will flag as COMPLETE if all children successfully complete, but it will deflag if the condition deflags.&lt;br /&gt;
* Once the condition is flagged, the rule starts executing child rules. The child rules continue execution with no regard for whether the condition changes between flagged or deflagged in either direction. If the condition transitions from deflagged to flagged again after the children have completed, the children are reset and execution starts anew. The rule will flag as COMPLETE if all children successfully complete, but it will deflag itself if the condition deflags. &lt;br /&gt;
&lt;br /&gt;
The complexity here derives from the fact that it is not possible to use the same set of rules multiple times concurrently for different trigger conditions. For example, if a set of rules is used to give demerit points and provide user notifications, and those rules live under a single conditional check which determines whether a train is speeding, it may be difficult to define what should happen if two trains are detected as speeding at the same time, or if a train stops speeding while the notification process is still in progress. It is not always possible to achieve a perfect solution to tracking multiple objects using a single set of rules, but correct selection from the above behaviors can minimise the possibility of serious side-effects.&lt;br /&gt;
&lt;br /&gt;
It is important to note that these behaviors describe how the rule reacts to internal condition checks. The rule&#039;s reaction to being paused by its parent is discussed above under &amp;quot;Early Termination via Pause&amp;quot; and is not affected by the description here.&lt;br /&gt;
&lt;br /&gt;
In short, there are many ways of handling this, and the important thing is for your (parent) rule to clearly explain which approach it is going to use.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Rule Reset =&lt;br /&gt;
A rule may be &#039;&#039;reset&#039;&#039; by its parent. This causes both the COMPLETE and WAS COMPLETE states to be deflagged. Individual rules may also react to the reset by modifying their internal state to forget past or present actions. Parent rules must also cause their children to be reset in turn.&lt;br /&gt;
&lt;br /&gt;
This mechanism is used to permit rules to be used in a repeating scenario, such as responding to a condition which can occur multiple times, or in a repeating loop. At some point after a rule has become flagged as WAS COMPLETE, it will typically become paused and will not be unpaused again. If the rule is to be included in some repeating behavior, this would normally prevent the behavior from operating successfully after the first run through. To avoid this, the parent rule responsible for implementing the repeating behavior will &#039;&#039;reset&#039;&#039; all children when a repeat occurs. This effectively cleans the rules back to their initial state ready to perform their roles again.&lt;br /&gt;
&lt;br /&gt;
It is important to note that a reset should cause the rule to return to its configured settings. For example, if a timer value is configured and is decremented during rule operation, the timer must be reset back to its initial value during rule reset.&lt;br /&gt;
&lt;br /&gt;
It is important to note that there is no requirement to pause a rule prior to resetting it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Saving and Loading Driver Sessions =&lt;br /&gt;
For better or worse, the script VM does not persist across a save/load operation. This means that each rule must correctly save both its configuration state and its runtime state, and must correctly reload those such that the state after a save/load operation is indistinguishable from the original state. The following aspects of the script state must be considered:&lt;br /&gt;
&lt;br /&gt;
* Member variables in the Rule instance.&lt;br /&gt;
* Which threads are running on the Rule instance, and where they are up to in the code flow.&lt;br /&gt;
* Local variables on the stack of each running thread.&lt;br /&gt;
* Non-persistent changes made to the state of other script objects (such as active &#039;sniff&#039; statements).&lt;br /&gt;
* Script Messages which might be in flight at the time of save (these are not persisted, so the net effect is that they are simply deleted between the save and the load.)&lt;br /&gt;
&lt;br /&gt;
Since the game state continues normal operation after a Save, no code flow or other behavioral changes should result from the Save operation itself. Instead, the Save operation (and the design of the rule as a whole) is responsible for ensuring that sufficient data is persisted in the save file such that the Load operation is able to restore to the correct running state.&lt;br /&gt;
&lt;br /&gt;
The rule base class, ScenarioBehavior, is responsible for saving and loading the rule state flags (COMPLETE, PAUSED, WAS COMPLETE, etc.) A rule which was paused at Save time will still be paused after the Load. A rule which was complete at Save time will still be complete after the Load. During a Load operation, the rule should inherit the parent class&#039; SetProperties() method so that these flags are correctly configured, then honor the paused state during the rest of the loading process.&lt;br /&gt;
&lt;br /&gt;
It is rarely appropriate for an unpaused rule to simply restart execution from the beginning. Care must be taken to ensure that execution resumes from the point that it left off at the time of saving. This process can be simplified by keeping as much state as possible in the rule member variables at all times, and only keeping reconstructible temporary values on the stack. If the member variables are correctly stored and restored, this approach will allow the loading process to detect the runtime state of the rule and resume any necessary threads, which will in turn be able to jump forward to the correct area of the code based on the stored state.&lt;br /&gt;
&lt;br /&gt;
Finally, the COMPLETE, WAS COMPLETE, and PAUSED flags on child rules should be honored. This is typically sufficient information to determine the running state of child rules, so no further state will generally need to be maintained. More accurately, the child rules take care of their own state at all times, and the parent only needs to react to changes in the child state. Since no child state change occurs across a Save/Load operation, the parent does not need to become involved.&lt;br /&gt;
&lt;br /&gt;
For rules which derive ConditionalScenarioBehavior, the majority of load/save logic is handled automatically. The only state information that such a rule should typically preserve is the instance-specific configuration data. The condition-monitor thread will be automatically restarted as required, and there is generally no need to distinguish between a first-startup and any subsequent startup.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Spurious Events =&lt;br /&gt;
There are various events (typically script messages) that a rule may listen for in order to detect state changes. It is important to note that spurious events are often possible, and that an event handler should often be coupled with a condition check. As a specific example, the &amp;quot;ScenarioBehavior&amp;quot;, &amp;quot;Touch&amp;quot; message typically indicates that a child state has changed, but the message may in fact be sent at any time. This message should prompt the rule to evaluate whether any state changes are necessary, but the rule should not simply assume that a state change is necessary without performing an evaluation.&lt;br /&gt;
&lt;br /&gt;
Similarly, calls to a function such as Pause() may in some cases have no effect. For example, if a rule is already executing and its parent calls Pause(false), the rule should not pause, reset, or change state in any way at all. Similarly, if a rule is already paused and its parent calls Pause(true), the rule should not unpause, reset, fire any events, or otherwise change state in any way at all.&lt;br /&gt;
&lt;br /&gt;
The short version is: do not assume that every event and every method call is supposed to achieve something meaningful. Check first, and if the event is meaningless to you then do nothing at all.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Future Considerations =&lt;br /&gt;
Rules should base their functionality on the state flags such as the PAUSED state, rather than attempting to detect and vary their functionality based on the state of the game.&lt;br /&gt;
&lt;br /&gt;
For example, we currently (in development builds) expose the rules editor in Driver for debugging purposes. This, or some mechanism like it, is likely to be included in public builds in the future. Rules should not assume that it is impossible to be reconfigured during gameplay. This will of course introduce some side effects, such as when an unpaused rule is modified during execution. It is the rule&#039;s responsibility to ensure that these side effects do not lead to script exceptions or to leaked state. For example, if a single thread is supposed to be running, reconfiguring the rule should not cause a second thread to run simultaneously. If a rule sniffs a target vehicle, and the target vehicle is redefined, then the rule should unsniff the original vehicle rather than now sniffing two vehicles.&lt;br /&gt;
&lt;br /&gt;
Likewise, we may in future allow some form of partial state swap between Driver and Surveyor. Rules should not assume that it is impossible to change from any one game state or module to any other game state or module, just because it is not possible at the current time. APIs already exist to detect such state changes where necessary, and in most cases it&#039;s simply not necessary to care whether your rule is in Surveyor or Driver - you should act based on the PAUSED state instead. Rules should deal with the game state as they find it rather than assuming that certain states will not ever occur.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Gotchas =&lt;br /&gt;
There are a few potential gotchas in the script environment that are worth considering when writing any non-trivial rule.&lt;br /&gt;
&lt;br /&gt;
== Response Latency ==&lt;br /&gt;
Scripts tend to rely heavily on message passing and threading. In both cases, there is a delay between triggering a certain behavior (eg. posting an event, or calling a threaded function) and having the receiving code react. Other code may execute during this delay.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
// Calling this might be expected to start and then stop the thread; in reality it&lt;br /&gt;
// will likely simply start the thread and leave it running, because the message&lt;br /&gt;
// is sent prior to the wait() statement starting.&lt;br /&gt;
void DemonstrateBug1(void)&lt;br /&gt;
{&lt;br /&gt;
  Pause(false);&lt;br /&gt;
  Pause(true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// In this case, we use a Sleep() statement to &amp;quot;ensure&amp;quot; that the thread has&lt;br /&gt;
// finished starting. This isn&#039;t actually reliable, but it works as long as the&lt;br /&gt;
// system isn&#039;t under too much load. We follow this up with a rapid pause-&lt;br /&gt;
// unpause sequence. As above, this doesn&#039;t work - the message is sent,&lt;br /&gt;
// then the function immediately checks whether the thread is still running&lt;br /&gt;
// (which it is) and thus the thread isn&#039;t restarted. The function completes,&lt;br /&gt;
// and finally the thread receives the message and exits.&lt;br /&gt;
void DemonstrateBug2(void)&lt;br /&gt;
{&lt;br /&gt;
  Pause(false);&lt;br /&gt;
  Sleep(1.0);&lt;br /&gt;
  Pause(true);&lt;br /&gt;
  Pause(false);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Helper code for the above functions.&lt;br /&gt;
void Pause(bool bIsPaused)&lt;br /&gt;
{&lt;br /&gt;
  if (bIsPaused)&lt;br /&gt;
  {&lt;br /&gt;
    PostMessage(me, &amp;quot;ThisRule&amp;quot;, &amp;quot;Pause&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  else if (!m_bIsThreadRunning)&lt;br /&gt;
  {&lt;br /&gt;
    m_bIsThreadRunning = true;&lt;br /&gt;
    StartThread();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
thread void StartThread(void)&lt;br /&gt;
{&lt;br /&gt;
  while (true)&lt;br /&gt;
  {&lt;br /&gt;
    wait ()&lt;br /&gt;
    {&lt;br /&gt;
    on &amp;quot;ThisRule&amp;quot;, &amp;quot;Pause&amp;quot;:&lt;br /&gt;
      break;&lt;br /&gt;
     ...&lt;br /&gt;
  }&lt;br /&gt;
  m_bIsThreadRunning = false;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Multiple Messages in Flight ==&lt;br /&gt;
It&#039;s possible to post multiple identical messages. This can be useful, but if you&#039;re expecting only one then it can be a source of errors.&lt;br /&gt;
&lt;br /&gt;
In the following pseudocode, each call to SetProperties() will place an additional &amp;quot;Timer&amp;quot;, &amp;quot;Tick&amp;quot; message into the cycle, effectively increasing the rate at which the IdleFunction is called. This will seem to be working for a single call to SetProperties(), which may be all that is called during a trivial testcase. It will probably give reasonable results for a few calls to SetProperties(), although if the function is time-sensitive then the results might be different to expectations. After a larger number of calls to SetProperties(), the object&#039;s message queue may become full, causing it to lose messages at random (perhaps the tick messages, or perhaps other unrelated messages that are more problematic).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
void Init(void)&lt;br /&gt;
{&lt;br /&gt;
  inherited();&lt;br /&gt;
  &lt;br /&gt;
  AddHandler(me, &amp;quot;Timer&amp;quot;, &amp;quot;Tick&amp;quot;, &amp;quot;IdleFunction&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void EnterIdleState(void)&lt;br /&gt;
{&lt;br /&gt;
  IdleFunction();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void IdleFunction(void)&lt;br /&gt;
{&lt;br /&gt;
  PostMessage(me, &amp;quot;Timer&amp;quot;, &amp;quot;Tick&amp;quot;, 1.0);&lt;br /&gt;
  .. do something here ..&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void SetProperties(Soup soup)&lt;br /&gt;
{&lt;br /&gt;
  inherited(soup);&lt;br /&gt;
  &lt;br /&gt;
  EnterIdleState();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A similar problem can occur if you start new threads rather than post new messages.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Thread Guard Variables ==&lt;br /&gt;
It&#039;s common to prevent a singleton thread from being started twice by using a boolean guard variable. Care must be taken to ensure that the guard variable is set and cleared at the correct locations, or they may be ineffective.&lt;br /&gt;
&lt;br /&gt;
The following pseudocode demonstrates one such correct usage. The key points to note are:&lt;br /&gt;
* We set &#039;m_bIsThreadedFunctionRunning&#039; prior to calling the threaded function. Setting it within the threaded function is too late; multiple threads might have already been started before the first thread reaches that point.&lt;br /&gt;
* We don&#039;t confuse whether the thread is actually running with whether we want the thread to be running. Once we ask a thread to start, we can&#039;t stop it starting. If we change our minds and want to stop it again, we must inform it in a way that it will realise after it finishes starting. In the worst-case scenario, we might flipflop on this multiple times before the thread actually starts.&lt;br /&gt;
* Similarly, we don&#039;t rely on messages to control the thread. Enqueuing a separate start or stop message with each StartThread()/StopThread() call might be possible, and we could clear any unwanted prior messages from the object&#039;s queue, but if the thread hasn&#039;t finished starting then it won&#039;t receive the messages anyway.&lt;br /&gt;
* We do rely on messages to wake the thread if it&#039;s waiting on messages, but we don&#039;t use those messages to imply any state - we just have it recheck the current state boolean to get the very latest info.&lt;br /&gt;
* We clear &#039;m_bIsThreadedFunctionRunning&#039; once the decision to exit has become unconditional. At this point, even though the thread is technically still running, we&#039;ll have to start a new thread if we want the thread to continue running.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
bool m_bIsThreadedFunctionRunning = false;&lt;br /&gt;
bool m_bWantThreadedFunctionRunning = false;&lt;br /&gt;
&lt;br /&gt;
void StartThread(void)&lt;br /&gt;
{&lt;br /&gt;
  m_bWantThreadedFunctionRunning = true;&lt;br /&gt;
  &lt;br /&gt;
  if (m_bIsThreadedFunctionRunning)&lt;br /&gt;
    return;&lt;br /&gt;
  &lt;br /&gt;
  m_bIsThreadedFunctionRunning = true;&lt;br /&gt;
  ThreadedFunction();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void StopThread(void)&lt;br /&gt;
{&lt;br /&gt;
  if (!m_bWantThreadedFunctionRunning)&lt;br /&gt;
    return;&lt;br /&gt;
  &lt;br /&gt;
  m_bWantThreadedFunctionRunning = false;&lt;br /&gt;
  PostMessage(me, &amp;quot;Thread&amp;quot;, &amp;quot;Touch&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
thread void ThreadedFunction(void)&lt;br /&gt;
{&lt;br /&gt;
  while (m_bWantThreadedFunctionRunning)&lt;br /&gt;
  {&lt;br /&gt;
    wait()&lt;br /&gt;
    {&lt;br /&gt;
      on &amp;quot;Thread&amp;quot;, &amp;quot;Touch&amp;quot;:&lt;br /&gt;
        break;&lt;br /&gt;
      .. whatever else..&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  m_bIsThreadedFunctionRunning = false;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Not Waiting For Messages ==&lt;br /&gt;
As seen above, it&#039;s possible for a thread to fail to receive posted messages because it wasn&#039;t waiting for them at the time. A more commonly problematic example follows.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
thread void MyThread(void)&lt;br /&gt;
{&lt;br /&gt;
  wait ()&lt;br /&gt;
  {&lt;br /&gt;
    on &amp;quot;Some&amp;quot;, &amp;quot;Condition&amp;quot;:&lt;br /&gt;
      HandleSomeCondition();&lt;br /&gt;
      continue;&lt;br /&gt;
    on &amp;quot;Thread&amp;quot;, &amp;quot;Exit&amp;quot;:&lt;br /&gt;
      break;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void HandleSomeCondition(void)&lt;br /&gt;
{&lt;br /&gt;
  wait ()&lt;br /&gt;
  {&lt;br /&gt;
    on &amp;quot;Some&amp;quot;, &amp;quot;End-Condition&amp;quot;:&lt;br /&gt;
      break;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In this example, the thread is waiting on both &amp;quot;Some&amp;quot;, &amp;quot;Condition&amp;quot; and also &amp;quot;Thread&amp;quot;, &amp;quot;Exit&amp;quot;. Either one will be handled correctly assuming that the thread is already running at the time they are posted. Even if multiple are posted, the thread will simply queue them and run each in turn.&lt;br /&gt;
&lt;br /&gt;
The problem occurs when HandleSomeCondition() is triggered and the thread begins waiting on &amp;quot;Some&amp;quot;, &amp;quot;End-Condition&amp;quot;. In this scenario, the thread is no longer waiting on &amp;quot;Thread&amp;quot;, &amp;quot;Exit&amp;quot;, and any attempt to post that message will simply be ignored. To reiterate: the message dispatch is NOT postponed until the function returns; the message is dropped entirely.&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=Session_Rule_Implementation&amp;diff=16824</id>
		<title>Session Rule Implementation</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=Session_Rule_Implementation&amp;diff=16824"/>
		<updated>2018-11-27T13:42:59Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page seeks to clearly define expected script behavior for [[KIND Scenariobehavior|Session Rule assets]]. This focuses specifically on correct behavior from the code perspective, rather than addressing how rules should be designed for best gameplay outcomes.&lt;br /&gt;
&lt;br /&gt;
= Legacy Behavior Note =&lt;br /&gt;
Please note that many existing rules do not behave correctly as defined here. This is considered a bug in the individual session rules. [[N3V Games]] has a policy of updating session rules to behave correctly even where that may lead to changes of function in existing [[session]] assets. Where reasonable to achieve, emulation of the existing (buggy) behavior may occur for existing rule instances in existing sessions, however any newly created rule instances will use the corrected behavior.&lt;br /&gt;
&lt;br /&gt;
These expectations were codified at the end of [[TS12]] development due to an increasing inability of session rules to work together resulting from the unpredictable nature of their responses to various common use-cases. The systems as a whole, including most of the core rules discussed in this document, have existed for far longer than this document. The document does not redefine any existing systems, but simply presents the only reasonable implementation approach possible if rules are to be expected to work properly in all use-cases. In some cases we also choose to mandate specific points of behavior relating to user expectations rather than technical necessities.&lt;br /&gt;
&lt;br /&gt;
Certain additional API mechanisms were introduced alongside the development of this document, to allow better communication with session authors regarding the differences in behavior between certain types of rule. The correct usage for these mechanisms is also included in this document.&lt;br /&gt;
&lt;br /&gt;
= The Rule Hierarchy =&lt;br /&gt;
All rules within a given session form a simple tree structure.&lt;br /&gt;
&lt;br /&gt;
== Rule State Flags ==&lt;br /&gt;
Each rule in the tree may have certain associated state flagged, including a combination of the following:&lt;br /&gt;
&lt;br /&gt;
=== PAUSED ===&lt;br /&gt;
The rule is currently paused, meaning that it does not affect the game world in any way and does not respond to any changes in the game world. The parent rule must cause the rule to become unpaused for the rule to have any effect. It is not correct behavior for a rule to unpause itself.&lt;br /&gt;
&lt;br /&gt;
=== COMPLETE ===&lt;br /&gt;
This flag indicates that rule has fully completed its operation (including any child rule operations) and does not affect the game world in any way. This flag is set by the rule itself, not by an outside entity such as the parent. This state should not be changed while the rule is PAUSED.&lt;br /&gt;
&lt;br /&gt;
Being COMPLETE does not imply being PAUSED. In many scenarios, the parent rule may respond to a child becoming COMPLETE by causing it to also become PAUSED, however this is certainly not guaranteed in all cases, and is not guaranteed to be immediate in the cases where it does happen.&lt;br /&gt;
&lt;br /&gt;
The rule may optionally respond to specific changes in the game world by de-flagging the COMPLETE status. For example, a rule which specifically implements a condition check may choose to become COMPLETE when that condition is met, but return to an incomplete state when the condition is no longer met (again, remembering that a change in either direction should only happen while the rule itself is not PAUSED).&lt;br /&gt;
&lt;br /&gt;
When a rule&#039;s COMPLETE state changes, a &amp;quot;ScenarioBehavior&amp;quot;, &amp;quot;Touch&amp;quot; message is sent &#039;&#039;&#039;(TBD: BY WHAT MECHANISM?)&#039;&#039;&#039; to its parent rule (if any), unless the parent is in the PAUSED state. This allows the parent to react to changes in its child rules&#039; states. It is important to note that the message indicates a possible change which the parent may be interested in, but it is the parent rule&#039;s responsibility to determine whether the state change is worth reacting to.&lt;br /&gt;
&lt;br /&gt;
=== WAS COMPLETE ===&lt;br /&gt;
This is typically set when a rule first becomes flagged as COMPLETE, and will stay set even if the rule later flags as incomplete. This can be used by a parent which only cares that the child rule has been flagged as COMPLETE at some point, rather than caring what its current completion status is.&lt;br /&gt;
&lt;br /&gt;
=== DOES COMPLETE ===&lt;br /&gt;
This indicates whether the rule can ever reach the COMPLETE state. Its value is constant for a given rule configuration, and does not change based on the runtime rule state or other game state. Rules which are flagged as DOES COMPLETE are expected to become complete after some discreet operations are completed. Rules which are not flagged are expected to run indefinitely unless PAUSED by an external agent (such as the parent rule).&lt;br /&gt;
&lt;br /&gt;
== Initial State ==&lt;br /&gt;
All rules are initially in the PAUSED state when in [[Surveyor]], and only become unpaused after gameplay begins in a [[Driver]] session. Since a PAUSED rule is not permitted to unpause itself, this is a stable state which will persist until the native code takes step to begin program flow.&lt;br /&gt;
&lt;br /&gt;
== Top Level Rules ==&lt;br /&gt;
All rules at the top level (ie. rules which are not a child of any other rule) simultaneously become unpaused after the session has loaded into Driver. Some of these rules may take initial setup steps and then become COMPLETE. Some of these rules may begin monitoring for specific game conditions before taking any further action. Some of these rules may begin taking action immediately. The rules are not sequenced against each other in any way, and it is the session author&#039;s responsibility to ensure that this does not cause any conflicts.&lt;br /&gt;
&lt;br /&gt;
== Scheduling ==&lt;br /&gt;
Since the script VM is a cooperatively-threaded environment, it is technically true that rule evaluation will occur in an ordered manner rather than truly simultaneously. However, no guarantees are made regarding the order in which the simultaneously-running rules will perform their checks or outcomes. Since rules may wait internally rather than fulfilling their entire purpose in an atomic operation, it is also not guaranteed that a first-running rule will fully complete before some other simultaneously-executing rule begins completion. In short, if order-of-execution is critical to the correct behavior of a session, then the order should be enforced by the session creator using the rule hierarchy rather than by making assumptions about execution order of simultaneously-running rules.&lt;br /&gt;
&lt;br /&gt;
(Note: with the introduction of [[Asynchronous Route Streaming]], this is even more true than previously. What may have been a near-instantaneous operation in older builds may now require a wait of several seconds while the necessary data is streamed in.)&lt;br /&gt;
&lt;br /&gt;
It is important to note that some conditional rules may partially or completely rely on a polling behavior to evaluate their conditions. (An example of partial reliance is a rule which waits for an event, but then evaluates a condition to clarify whether the event should be acted upon.) In these cases, it is possible that the condition can rapidly become true and then become false again without the rule responding. This results in an uncertainty as to whether the conditional rule will correctly detect a given instance of the condition. This type of scenario should be avoided completely where possible, and should most definitely be limited to outcomes that do not significantly affect gameplay.&lt;br /&gt;
&lt;br /&gt;
For a hypothetical example, if the player&#039;s train speeds for 0.5sec, and a speeding check rule was implemented that polled every second, then the overspeed event may or may not trigger on any given occurrence. A session creator should not use this outcome as a failure condition, since some players may be able to speed without penalty, whereas other players would be penalised on the first attempt. A sensible solution in this case might be to increment a counter while speeding is detected, and only take action if the counter reaches a certain threshold. If the only penalty was a warning to the player which had no actual gameplay impact, then it might be acceptable to forgo this check and simply accept that some players will receive a warning where others may not.&lt;br /&gt;
&lt;br /&gt;
==Child Rules==&lt;br /&gt;
As with all other rules, child rules (ie. those that have parent rules in the hierarchy) start out in the PAUSED state. They do not become unpaused until the parent is ready for the children to start operating. Exactly when this occurs depends on the specific parent rule, but the general flow is the same for all rules:&lt;br /&gt;
&lt;br /&gt;
1. Parent rule becomes unpaused and begins operation.&lt;br /&gt;
2. Parent rule configures any necessary world state changes.&lt;br /&gt;
3. Parent rule optionally waits for a specific condition to occur.&lt;br /&gt;
4. Parent rule begins executing its children. This involves unpausing one or more of the children (as discussed below in &amp;quot;Parent Rule Styles&amp;quot;).&lt;br /&gt;
5. Parent waits for its children to complete (as discussed below in &amp;quot;Parent Rule Styles&amp;quot;) and then pauses the children.&lt;br /&gt;
6. Parent flags itself as COMPLETE.&lt;br /&gt;
&lt;br /&gt;
This process allows program control flow to pass from a top-level rule, to its immediate children, to their immediate children, and so on. As the bottom-level children become complete, completion flows back to the higher level children until finally the top-level rules become COMPLETE.&lt;br /&gt;
&lt;br /&gt;
It is worth noting that there is nothing special about a top-level rule being flagged as COMPLETE. This does not indicate an end-of-session or any other fundamental gameplay mode change. Since the pausing of rules on completion is handled by the parent rule (see step 5 above), the top-level rules never become PAUSED on completion.&lt;br /&gt;
&lt;br /&gt;
==Parent Rule Styles==&lt;br /&gt;
There are a few common techniques with which parent rules interact with their children. Rules should always fit one of these descriptions. The vast majority of rules should follow either the &amp;quot;Does Not Support Children&amp;quot; style, or the &amp;quot;Ordered Execution of Children&amp;quot; style.&lt;br /&gt;
&lt;br /&gt;
=== Does Not Support Children ===&lt;br /&gt;
The rule is incapable of supporting children and will always ignore them.&lt;br /&gt;
&lt;br /&gt;
This is used for trivial rules which perform a set function and then become permanently COMPLETE. Such rules are not conditional and do not wait for any world state changes except those which they initiate internally.&lt;br /&gt;
The rule should be configured to validate and/or enforce that no child rules can be added.&lt;br /&gt;
&lt;br /&gt;
=== Simultaneous Execution of Children ===&lt;br /&gt;
When the rule is ready to begin executing children, it unpauses all children simultaneously. The rule then waits for all children to flag as WAS COMPLETE. Once this is detected, the rule pauses all children and flags itself as COMPLETE.&lt;br /&gt;
This is used for rules which have a specific need to simultaneously execute children, such as the &amp;quot;Simultaneous List&amp;quot; rule.&lt;br /&gt;
&lt;br /&gt;
The rule editor interface should be explicit that child rules will be executed simultaneously. Child rules should be tagged appropriately in the rule editor list to denote unordered execution.&lt;br /&gt;
&lt;br /&gt;
=== Ordered Execution of Children ===&lt;br /&gt;
When the rule is ready to begin executing children, it iterates through the children in top-to-bottom order. If the child is flagged as WAS COMPLETE, the child is paused and iteration continues. If the child is not flagged as WAS COMPLETE, the child is unpaused and iteration ends. Whenever a child state change is detected, this process is repeated from the start. Once iteration passes over all children without leaving any child unpaused, the rule flags itself as COMPLETE.&lt;br /&gt;
&lt;br /&gt;
This style is used for all rules which do not explicitly fall under one of the other styles described here. Almost all third-party rules will follow this style. Implementing one of the other styles without there being a fundamental requirement to do so is considered a programming error.&lt;br /&gt;
&lt;br /&gt;
Rules which follow this style should derive from ConditionalScenarioBehavior in order to avoid re-implementing the control flow logic, as it is exceedingly complex to implement correctly. Any rules which do not derive from ConditionalScenarioBehavior should be accompanied by a clear explanation of the reasons that ConditionalScenarioBehavior is an unsuitable base class for the intended behavior. Rules which do derive from ConditionalScenarioBehavior should avoid complex overrides of the default logic.&lt;br /&gt;
&lt;br /&gt;
Child rules should be tagged appropriately in the rule editor list to denote execution order.&lt;br /&gt;
&lt;br /&gt;
=== Controlled Selection of a Single Child ===&lt;br /&gt;
When the rule is ready to begin executing children, it selects a single child and unpauses it. All other children remain paused. Once the selected child becomes flagged as WAS COMPLETE, the child is paused and the rule flags itself as COMPLETE.&lt;br /&gt;
&lt;br /&gt;
This style is used where complex conditional selection of child rules is required. This can be used to implement an &amp;quot;if-else&amp;quot; logic flow, a &amp;quot;switch-case&amp;quot; logic flow, or the &amp;quot;Random List&amp;quot; rule. This style should not be used to implement a simple &amp;quot;if&amp;quot; logic flow, because that would unnecessarily restrict the rule to a single child where the &amp;quot;Ordered Execution of Children&amp;quot; style would provide the same functionality while allowing multiple children.&lt;br /&gt;
The rule editor interface should be very explicit about how the child rules will be selected. Child rules should be tagged appropriately in the rule editor list to avoid the user attempting to fit a child rule into the wrong role.&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=Session_Rule_Implementation&amp;diff=16823</id>
		<title>Session Rule Implementation</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=Session_Rule_Implementation&amp;diff=16823"/>
		<updated>2018-11-27T13:09:55Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: WIP transcription&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page seeks to clearly define expected script behavior for [[KIND Scenariobehavior|Session Rule assets]]. This focuses specifically on correct behavior from the code perspective, rather than addressing how rules should be designed for best gameplay outcomes.&lt;br /&gt;
&lt;br /&gt;
= Legacy Behavior Note =&lt;br /&gt;
Please note that many existing rules do not behave correctly as defined here. This is considered a bug in the individual session rules. [[N3V Games]] has a policy of updating session rules to behave correctly even where that may lead to changes of function in existing [[session]] assets. Where reasonable to achieve, emulation of the existing (buggy) behavior may occur for existing rule instances in existing sessions, however any newly created rule instances will use the corrected behavior.&lt;br /&gt;
&lt;br /&gt;
These expectations were codified at the end of [[TS12]] development due to an increasing inability of session rules to work together resulting from the unpredictable nature of their responses to various common use-cases. The systems as a whole, including most of the core rules discussed in this document, have existed for far longer than this document. The document does not redefine any existing systems, but simply presents the only reasonable implementation approach possible if rules are to be expected to work properly in all use-cases. In some cases we also choose to mandate specific points of behavior relating to user expectations rather than technical necessities.&lt;br /&gt;
&lt;br /&gt;
Certain additional API mechanisms were introduced alongside the development of this document, to allow better communication with session authors regarding the differences in behavior between certain types of rule. The correct usage for these mechanisms is also included in this document.&lt;br /&gt;
&lt;br /&gt;
= The Rule Hierarchy =&lt;br /&gt;
All rules within a given session form a simple tree structure.&lt;br /&gt;
&lt;br /&gt;
== Rule State Flags ==&lt;br /&gt;
Each rule in the tree may have certain associated state flagged, including a combination of the following:&lt;br /&gt;
&lt;br /&gt;
=== PAUSED ===&lt;br /&gt;
The rule is currently paused, meaning that it does not affect the game world in any way and does not respond to any changes in the game world. The parent rule must cause the rule to become unpaused for the rule to have any effect. It is not correct behavior for a rule to unpause itself.&lt;br /&gt;
&lt;br /&gt;
=== COMPLETE ===&lt;br /&gt;
This flag indicates that rule has fully completed its operation (including any child rule operations) and does not affect the game world in any way. This flag is set by the rule itself, not by an outside entity such as the parent. This state should not be changed while the rule is PAUSED.&lt;br /&gt;
&lt;br /&gt;
Being COMPLETE does not imply being PAUSED. In many scenarios, the parent rule may respond to a child becoming COMPLETE by causing it to also become PAUSED, however this is certainly not guaranteed in all cases, and is not guaranteed to be immediate in the cases where it does happen.&lt;br /&gt;
&lt;br /&gt;
The rule may optionally respond to specific changes in the game world by de-flagging the COMPLETE status. For example, a rule which specifically implements a condition check may choose to become COMPLETE when that condition is met, but return to an incomplete state when the condition is no longer met (again, remembering that a change in either direction should only happen while the rule itself is not PAUSED).&lt;br /&gt;
&lt;br /&gt;
When a rule&#039;s COMPLETE state changes, a &amp;quot;ScenarioBehavior&amp;quot;, &amp;quot;Touch&amp;quot; message is sent &#039;&#039;&#039;(TBD: BY WHAT MECHANISM?)&#039;&#039;&#039; to its parent rule (if any), unless the parent is in the PAUSED state. This allows the parent to react to changes in its child rules&#039; states. It is important to note that the message indicates a possible change which the parent may be interested in, but it is the parent rule&#039;s responsibility to determine whether the state change is worth reacting to.&lt;br /&gt;
&lt;br /&gt;
=== WAS COMPLETE ===&lt;br /&gt;
This is typically set when a rule first becomes flagged as COMPLETE, and will stay set even if the rule later flags as incomplete. This can be used by a parent which only cares that the child rule has been flagged as COMPLETE at some point, rather than caring what its current completion status is.&lt;br /&gt;
&lt;br /&gt;
=== DOES COMPLETE ===&lt;br /&gt;
This indicates whether the rule can ever reach the COMPLETE state. Its value is constant for a given rule configuration, and does not change based on the runtime rule state or other game state. Rules which are flagged as DOES COMPLETE are expected to become complete after some discreet operations are completed. Rules which are not flagged are expected to run indefinitely unless PAUSED by an external agent (such as the parent rule).&lt;br /&gt;
&lt;br /&gt;
== Initial State ==&lt;br /&gt;
All rules are initially in the PAUSED state when in [[Surveyor]], and only become unpaused after gameplay begins in a [[Driver]] session. Since a PAUSED rule is not permitted to unpause itself, this is a stable state which will persist until the native code takes step to begin program flow.&lt;br /&gt;
&lt;br /&gt;
== Top Level Rules ==&lt;br /&gt;
All rules at the top level (ie. rules which are not a child of any other rule) simultaneously become unpaused after the session has loaded into Driver. Some of these rules may take initial setup steps and then become COMPLETE. Some of these rules may begin monitoring for specific game conditions before taking any further action. Some of these rules may begin taking action immediately. The rules are not sequenced against each other in any way, and it is the session author&#039;s responsibility to ensure that this does not cause any conflicts.&lt;br /&gt;
&lt;br /&gt;
== Scheduling ==&lt;br /&gt;
Since the script VM is a cooperatively-threaded environment, it is technically true that rule evaluation will occur in an ordered manner rather than truly simultaneously. However, no guarantees are made regarding the order in which the simultaneously-running rules will perform their checks or outcomes. Since rules may wait internally rather than fulfilling their entire purpose in an atomic operation, it is also not guaranteed that a first-running rule will fully complete before some other simultaneously-executing rule begins completion. In short, if order-of-execution is critical to the correct behavior of a session, then the order should be enforced by the session creator using the rule hierarchy rather than by making assumptions about execution order of simultaneously-running rules.&lt;br /&gt;
&lt;br /&gt;
(Note: with the introduction of [[Asynchronous Route Streaming]], this is even more true than previously. What may have been a near-instantaneous operation in older builds may now require a wait of several seconds while the necessary data is streamed in.)&lt;br /&gt;
&lt;br /&gt;
It is important to note that some conditional rules may partially or completely rely on a polling behavior to evaluate their conditions. (An example of partial reliance is a rule which waits for an event, but then evaluates a condition to clarify whether the event should be acted upon.) In these cases, it is possible that the condition can rapidly become true and then become false again without the rule responding. This results in an uncertainty as to whether the conditional rule will correctly detect a given instance of the condition. This type of scenario should be avoided completely where possible, and should most definitely be limited to outcomes that do not significantly affect gameplay.&lt;br /&gt;
&lt;br /&gt;
For a hypothetical example, if the player&#039;s train speeds for 0.5sec, and a speeding check rule was implemented that polled every second, then the overspeed event may or may not trigger on any given occurrence. A session creator should not use this outcome as a failure condition, since some players may be able to speed without penalty, whereas other players would be penalised on the first attempt. A sensible solution in this case might be to increment a counter while speeding is detected, and only take action if the counter reaches a certain threshold. If the only penalty was a warning to the player which had no actual gameplay impact, then it might be acceptable to forgo this check and simply accept that some players will receive a warning where others may not.&lt;br /&gt;
&lt;br /&gt;
==Child Rules==&lt;br /&gt;
As with all other rules, child rules (ie. those that have parent rules in the hierarchy) start out in the PAUSED state. They do not become unpaused until the parent is ready for the children to start operating. Exactly when this occurs depends on the specific parent rule, but the general flow is the same for all rules:&lt;br /&gt;
&lt;br /&gt;
1. Parent rule becomes unpaused and begins operation.&lt;br /&gt;
2. Parent rule configures any necessary world state changes.&lt;br /&gt;
3. Parent rule optionally waits for a specific condition to occur.&lt;br /&gt;
4. Parent rule begins executing its children. This involves unpausing one or more of the children (as discussed below in &amp;quot;Parent Rule Styles&amp;quot;).&lt;br /&gt;
5. Parent waits for its children to complete (as discussed below in &amp;quot;Parent Rule Styles&amp;quot;) and then pauses the children.&lt;br /&gt;
6. Parent flags itself as COMPLETE.&lt;br /&gt;
&lt;br /&gt;
This process allows program control flow to pass from a top-level rule, to its immediate children, to their immediate children, and so on. As the bottom-level children become complete, completion flows back to the higher level children until finally the top-level rules become COMPLETE.&lt;br /&gt;
&lt;br /&gt;
It is worth noting that there is nothing special about a top-level rule being flagged as COMPLETE. This does not indicate an end-of-session or any other fundamental gameplay mode change. Since the pausing of rules on completion is handled by the parent rule (see step 5 above), the top-level rules never become PAUSED on completion.&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=Category:Validation_Errors&amp;diff=16817</id>
		<title>Category:Validation Errors</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=Category:Validation_Errors&amp;diff=16817"/>
		<updated>2018-11-26T04:30:35Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Validation Error (VE) numbers are logged during content validation, to allow users to look up particular validation messages to better understand the source of the problem. Normal logs provide a substantial amount of technical detail about the error, but typically assume that the reader is familiar with the subject matter and will understand why the log is relevant. This wiki provides the necessary background information to understanding many of the logs, however a user who is unfamiliar with the area in question may not know where to start looking. VE numbers allow users to quickly find relevant pages in the wiki without any prior knowledge of the subject.&lt;br /&gt;
&lt;br /&gt;
This page serves as a master guide to all VE numbers currently logged by Trainz. This page does not provide detailed information on any given VE number- please refer to the individual VE number pages for specific details. The error text here is correct for the English localisation of Trainz at the time of writing, however the exact text may change from time to time. It is intended that the overall meaning of a VE number will never change- new VE numbers will be issued instead, and old VE numbers may be made obsolete.&lt;br /&gt;
&lt;br /&gt;
Logs which lack VE numbers do not belong on this page.&lt;br /&gt;
&lt;br /&gt;
The individual VE pages can be found at the links below, or can be accessed directly from [[Content Manager]] by right-clicking on the Validation Error in the results log, and selecting &amp;quot;View Help for This Message&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|1||[[Help:VE1|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Decimal value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|2||[[Help:VE2|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Integer value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|3||[[Help:VE3|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|4||[[Help:VE4|&amp;quot;&#039;$(TAG_NAME)&#039; must have a positive value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|5||[[Help:VE5|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|6||[[Help:VE6|&amp;quot;&#039;$(TAG_NAME)&#039; must not be zero.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|7||[[Help:VE7|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|8||[[Help:VE8|&amp;quot;The value for &#039;$(TAG_NAME)&#039; must be between &#039;$(MIN)&#039; and &#039;$(MAX)&#039; but was specified as &#039;$(VALUE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|9||[[Help:VE9|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|10||[[Help:VE10|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|11||[[Help:VE11|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|12||[[Help:VE12|&amp;quot;No string-table entry found with tag &#039;$(VALUE)&#039; for for string-token tag &#039;$(TAG)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|13||[[Help:VE13|&amp;quot;Missing or invalid selection for tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|14||[[Help:VE14|&amp;quot;Missing or invalid selection for tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|15||[[Help:VE15|&amp;quot;Attachment point &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must be found in mesh &#039;$(MESH_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|16||[[Help:VE16|&amp;quot;Container &#039;$(CONT_NAME)&#039; does not have an &#039;att-parent&#039; tag which is required to reference an attachment point.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|17||[[Help:VE17|&amp;quot;Attachment point &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must be found in mesh &#039;$(MESH_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|18||[[Help:VE18|&amp;quot;Attachment point &#039;$(TAG_VAL)&#039; referenced by tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; was not found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|19||[[Help:VE19|&amp;quot;Effect &#039;$(EFFECT_NAME)&#039; in &#039;$(CONT_NAME)&#039; was not found within the mesh table.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|20||[[Help:VE20|&amp;quot;Mesh &#039;$(MESH_NAME)&#039; referenced in &#039;$(CONT_NAME)&#039; was not found within the mesh table.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|21||[[Help:VE21|&amp;quot;Attachment point &#039;$(TAG_VAL)&#039; referenced by tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; was not found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|22||[[Help:VE22|&amp;quot;Missing or invalid selection for tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|23||[[Help:VE23|&amp;quot;Invalid tag name &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|24||[[Help:VE24|&amp;quot;Invalid tag name &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|25||[[Help:VE25|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|26||[[Help:VE26|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|27||[[Help:VE27|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must have a mesh file extension.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|28||[[Help:VE28|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must have an image file extension.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|29||[[Help:VE29|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must have an animation file extension.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|30||[[Help:VE30|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; refers to a nonexistent file: &#039;$(FILENAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|31||[[Help:VE31|&amp;quot;Invalid tag name &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|32||[[Help:VE32|&amp;quot;Alias mesh requires valid parent asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|33||[[Help:VE33|&amp;quot;Alias mesh &#039;$(FILE)&#039; not found in dependency $(KUID).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|34||[[Help:VE34|&amp;quot;Alias mesh &#039;$(FILE)&#039; not found in latest version ($(NEW_KUID)) of dependency $(OLD_KUID).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|35||[[Help:VE35|&amp;quot;Required alias mesh asset $(KUID) is missing and cannot be validated.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|36||[[Help:VE36|&amp;quot;The texture &#039;$(FILE)&#039; failed to load.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|37||[[Help:VE37|&amp;quot;The texture &#039;$(FILE)&#039; is not a power of 2, please resize it.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|38||[[Help:VE38|&amp;quot;The texture &#039;$(FILE)&#039; is not square. Cubemap textures need to have the same width and height.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|39||[[Help:VE39|&amp;quot;The texture &#039;$(FILE)&#039; is a uniform color.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|40||[[Help:VE40|&amp;quot;Unable to load $(TYPE) texture &#039;$(TEXTURE)&#039; for texture file &#039;$(FILE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|41||[[Help:VE41|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Integer value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|42||[[Help:VE42|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Decimal value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|43||[[Help:VE43|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Boolean value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|44||[[Help:VE44|&amp;quot;Tag &#039;$(TAG_NAME)&#039; in the container &#039;$(CONT_NAME)&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|45||[[Help:VE45|&amp;quot;The Tag &#039;$(TAG_NAME)&#039; is not permitted within a container of type &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|46||[[Help:VE46|&amp;quot;Internal Error: The template does not specify that a smoke container is valid in the container being parsed.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|47||[[Help:VE47|&amp;quot;Container &#039;$(CONT_NAME)&#039; is not permitted in this section.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|48||[[Help:VE48|&amp;quot;This asset uses an obsolete trainz-build number. Trainz-build numbers below $(LOWEST_TRAINZBUILD) are no longer supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|49||[[Help:VE49|&amp;quot;Required tag &#039;kind&#039; is not present. Ensure this is a valid config file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|50||[[Help:VE50|&amp;quot;Unsupported kind &#039;$(KIND)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|51||[[Help:VE51|&amp;quot;Tag &#039;$(TAG_NAME)&#039; in the container &#039;$(CONT_NAME)&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|52||[[Help:VE52|&amp;quot;The Tag &#039;$(TAG_NAME)&#039; is not permitted within a container of type &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|53||[[Help:VE53|&amp;quot;This container is no longer supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|54||[[Help:VE54|&amp;quot;The Tag &#039;$(TAG_NAME)&#039; is not permitted within a container of type &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|55||[[Help:VE55|&amp;quot;This container is no longer supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|56||[[Help:VE56|&amp;quot;Container &#039;$(CONT_NAME)&#039; is not permitted in this section.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|57||[[Help:VE57|&amp;quot;Container &#039;$(CONT_NAME)&#039; is not permitted in this section.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|58||[[Help:VE58|&amp;quot;The tag &#039;$(TAG_NAME)&#039; is not a valid container type (expected &#039;$(TYPE)&#039;).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|59||[[Help:VE59|&amp;quot;Internal error: unknown dataType - kind &#039;$(KIND)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|60||[[Help:VE60|&amp;quot;Required tag &#039;$(TAG_NAME)&#039; was missing and has been set to default.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|61||[[Help:VE61|&amp;quot;Required tag &#039;$(TAG_NAME)&#039; was missing and has been set to default.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|62||[[Help:VE62|&amp;quot;Required container &#039;$(CONT_NAME)&#039; is missing.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|63||[[Help:VE63|&amp;quot;The cubemap texture &#039;$(FILE)&#039; has missing images. Please verify the texture.txt file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|64||[[Help:VE64|&amp;quot;Cubemap texture &#039;$(FILE)&#039; contains images of different sizes.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|65||[[Help:VE65|&amp;quot;The *.texture.txt file is missing for texture resource &#039;$(FILE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|66||[[Help:VE66|&amp;quot;The texture file &#039;$(FILE)&#039; contains non-ANSI characters. Textures must be ANSI.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|67||[[Help:VE67|&amp;quot;The texture &#039;$(FILE)&#039; does not seem to have a primary texture set. Please verify the texture.txt file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|68||[[Help:VE68|&amp;quot;The primary and alpha texture are not the same size for &#039;$(FILE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|69||[[Help:VE69|&amp;quot;Binary conversion failed for texture resource &#039;$(FILE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|70||[[Help:VE70|&amp;quot;The KUID tag is not a valid KUID value: &#039;$(string)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|71||[[Help:VE71|&amp;quot;Unsupported SpeedTree version for mesh: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|72||[[Help:VE72|&amp;quot;Unable to load mesh file: &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|73||[[Help:VE73|&amp;quot;Image file &#039;$(FILE)&#039; is incorrectly used as both a texture.txt source file and a raw image file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|74||[[Help:VE74|&amp;quot;Image file &#039;$(FILE)&#039; is incorrectly used as both a texture.txt source file and a raw image file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|76||[[Help:VE76|&amp;quot;Unable to load mesh file: &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|77||[[Help:VE77|&amp;quot;Unable to load indexed mesh &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|79||[[Help:VE79|&amp;quot;Unable to load animation file &#039;$(FILE)&#039; (mesh has not been loaded correctly).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|81||[[Help:VE81|&amp;quot;The high-poly mesh &#039;$(FILE)&#039; should have LOD levels.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|82||[[Help:VE82|&amp;quot;High-detail .im files are not supported for traincar assets, as they are likely to perform poorly. It is recommended that you upgrade &#039;$(FILE)&#039; to a .lm file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|83||[[Help:VE83|&amp;quot;The file &#039;$(FILE)&#039; is provided in LM format despite having no attachment points and no animation support. This may have a negative impact on performance.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|84||[[Help:VE84|&amp;quot;The file &#039;$(FILE)&#039; is provided in LM format despite containing only a single mesh. This may have a negative impact on performance.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|85||[[Help:VE85|&amp;quot;The file &#039;$(FILE)&#039; is provided in LM format, however the high-detail mesh is comprised of less than 300 polygons. This may have a negative impact on performance.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|86||[[Help:VE86|&amp;quot;Legacy .pm files are no longer supported, and will perform poorly. It is recommended that you switch to using a .lm file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|87||[[Help:VE87|&amp;quot;Legacy .pm files are no longer supported, and will perform poorly. It is recommended that you switch to using a .lm file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|88||[[Help:VE88|&amp;quot;This asset has a trainz-build number which is not recognised by this tool.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|89||[[Help:VE89|&amp;quot;Tag &#039;$(TAG_NAME)&#039; in the container &#039;$(CONT_NAME)&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|90||[[Help:VE90|&amp;quot;This asset has an invalid KUID user id&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|91||[[Help:VE91|&amp;quot;The dependency $(KUID) has an invalid KUID User ID and cannot be used&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|92||[[Help:VE92|&amp;quot;Duplicate &#039;$(TAG_NAME)&#039; containers in &#039;$(CONT_NAME)&#039;. Containers must have a unique name.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|93||[[Help:VE93|&amp;quot;Duplicate &#039;$(TAG_NAME)&#039; tags in &#039;$(CONT_NAME)&#039;. Tags must have a unique name.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|94||[[Help:VE94|&amp;quot;This asset requires a shadow mesh, but the mesh table does not contain one.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|95||[[Help:VE95|&amp;quot;This asset does not have a mesh that is visible by default.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|96||[[Help:VE96|&amp;quot;Maximum of 5 running number fonts supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|97||[[Help:VE97|&amp;quot;The running number font directory &#039;$(DIR)&#039; could not be found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|98||[[Help:VE98|&amp;quot;The running number font file &#039;$(DIR)/$(FILE)&#039; could not be found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|99||[[Help:VE99|&amp;quot;The track-sound container &#039;$(NAME)&#039; has no bogey, track or track-parent tag.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|100||[[Help:VE100|&amp;quot;Required tag &#039;$(TAG_NAME)&#039; was missing and has been set to default.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|101||[[Help:VE101|&amp;quot;The file &#039;$(FILE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|102||[[Help:VE102|&amp;quot;Failed to load sound file &#039;$(FILE)&#039;, please ensure this is a valid wav file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|103||[[Help:VE103|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|104||[[Help:VE104|&amp;quot;Multiple template property bindings for rule property &#039;$(PROP)&#039; for rule &#039;$(RULE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|105||[[Help:VE105|&amp;quot;The template property &#039;$(NAME)&#039; specified in the rule-template-bindings container of rule &#039;$(RULE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|106||[[Help:VE106|&amp;quot;The high-detail meshes in season $(SEASON) total more than $(LIMIT) polygons. This may have a negative impact on performance: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|107||[[Help:VE107|&amp;quot;The high-detail meshes total more than $(LIMIT) polygons. This may have a negative impact on performance: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|108||[[Help:VE108|&amp;quot;The low-detail meshes in season $(SEASON) total more than 500 polygons. This may have a negative impact on performance: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|109||[[Help:VE109|&amp;quot;The low-detail meshes total more than 500 polygons. This may have a negative impact on performance: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|110||[[Help:VE110|&amp;quot;The meshes in LOD level $(LOD_LEVEL) in season $(SEASON) must total at least 20% fewer polygons than the next higher LOD in the same season: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|111||[[Help:VE111|&amp;quot;The meshes in LOD level $(LOD_LEVEL) must total at least 20% fewer polygons than the next higher LOD: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|112||[[Help:VE112|&amp;quot;Multiple track stretches between &#039;$(FROM_VERTEX)&#039; and &#039;$(TO_VERTEX)&#039; in container &#039;$(CONT_NAME)&#039;. Track stretches must be unique.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|113||[[Help:VE113|&amp;quot;An image file (&#039;$(FILE)&#039;) has been supplied where a texture file (&#039;*.texture.txt&#039;) is required.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|114||[[Help:VE114|&amp;quot;An image file (&#039;$(FILE)&#039;) has been supplied where a texture file (&#039;*.texture.txt&#039;) is required.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|115||[[Help:VE115|&amp;quot;The texture file &#039;$(FILE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|116||[[Help:VE116|&amp;quot;No texture file has been specified for this texture asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|117||[[Help:VE117|&amp;quot;&#039;$(TAG_0)&#039; must be set to a &#039;$(KIND)&#039; for &#039;$(TAG_1)&#039; to be allowed.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|118||[[Help:VE118|&amp;quot;Tag &#039;$(TAG_0)&#039; requires that &#039;$(TAG_1)&#039; be set to &#039;$(KIND)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|119||[[Help:VE119|&amp;quot;The tag &#039;$(TAG_NAME)&#039; is not valid for kind &#039;$(KIND)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|120||[[Help:VE120|&amp;quot;Tag &#039;$(TAG_0)&#039;, requires the tag &#039;$(TAG_1)&#039; to be present.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|121||[[Help:VE121|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|122||[[Help:VE122|&amp;quot;&#039;$(TAG_NAME)&#039; must have a positive value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|123||[[Help:VE123|&amp;quot;The script file &#039;$(FILE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|124||[[Help:VE124|&amp;quot;The file &#039;$(FILE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|125||[[Help:VE125|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|126||[[Help:VE126|&amp;quot;&#039;$(TAG_NAME)&#039; must not be zero.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|127||[[Help:VE127|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|128||[[Help:VE128|&amp;quot;The value for &#039;$(TAG_NAME)&#039; must be between &#039;$(MIN)&#039; and &#039;$(MAX)&#039; but was specified as &#039;$(VALUE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|129||[[Help:VE129|&amp;quot;Incorrect number of values for the tag &#039;$(TAG_NAME)&#039;, expected $(NUM_0) values, found $(NUM_1).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|130||[[Help:VE130|&amp;quot;Too many values for the tag &#039;$(TAG_NAME)&#039;, maximum is $(MAX) values, found $(FOUND).&amp;quot;]]]]&lt;br /&gt;
|-&lt;br /&gt;
|131||[[Help:VE131|&amp;quot;Value must be a mesh from the mesh-table (not a parent container).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|132||[[Help:VE132|&amp;quot;The attachment point &#039;$(ATT)&#039; must belong to the parent mesh of the effect (mesh=$(MESH)).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|133||[[Help:VE133|&amp;quot;A light container must be present to link the signals.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|134||[[Help:VE134|&amp;quot;&#039;$(NUM)&#039; must be a valid light number from the light container.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|135||[[Help:VE135|&amp;quot;&#039;$(TAG_0)&#039; requires that the tag &#039;$(TAG_1)&#039; be present.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|136||[[Help:VE136|&amp;quot;&#039;$(TAG_0)&#039; requires that the tag &#039;$(TAG_1)&#039; be present.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|137||[[Help:VE137|&amp;quot;Empty or invalid running number specified at character index $(INDEX)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|138||[[Help:VE138|&amp;quot;Running number specified at character index $(INDEX) is too large, must be less than 9 characters.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|139||[[Help:VE139|&amp;quot;Invalid running number range specified at character index $(INDEX), ($(FROM)-$(TO)).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|140||[[Help:VE140|&amp;quot;Running number range &#039;$(FROM)-$(TO)&#039; specified at character index $(INDEX) overlaps already in use numbers, running numbers must be unique.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|141||[[Help:VE141|&amp;quot;Running number &#039;$(NUMBER)&#039; specified at character index $(INDEX) is already in use.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|142||[[Help:VE142|&amp;quot;Invalid character &#039;$(CHAR)&#039; specified in running number list, only numbers, &#039;,&#039; and &#039;-&#039; are supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|143||[[Help:VE143|&amp;quot;Possible running number list is too large, the set must contain less than 20000 possibilities.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|144||[[Help:VE144|&amp;quot;Category code &#039;ZX - Paintshed template&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|145||[[Help:VE145|&amp;quot;Category code &#039;ZX - Paintshed template&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|146||[[Help:VE146|&amp;quot;An asset must be specified for tag &#039;$(TAG_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|147||[[Help:VE147|&amp;quot;The tag(s) $(MISPLACED_TAGS) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|148||[[Help:VE148|&amp;quot;The tag(s) $(MISPLACED_TAGS) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|149||[[Help:VE149|&amp;quot;The mesh(es) $(MISPLACED_MESHES) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|150||[[Help:VE150|&amp;quot;The mesh(es) $(MISPLACED_MESHES) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|151||[[Help:VE150|&amp;quot;The mesh(es) $(MISPLACED_MESHES) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|152||[[Help:VE152|&amp;quot;The tags $(MISSING_TAGS) are not all defined. The default values will be used and the positions of the elements may not fit your track.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|153||[[Help:VE153|&amp;quot;The mesh $(MESH) is present but the tag $(MISSING_TAG) is not defined.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|154||[[Help:VE154|&amp;quot;The mesh $(MESH) is present but the tag $(MISSING_TAG) is not defined.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|155||[[Help:VE155|&amp;quot;The mesh $(MESH) is present but the tags $(MISSING_TAGS) are not all defined.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|156||[[Help:VE156|&amp;quot;The tag $(MISSING_TAG) is not defined. The default value will be used and the positions of the elements may not fit your track.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|157||[[Help:VE157|&amp;quot;The mesh $(MESH) is present but the tag $(MISSING_TAG) is missing. The default value will be used and the positions of the elements may not fit your track.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|158||[[Help:VE158|&amp;quot;Unable to open .lm.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|159||[[Help:VE159|&amp;quot;Unable to parse .lm.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|160||[[Help:VE160|&amp;quot;No &#039;mesh&#039; keys found in .lm.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|161||[[Help:VE161|&amp;quot;$(LODCOUNT) LODs in .lm.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|162||[[Help:VE162|&amp;quot;One of the LOD reductions of &#039;$(FILE)&#039; introduces a new attachment point: $(ATT)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|163||[[Help:VE163|&amp;quot;Unable to parse .im file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|164||[[Help:VE164|&amp;quot;Invalid position data in .im file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|165||[[Help:VE165|&amp;quot;Texture &#039;$(TEXTURE)&#039; is missing or could not be loaded in mesh &#039;$(FILE)&#039;, material &#039;$(MATERIAL)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|166||[[Help:VE166|&amp;quot;$(COMBINEDCOUNT) combined chunks (of $(SOURCECOUNT) source) in .im file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|167||[[Help:VE167|&amp;quot;Source image texture file &#039;$(TEXTUREFILE)&#039; is too large for &#039;$(ASSETFILE)&#039; ($(WIDTH)x$(HEIGHT))&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|168||[[Help:VE168|&amp;quot;File &#039;$(TEXTUREFILE)&#039; is not a valid compiled texture file for &#039;$(ASSETFILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|169||[[Help:VE169|&amp;quot;Compiled texture file &#039;$(TEXTUREFILE)&#039; is unsupported version for &#039;$(ASSETFILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|170||[[Help:VE170|&amp;quot;Failed to open compiled texture &#039;$(TEXTUREFILE)&#039; for &#039;$(ASSETFILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|171||[[Help:VE171|&amp;quot;Expected texture file type but found &#039;$(TEXTUREFILE)&#039; for &#039;$(ASSETFILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|172||[[Help:VE172|&amp;quot;Script class does not match asset kind ($(KIND)).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|173||[[Help:VE173|&amp;quot;Material &#039;$(MATERIAL)&#039; in mesh &#039;$(FILE)&#039; is not of a recognised material type.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|174||[[Help:VE174|&amp;quot;MeshObjectSpec::LinkSpecs&amp;gt; Mesh-table element #$(MESH_INDEX) parent mesh is invalid.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|175||[[Help:VE175|&amp;quot;MeshObjectSpec::LinkSpecs&amp;gt; Mesh-table element #$(MESH_INDEX) is part of invalid hierarchy.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|176||[[Help:VE176|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must have a texture file extension.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|177||[[Help:VE177|&amp;quot;The kuid &#039;$(KUID)&#039; is not in the database, and could not be found in any known location. Ensure that this is a valid asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|178||[[Help:VE178|&amp;quot;The asset specified in &#039;$(KUID)&#039; is not installed locally but is available for download.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|179||[[Help:VE179|&amp;quot;The kuid &#039;$(KUID)&#039; specified in &#039;$(TAG_NAME)&#039; is not of the correct type.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|180||[[Help:VE180|&amp;quot;Integrity check failure on $(FILE). One or more route/session tiles may be missing.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|181||[[Help:VE181|&amp;quot;The tag &#039;$(TAG_NAME)&#039; requires a minimum asset version of $(MIN_VERSION)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|182||[[Help:VE182|&amp;quot;Material &#039;$(MATERIAL)&#039; in mesh &#039;$(FILE)&#039; is missing a texture for a mandatory texture slot.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|183||[[Help:VE183|&amp;quot;FBX file is in an unsupported older format.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|184||[[Help:VE184|&amp;quot;KIND &#039;$(KIND)&#039; requires trainz-build $(TRAINZBUILD).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|185||[[Help:VE185|&amp;quot;Material &#039;$(MATERIAL)&#039; in mesh &#039;$(FILE)&#039; has heightmap texture. Provide a normal map instead.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|186||[[Help:VE186|&amp;quot;Material &#039;$(MATERIAL)&#039; is shared between multiple chunks in this asset but the material parameters conflict.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|187||[[Help:VE187|&amp;quot;The value &#039;$(VALUE)&#039; in not a valid KUID.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|188||[[Help:VE188|&amp;quot;Custom render plugin failed to load mesh &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|189||[[Help:VE189|&amp;quot;Collision data exceeds $(LIMIT)KB. Please specify a different generation method or a simplified mesh.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|190||[[Help:VE190|&amp;quot;Tag &#039;$(NAME)&#039; is unable to be converted from $(TYPE1) to $(TYPE2)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|191||[[Help:VE191|&amp;quot;Tag &#039;$(NAME)&#039; does not contain a valid integer: $(VALUE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|192||[[Help:VE192|&amp;quot;Tag &#039;$(NAME)&#039; does not contain a valid float list: $(VALUE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|193||[[Help:VE193|&amp;quot;Tag &#039;$(NAME)&#039; does not contain a valid float&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|194||[[Help:VE194|&amp;quot;Tag &#039;$(NAME)&#039; does not contain a valid kuid: $(VALUE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|195||[[Help:VE195|&amp;quot;Unable to parse chunk $(CHUNK_INDEX) in mesh file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|196||[[Help:VE196|&amp;quot;Failed to load bogey $(KUID)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|197||[[Help:VE197|&amp;quot;Syntax error in script &#039;$(SCRIPT)&#039; for asset $(ASSET)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|198||[[Help:VE198|&amp;quot;Session failed to load route asset: $(KUID)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|199||[[Help:VE199|&amp;quot;Asset $(KUID) failed to load. Unloading resources.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|200||[[Help:VE200|&amp;quot;Unable to load mesh $(NAME) for $(ASSET_ID)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|201||[[Help:VE201|&amp;quot;Traincar is missing required attachment point: $(ATT_NAME)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|202||[[Help:VE202|&amp;quot;Parse error reading twinkles file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|203||[[Help:VE203|&amp;quot;Bad sequence order in $(TAG_NAME) list. Each element must be greater than the last.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|204||[[Help:VE204|&amp;quot;Invalid range in $(TAG_NAME) list. Elements must be greater than or equal to $(INC_MIN) and less than $(EXC_MAX).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|205||[[Help:VE205|&amp;quot;Invalid element count in $(TAG_NAME) list. This list must have at least $(COUNT) elements (to match the $(TAG_START) list).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|206||[[Help:VE206|&amp;quot;The season-selector references season &#039;$(SEASON)&#039;, but this does not exist in the texture-variants container.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|207||[[Help:VE207|&amp;quot;Attached track asset $(CHILD) failed to load.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|208||[[Help:VE208|&amp;quot;Attached track asset not specified for track $(INDEX).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|209||[[Help:VE209|&amp;quot;Asset is missing the required &#039;attached-track&#039; container.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|210||[[Help:VE210|&amp;quot;Asset is missing the required &#039;track&#039; tag.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|211||[[Help:VE211|&amp;quot;Asset is missing the required &#039;road&#039; tag.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|212||[[Help:VE212|&amp;quot;Traincar asset must have at least two bogeys.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|213||[[Help:VE213|&amp;quot;Traincar asset has invalid bogey placement.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|214||[[Help:VE214|&amp;quot;Traincar asset has invalid length.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|215||[[Help:VE215|&amp;quot;Asset has an invalid number of LODs: $(LOD_COUNT)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|216||[[Help:VE216|&amp;quot;Material $(MATERIAL) in mesh file $(MESH) has an inappropriate texture slot assigned: $(TEXTURE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|217||[[Help:VE217|&amp;quot;Material $(MATERIAL) in mesh file $(MESH) has no texture assigned to a required slot: $(TEXTURE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|218||[[Help:VE218|&amp;quot;Asset has duplicate attached track at track $(INDEX).&amp;quot;]]&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=Category:Validation_Errors&amp;diff=16562</id>
		<title>Category:Validation Errors</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=Category:Validation_Errors&amp;diff=16562"/>
		<updated>2018-10-16T02:13:16Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Validation Error (VE) numbers are logged during content validation, to allow users to look up particular validation messages to better understand the source of the problem. Normal logs provide a substantial amount of technical detail about the error, but typically assume that the reader is familiar with the subject matter and will understand why the log is relevant. This wiki provides the necessary background information to understanding many of the logs, however a user who is unfamiliar with the area in question may not know where to start looking. VE numbers allow users to quickly find relevant pages in the wiki without any prior knowledge of the subject.&lt;br /&gt;
&lt;br /&gt;
This page serves as a master guide to all VE numbers currently logged by Trainz. This page does not provide detailed information on any given VE number- please refer to the individual VE number pages for specific details. The error text here is correct for the English localisation of Trainz at the time of writing, however the exact text may change from time to time. It is intended that the overall meaning of a VE number will never change- new VE numbers will be issued instead, and old VE numbers may be made obsolete.&lt;br /&gt;
&lt;br /&gt;
Logs which lack VE numbers do not belong on this page.&lt;br /&gt;
&lt;br /&gt;
The individual VE pages can be found at the links below, or can be accessed directly from [[Content Manager]] by right-clicking on the Validation Error in the results log, and selecting &amp;quot;View Help for This Message&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|1||[[Help:VE1|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Decimal value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|2||[[Help:VE2|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Integer value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|3||[[Help:VE3|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|4||[[Help:VE4|&amp;quot;&#039;$(TAG_NAME)&#039; must have a positive value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|5||[[Help:VE5|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|6||[[Help:VE6|&amp;quot;&#039;$(TAG_NAME)&#039; must not be zero.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|7||[[Help:VE7|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|8||[[Help:VE8|&amp;quot;The value for &#039;$(TAG_NAME)&#039; must be between &#039;$(MIN)&#039; and &#039;$(MAX)&#039; but was specified as &#039;$(VALUE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|9||[[Help:VE9|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|10||[[Help:VE10|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|11||[[Help:VE11|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|12||[[Help:VE12|&amp;quot;No string-table entry found with tag &#039;$(VALUE)&#039; for for string-token tag &#039;$(TAG)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|13||[[Help:VE13|&amp;quot;Missing or invalid selection for tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|14||[[Help:VE14|&amp;quot;Missing or invalid selection for tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|15||[[Help:VE15|&amp;quot;Attachment point &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must be found in mesh &#039;$(MESH_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|16||[[Help:VE16|&amp;quot;Container &#039;$(CONT_NAME)&#039; does not have an &#039;att-parent&#039; tag which is required to reference an attachment point.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|17||[[Help:VE17|&amp;quot;Attachment point &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must be found in mesh &#039;$(MESH_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|18||[[Help:VE18|&amp;quot;Attachment point &#039;$(TAG_VAL)&#039; referenced by tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; was not found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|19||[[Help:VE19|&amp;quot;Effect &#039;$(EFFECT_NAME)&#039; in &#039;$(CONT_NAME)&#039; was not found within the mesh table.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|20||[[Help:VE20|&amp;quot;Mesh &#039;$(MESH_NAME)&#039; referenced in &#039;$(CONT_NAME)&#039; was not found within the mesh table.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|21||[[Help:VE21|&amp;quot;Attachment point &#039;$(TAG_VAL)&#039; referenced by tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; was not found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|22||[[Help:VE22|&amp;quot;Missing or invalid selection for tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|23||[[Help:VE23|&amp;quot;Invalid tag name &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|24||[[Help:VE24|&amp;quot;Invalid tag name &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|25||[[Help:VE25|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|26||[[Help:VE26|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|27||[[Help:VE27|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must have a mesh file extension.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|28||[[Help:VE28|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must have an image file extension.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|29||[[Help:VE29|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must have an animation file extension.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|30||[[Help:VE30|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; refers to a nonexistent file: &#039;$(FILENAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|31||[[Help:VE31|&amp;quot;Invalid tag name &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|32||[[Help:VE32|&amp;quot;Alias mesh requires valid parent asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|33||[[Help:VE33|&amp;quot;Alias mesh &#039;$(FILE)&#039; not found in dependency $(KUID).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|34||[[Help:VE34|&amp;quot;Alias mesh &#039;$(FILE)&#039; not found in latest version ($(NEW_KUID)) of dependency $(OLD_KUID).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|35||[[Help:VE35|&amp;quot;Required alias mesh asset $(KUID) is missing and cannot be validated.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|36||[[Help:VE36|&amp;quot;The texture &#039;$(FILE)&#039; failed to load.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|37||[[Help:VE37|&amp;quot;The texture &#039;$(FILE)&#039; is not a power of 2, please resize it.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|38||[[Help:VE38|&amp;quot;The texture &#039;$(FILE)&#039; is not square. Cubemap textures need to have the same width and height.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|39||[[Help:VE39|&amp;quot;The texture &#039;$(FILE)&#039; is a uniform color.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|40||[[Help:VE40|&amp;quot;Unable to load $(TYPE) texture &#039;$(TEXTURE)&#039; for texture file &#039;$(FILE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|41||[[Help:VE41|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Integer value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|42||[[Help:VE42|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Decimal value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|43||[[Help:VE43|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Boolean value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|44||[[Help:VE44|&amp;quot;Tag &#039;$(TAG_NAME)&#039; in the container &#039;$(CONT_NAME)&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|45||[[Help:VE45|&amp;quot;The Tag &#039;$(TAG_NAME)&#039; is not permitted within a container of type &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|46||[[Help:VE46|&amp;quot;Internal Error: The template does not specify that a smoke container is valid in the container being parsed.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|47||[[Help:VE47|&amp;quot;Container &#039;$(CONT_NAME)&#039; is not permitted in this section.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|48||[[Help:VE48|&amp;quot;This asset uses an obsolete trainz-build number. Trainz-build numbers below $(LOWEST_TRAINZBUILD) are no longer supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|49||[[Help:VE49|&amp;quot;Required tag &#039;kind&#039; is not present. Ensure this is a valid config file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|50||[[Help:VE50|&amp;quot;Unsupported kind &#039;$(KIND)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|51||[[Help:VE51|&amp;quot;Tag &#039;$(TAG_NAME)&#039; in the container &#039;$(CONT_NAME)&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|52||[[Help:VE52|&amp;quot;The Tag &#039;$(TAG_NAME)&#039; is not permitted within a container of type &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|53||[[Help:VE53|&amp;quot;This container is no longer supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|54||[[Help:VE54|&amp;quot;The Tag &#039;$(TAG_NAME)&#039; is not permitted within a container of type &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|55||[[Help:VE55|&amp;quot;This container is no longer supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|56||[[Help:VE56|&amp;quot;Container &#039;$(CONT_NAME)&#039; is not permitted in this section.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|57||[[Help:VE57|&amp;quot;Container &#039;$(CONT_NAME)&#039; is not permitted in this section.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|58||[[Help:VE58|&amp;quot;The tag &#039;$(TAG_NAME)&#039; is not a valid container type (expected &#039;$(TYPE)&#039;).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|59||[[Help:VE59|&amp;quot;Internal error: unknown dataType - kind &#039;$(KIND)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|60||[[Help:VE60|&amp;quot;Required tag &#039;$(TAG_NAME)&#039; was missing and has been set to default.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|61||[[Help:VE61|&amp;quot;Required tag &#039;$(TAG_NAME)&#039; was missing and has been set to default.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|62||[[Help:VE62|&amp;quot;Required container &#039;$(CONT_NAME)&#039; is missing.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|63||[[Help:VE63|&amp;quot;The cubemap texture &#039;$(FILE)&#039; has missing images. Please verify the texture.txt file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|64||[[Help:VE64|&amp;quot;Cubemap texture &#039;$(FILE)&#039; contains images of different sizes.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|65||[[Help:VE65|&amp;quot;The *.texture.txt file is missing for texture resource &#039;$(FILE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|66||[[Help:VE66|&amp;quot;The texture file &#039;$(FILE)&#039; contains non-ANSI characters. Textures must be ANSI.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|67||[[Help:VE67|&amp;quot;The texture &#039;$(FILE)&#039; does not seem to have a primary texture set. Please verify the texture.txt file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|68||[[Help:VE68|&amp;quot;The primary and alpha texture are not the same size for &#039;$(FILE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|69||[[Help:VE69|&amp;quot;Binary conversion failed for texture resource &#039;$(FILE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|70||[[Help:VE70|&amp;quot;The KUID tag is not a valid KUID value: &#039;$(string)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|71||[[Help:VE71|&amp;quot;Unsupported SpeedTree version for mesh: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|72||[[Help:VE72|&amp;quot;Unable to load mesh file: &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|73||[[Help:VE73|&amp;quot;Image file &#039;$(FILE)&#039; is incorrectly used as both a texture.txt source file and a raw image file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|74||[[Help:VE74|&amp;quot;Image file &#039;$(FILE)&#039; is incorrectly used as both a texture.txt source file and a raw image file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|76||[[Help:VE76|&amp;quot;Unable to load mesh file: &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|77||[[Help:VE77|&amp;quot;Unable to load indexed mesh &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|79||[[Help:VE79|&amp;quot;Unable to load animation file &#039;$(FILE)&#039; (mesh has not been loaded correctly).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|81||[[Help:VE81|&amp;quot;The high-poly mesh &#039;$(FILE)&#039; should have LOD levels.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|82||[[Help:VE82|&amp;quot;High-detail .im files are not supported for traincar assets, as they are likely to perform poorly. It is recommended that you upgrade &#039;$(FILE)&#039; to a .lm file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|83||[[Help:VE83|&amp;quot;The file &#039;$(FILE)&#039; is provided in LM format despite having no attachment points and no animation support. This may have a negative impact on performance.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|84||[[Help:VE84|&amp;quot;The file &#039;$(FILE)&#039; is provided in LM format despite containing only a single mesh. This may have a negative impact on performance.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|85||[[Help:VE85|&amp;quot;The file &#039;$(FILE)&#039; is provided in LM format, however the high-detail mesh is comprised of less than 300 polygons. This may have a negative impact on performance.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|86||[[Help:VE86|&amp;quot;Legacy .pm files are no longer supported, and will perform poorly. It is recommended that you switch to using a .lm file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|87||[[Help:VE87|&amp;quot;Legacy .pm files are no longer supported, and will perform poorly. It is recommended that you switch to using a .lm file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|88||[[Help:VE88|&amp;quot;This asset has a trainz-build number which is not recognised by this tool.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|89||[[Help:VE89|&amp;quot;Tag &#039;$(TAG_NAME)&#039; in the container &#039;$(CONT_NAME)&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|90||[[Help:VE90|&amp;quot;This asset has an invalid KUID user id&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|91||[[Help:VE91|&amp;quot;The dependency $(KUID) has an invalid KUID User ID and cannot be used&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|92||[[Help:VE92|&amp;quot;Duplicate &#039;$(TAG_NAME)&#039; containers in &#039;$(CONT_NAME)&#039;. Containers must have a unique name.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|93||[[Help:VE93|&amp;quot;Duplicate &#039;$(TAG_NAME)&#039; tags in &#039;$(CONT_NAME)&#039;. Tags must have a unique name.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|94||[[Help:VE94|&amp;quot;This asset requires a shadow mesh, but the mesh table does not contain one.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|95||[[Help:VE95|&amp;quot;This asset does not have a mesh that is visible by default.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|96||[[Help:VE96|&amp;quot;Maximum of 5 running number fonts supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|97||[[Help:VE97|&amp;quot;The running number font directory &#039;$(DIR)&#039; could not be found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|98||[[Help:VE98|&amp;quot;The running number font file &#039;$(DIR)/$(FILE)&#039; could not be found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|99||[[Help:VE99|&amp;quot;The track-sound container &#039;$(NAME)&#039; has no bogey, track or track-parent tag.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|100||[[Help:VE100|&amp;quot;Required tag &#039;$(TAG_NAME)&#039; was missing and has been set to default.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|101||[[Help:VE101|&amp;quot;The file &#039;$(FILE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|102||[[Help:VE102|&amp;quot;Failed to load sound file &#039;$(FILE)&#039;, please ensure this is a valid wav file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|103||[[Help:VE103|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|104||[[Help:VE104|&amp;quot;Multiple template property bindings for rule property &#039;$(PROP)&#039; for rule &#039;$(RULE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|105||[[Help:VE105|&amp;quot;The template property &#039;$(NAME)&#039; specified in the rule-template-bindings container of rule &#039;$(RULE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|106||[[Help:VE106|&amp;quot;The high-detail meshes in season $(SEASON) total more than $(LIMIT) polygons. This may have a negative impact on performance: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|107||[[Help:VE107|&amp;quot;The high-detail meshes total more than $(LIMIT) polygons. This may have a negative impact on performance: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|108||[[Help:VE108|&amp;quot;The low-detail meshes in season $(SEASON) total more than 500 polygons. This may have a negative impact on performance: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|109||[[Help:VE109|&amp;quot;The low-detail meshes total more than 500 polygons. This may have a negative impact on performance: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|110||[[Help:VE110|&amp;quot;The meshes in LOD level $(LOD_LEVEL) in season $(SEASON) must total at least 20% fewer polygons than the next higher LOD in the same season: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|111||[[Help:VE111|&amp;quot;The meshes in LOD level $(LOD_LEVEL) must total at least 20% fewer polygons than the next higher LOD: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|112||[[Help:VE112|&amp;quot;Multiple track stretches between &#039;$(FROM_VERTEX)&#039; and &#039;$(TO_VERTEX)&#039; in container &#039;$(CONT_NAME)&#039;. Track stretches must be unique.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|113||[[Help:VE113|&amp;quot;An image file (&#039;$(FILE)&#039;) has been supplied where a texture file (&#039;*.texture.txt&#039;) is required.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|114||[[Help:VE114|&amp;quot;An image file (&#039;$(FILE)&#039;) has been supplied where a texture file (&#039;*.texture.txt&#039;) is required.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|115||[[Help:VE115|&amp;quot;The texture file &#039;$(FILE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|116||[[Help:VE116|&amp;quot;No texture file has been specified for this texture asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|117||[[Help:VE117|&amp;quot;&#039;$(TAG_0)&#039; must be set to a &#039;$(KIND)&#039; for &#039;$(TAG_1)&#039; to be allowed.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|118||[[Help:VE118|&amp;quot;Tag &#039;$(TAG_0)&#039; requires that &#039;$(TAG_1)&#039; be set to &#039;$(KIND)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|119||[[Help:VE119|&amp;quot;The tag &#039;$(TAG_NAME)&#039; is not valid for kind &#039;$(KIND)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|120||[[Help:VE120|&amp;quot;Tag &#039;$(TAG_0)&#039;, requires the tag &#039;$(TAG_1)&#039; to be present.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|121||[[Help:VE121|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|122||[[Help:VE122|&amp;quot;&#039;$(TAG_NAME)&#039; must have a positive value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|123||[[Help:VE123|&amp;quot;The script file &#039;$(FILE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|124||[[Help:VE124|&amp;quot;The file &#039;$(FILE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|125||[[Help:VE125|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|126||[[Help:VE126|&amp;quot;&#039;$(TAG_NAME)&#039; must not be zero.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|127||[[Help:VE127|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|128||[[Help:VE128|&amp;quot;The value for &#039;$(TAG_NAME)&#039; must be between &#039;$(MIN)&#039; and &#039;$(MAX)&#039; but was specified as &#039;$(VALUE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|129||[[Help:VE129|&amp;quot;Incorrect number of values for the tag &#039;$(TAG_NAME)&#039;, expected $(NUM_0) values, found $(NUM_1).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|130||[[Help:VE130|&amp;quot;Too many values for the tag &#039;$(TAG_NAME)&#039;, maximum is $(MAX) values, found $(FOUND).&amp;quot;]]]]&lt;br /&gt;
|-&lt;br /&gt;
|131||[[Help:VE131|&amp;quot;Value must be a mesh from the mesh-table (not a parent container).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|132||[[Help:VE132|&amp;quot;The attachment point &#039;$(ATT)&#039; must belong to the parent mesh of the effect (mesh=$(MESH)).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|133||[[Help:VE133|&amp;quot;A light container must be present to link the signals.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|134||[[Help:VE134|&amp;quot;&#039;$(NUM)&#039; must be a valid light number from the light container.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|135||[[Help:VE135|&amp;quot;&#039;$(TAG_0)&#039; requires that the tag &#039;$(TAG_1)&#039; be present.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|136||[[Help:VE136|&amp;quot;&#039;$(TAG_0)&#039; requires that the tag &#039;$(TAG_1)&#039; be present.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|137||[[Help:VE137|&amp;quot;Empty or invalid running number specified at character index $(INDEX)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|138||[[Help:VE138|&amp;quot;Running number specified at character index $(INDEX) is too large, must be less than 9 characters.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|139||[[Help:VE139|&amp;quot;Invalid running number range specified at character index $(INDEX), ($(FROM)-$(TO)).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|140||[[Help:VE140|&amp;quot;Running number range &#039;$(FROM)-$(TO)&#039; specified at character index $(INDEX) overlaps already in use numbers, running numbers must be unique.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|141||[[Help:VE141|&amp;quot;Running number &#039;$(NUMBER)&#039; specified at character index $(INDEX) is already in use.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|142||[[Help:VE142|&amp;quot;Invalid character &#039;$(CHAR)&#039; specified in running number list, only numbers, &#039;,&#039; and &#039;-&#039; are supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|143||[[Help:VE143|&amp;quot;Possible running number list is too large, the set must contain less than 20000 possibilities.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|144||[[Help:VE144|&amp;quot;Category code &#039;ZX - Paintshed template&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|145||[[Help:VE145|&amp;quot;Category code &#039;ZX - Paintshed template&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|146||[[Help:VE146|&amp;quot;An asset must be specified for tag &#039;$(TAG_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|147||[[Help:VE147|&amp;quot;The tag(s) $(MISPLACED_TAGS) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|148||[[Help:VE148|&amp;quot;The tag(s) $(MISPLACED_TAGS) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|149||[[Help:VE149|&amp;quot;The mesh(es) $(MISPLACED_MESHES) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|150||[[Help:VE150|&amp;quot;The mesh(es) $(MISPLACED_MESHES) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|151||[[Help:VE150|&amp;quot;The mesh(es) $(MISPLACED_MESHES) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|152||[[Help:VE152|&amp;quot;The tags $(MISSING_TAGS) are not all defined. The default values will be used and the positions of the elements may not fit your track.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|153||[[Help:VE153|&amp;quot;The mesh $(MESH) is present but the tag $(MISSING_TAG) is not defined.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|154||[[Help:VE154|&amp;quot;The mesh $(MESH) is present but the tag $(MISSING_TAG) is not defined.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|155||[[Help:VE155|&amp;quot;The mesh $(MESH) is present but the tags $(MISSING_TAGS) are not all defined.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|156||[[Help:VE156|&amp;quot;The tag $(MISSING_TAG) is not defined. The default value will be used and the positions of the elements may not fit your track.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|157||[[Help:VE157|&amp;quot;The mesh $(MESH) is present but the tag $(MISSING_TAG) is missing. The default value will be used and the positions of the elements may not fit your track.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|158||[[Help:VE158|&amp;quot;Unable to open .lm.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|159||[[Help:VE159|&amp;quot;Unable to parse .lm.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|160||[[Help:VE160|&amp;quot;No &#039;mesh&#039; keys found in .lm.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|161||[[Help:VE161|&amp;quot;$(LODCOUNT) LODs in .lm.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|162||[[Help:VE162|&amp;quot;One of the LOD reductions of &#039;$(FILE)&#039; introduces a new attachment point: $(ATT)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|163||[[Help:VE163|&amp;quot;Unable to parse .im file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|164||[[Help:VE164|&amp;quot;Invalid position data in .im file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|165||[[Help:VE165|&amp;quot;Texture &#039;$(TEXTURE)&#039; is missing or could not be loaded in mesh &#039;$(FILE)&#039;, material &#039;$(MATERIAL)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|166||[[Help:VE166|&amp;quot;$(COMBINEDCOUNT) combined chunks (of $(SOURCECOUNT) source) in .im file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|167||[[Help:VE167|&amp;quot;Source image texture file &#039;$(TEXTUREFILE)&#039; is too large for &#039;$(ASSETFILE)&#039; ($(WIDTH)x$(HEIGHT))&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|168||[[Help:VE168|&amp;quot;File &#039;$(TEXTUREFILE)&#039; is not a valid compiled texture file for &#039;$(ASSETFILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|169||[[Help:VE169|&amp;quot;Compiled texture file &#039;$(TEXTUREFILE)&#039; is unsupported version for &#039;$(ASSETFILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|170||[[Help:VE170|&amp;quot;Failed to open compiled texture &#039;$(TEXTUREFILE)&#039; for &#039;$(ASSETFILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|171||[[Help:VE171|&amp;quot;Expected texture file type but found &#039;$(TEXTUREFILE)&#039; for &#039;$(ASSETFILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|172||[[Help:VE172|&amp;quot;Script class does not match asset kind ($(KIND)).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|173||[[Help:VE173|&amp;quot;Material &#039;$(MATERIAL)&#039; in mesh &#039;$(FILE)&#039; is not of a recognised material type.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|174||[[Help:VE174|&amp;quot;MeshObjectSpec::LinkSpecs&amp;gt; Mesh-table element #$(MESH_INDEX) parent mesh is invalid.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|175||[[Help:VE175|&amp;quot;MeshObjectSpec::LinkSpecs&amp;gt; Mesh-table element #$(MESH_INDEX) is part of invalid hierarchy.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|176||[[Help:VE176|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must have a texture file extension.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|177||[[Help:VE177|&amp;quot;The kuid &#039;$(KUID)&#039; is not in the database, and could not be found in any known location. Ensure that this is a valid asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|178||[[Help:VE178|&amp;quot;The asset specified in &#039;$(KUID)&#039; is not installed locally but is available for download.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|179||[[Help:VE179|&amp;quot;The kuid &#039;$(KUID)&#039; specified in &#039;$(TAG_NAME)&#039; is not of the correct type.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|180||[[Help:VE180|&amp;quot;Integrity check failure on $(FILE). One or more route/session tiles may be missing.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|181||[[Help:VE181|&amp;quot;The tag &#039;$(TAG_NAME)&#039; requires a minimum asset version of $(MIN_VERSION)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|182||[[Help:VE182|&amp;quot;Material &#039;$(MATERIAL)&#039; in mesh &#039;$(FILE)&#039; is missing a texture for a mandatory texture slot.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|183||[[Help:VE183|&amp;quot;FBX file is in an unsupported older format.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|184||[[Help:VE184|&amp;quot;KIND &#039;$(KIND)&#039; requires trainz-build $(TRAINZBUILD).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|185||[[Help:VE185|&amp;quot;Material &#039;$(MATERIAL)&#039; in mesh &#039;$(FILE)&#039; has heightmap texture. Provide a normal map instead.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|186||[[Help:VE186|&amp;quot;Material &#039;$(MATERIAL)&#039; is shared between multiple chunks in this asset but the material parameters conflict.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|187||[[Help:VE187|&amp;quot;The value &#039;$(VALUE)&#039; in not a valid KUID.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|188||[[Help:VE188|&amp;quot;Custom render plugin failed to load mesh &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|189||[[Help:VE189|&amp;quot;Collision data exceeds $(LIMIT)KB. Please specify a different generation method or a simplified mesh.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|190||[[Help:VE190|&amp;quot;Tag &#039;$(NAME)&#039; is unable to be converted from $(TYPE1) to $(TYPE2)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|191||[[Help:VE191|&amp;quot;Tag &#039;$(NAME)&#039; does not contain a valid integer: $(VALUE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|192||[[Help:VE192|&amp;quot;Tag &#039;$(NAME)&#039; does not contain a valid float list: $(VALUE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|193||[[Help:VE193|&amp;quot;Tag &#039;$(NAME)&#039; does not contain a valid float&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|194||[[Help:VE194|&amp;quot;Tag &#039;$(NAME)&#039; does not contain a valid kuid: $(VALUE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|195||[[Help:VE195|&amp;quot;Unable to parse chunk $(CHUNK_INDEX) in mesh file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|196||[[Help:VE196|&amp;quot;Failed to load bogey $(KUID)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|197||[[Help:VE197|&amp;quot;Syntax error in script &#039;$(SCRIPT)&#039; for asset $(ASSET)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|198||[[Help:VE198|&amp;quot;Session failed to load route asset: $(KUID)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|199||[[Help:VE199|&amp;quot;Asset $(KUID) failed to load. Unloading resources.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|200||[[Help:VE200|&amp;quot;Unable to load mesh $(NAME) for $(ASSET_ID)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|201||[[Help:VE201|&amp;quot;Traincar is missing required attachment point: $(ATT_NAME)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|202||[[Help:VE202|&amp;quot;Parse error reading twinkles file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|203||[[Help:VE203|&amp;quot;Bad sequence order in $(TAG_NAME) list. Each element must be greater than the last.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|204||[[Help:VE204|&amp;quot;Invalid range in $(TAG_NAME) list. Elements must be greater than or equal to $(INC_MIN) and less than $(EXC_MAX).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|205||[[Help:VE205|&amp;quot;Invalid element count in $(TAG_NAME) list. This list must have at least $(COUNT) elements (to match the $(TAG_START) list).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|206||[[Help:VE206|&amp;quot;The season-selector references season &#039;$(SEASON)&#039;, but this does not exist in the texture-variants container.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|207||[[Help:VE207|&amp;quot;Attached track asset $(CHILD) failed to load.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|208||[[Help:VE208|&amp;quot;Attached track asset not specified for track $(INDEX).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|209||[[Help:VE209|&amp;quot;Asset is missing the required &#039;attached-track&#039; container.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|210||[[Help:VE210|&amp;quot;Asset is missing the required &#039;track&#039; tag.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|211||[[Help:VE211|&amp;quot;Asset is missing the required &#039;road&#039; tag.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|212||[[Help:VE212|&amp;quot;Traincar asset must have at least two bogeys.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|213||[[Help:VE213|&amp;quot;Traincar asset has invalid bogey placement.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|214||[[Help:VE214|&amp;quot;Traincar asset has invalid length.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|215||[[Help:VE215|&amp;quot;Asset has an invalid number of LODs: $(LOD_COUNT)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|216||[[Help:VE216|&amp;quot;Material $(MATERIAL) in mesh file $(MESH) has an inappropriate texture slot assigned: $(TEXTURE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|217||[[Help:VE217|&amp;quot;Material $(MATERIAL) in mesh file $(MESH) has no texture assigned to a required slot: $(TEXTURE)&amp;quot;]]&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=%22trainz-build%22_number&amp;diff=16392</id>
		<title>&quot;trainz-build&quot; number</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=%22trainz-build%22_number&amp;diff=16392"/>
		<updated>2018-09-04T03:12:58Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;New releases of Trainz bring new features and improved content validation techniques. This will happen for major product editions (eg. [[TS2010]], [[TS12]] and [[TANE]]) but may also occur during the larger service packs which are released for each product. The [[&amp;quot;Trainz-build&amp;quot; number]] is used to differentiate these compatibility versions, and the corresponding [[&amp;quot;Trainz-build&amp;quot; tag]] is used in each asset&#039;s [[Config.txt file]] to specify the minimum Trainz version required in order to use the asset.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=2 cellpadding=5 cellspacing=2 &lt;br /&gt;
|-&lt;br /&gt;
! colspan=2|Trainz-Build version numbers and their mapping to official Trainz release versions are as follows: &lt;br /&gt;
|-&lt;br /&gt;
!&#039;trainz-build&#039; || Trainz product for which the asset was designed&lt;br /&gt;
|-&lt;br /&gt;
| {{center|1.3 }} || [[Trainz SP3|Trainz SP3]]&lt;br /&gt;
|-&lt;br /&gt;
| {{center|1.5 }} || Ultimate Trainz Collection&lt;br /&gt;
|-&lt;br /&gt;
| {{center|1.6 }} || Ultimate Trainz Collection SP1&lt;br /&gt;
|-&lt;br /&gt;
| {{center|2.0 }} || [[TRS2004]]&lt;br /&gt;
|-&lt;br /&gt;
| {{center|2.1 }} || [[TRS2004]] SP1&lt;br /&gt;
|-&lt;br /&gt;
| {{center|2.2 }} || [[TRS2004]] SP2 - Passenger Pack&lt;br /&gt;
|-&lt;br /&gt;
| {{center|2.3 }} || [[TRS2004]] SP3&lt;br /&gt;
|-&lt;br /&gt;
| {{center|2.4 }} || [[TRS2004]] SP4&lt;br /&gt;
|-&lt;br /&gt;
| {{center|2.5 }} || [[TRS2006]]&lt;br /&gt;
|-&lt;br /&gt;
| {{center|2.6 }} || [[TRS2006]] SP1&lt;br /&gt;
|-&lt;br /&gt;
| {{center|2.7 }} || Trainz Classics 1&amp;amp;2&lt;br /&gt;
|-&lt;br /&gt;
| {{center|2.8 }} || Trainz Classics 3&lt;br /&gt;
|-&lt;br /&gt;
| {{center|2.9 }} || [[TS2009]]&lt;br /&gt;
|-&lt;br /&gt;
| {{center|3.0 }} || [[TS2009 SP1]]&lt;br /&gt;
|-&lt;br /&gt;
| {{center|3.1 }} || [[TS2009 SP2]] / [[TS2009 SP3]]&lt;br /&gt;
|-&lt;br /&gt;
| {{center|3.2 }} || [[TS2010]] / [[TS2010 SP1]]&lt;br /&gt;
|-&lt;br /&gt;
| {{center|3.3 }} || [[TS2010 SP2]] / [[TS2010 SP3]] / [[TS2009 SP4]]&lt;br /&gt;
|-&lt;br /&gt;
| {{center|3.4 }} || [[TS2010 SP4]]&lt;br /&gt;
|-&lt;br /&gt;
| {{center|3.5 }} || [[TS12]]&lt;br /&gt;
|-&lt;br /&gt;
| {{center|3.6 }} || [[TS12]] and [[Trainz Simulator Mac]]&lt;br /&gt;
|-&lt;br /&gt;
| {{center|3.7 }} || [[TS12 SP1]]&lt;br /&gt;
|-&lt;br /&gt;
| {{center|3.8 }} || [[Trainz Simulator 2]] (Mac)&lt;br /&gt;
|-&lt;br /&gt;
| {{center|3.9 }} || [[Trainz A New Era: Community Edition]] 1.0&lt;br /&gt;
|-&lt;br /&gt;
| {{center|4.0 }} || [[Trainz A New Era: Community Edition]] 1.1&lt;br /&gt;
|-&lt;br /&gt;
| {{center|4.1 }} || [[Trainz A New Era: Community Edition]] 1.2&lt;br /&gt;
|-&lt;br /&gt;
| {{center|4.2 }} || [[Trainz A New Era]]&lt;br /&gt;
|-&lt;br /&gt;
| {{center|4.3 }} || [[Trainz A New Era]] SP1&lt;br /&gt;
|-&lt;br /&gt;
| {{center|4.4 }} || [[Trainz Model Railways TMR2017]]&lt;br /&gt;
|-&lt;br /&gt;
| {{center|4.5 }} || [[Trainz A New Era]] SP2 / SP3&lt;br /&gt;
|-&lt;br /&gt;
| {{center|4.6 }} || [[TRS19]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Obsolete Versions==&lt;br /&gt;
&lt;br /&gt;
The [[Trainz Life-Cycle Policy]] defines which product releases have active support from [[N3V Games]]. While users may continue to use older products, including downloading such older content from the [[Download Station]] and even creating new content for these older versions, it is typically not possible to upload content with an unsupported [[&amp;quot;Trainz-build&amp;quot; number]] to the [[Download Station]]. This ensures that older content-creation techniques are slowly phased out over time in favour of the more recent improvements.&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=Help:VE215&amp;diff=13777</id>
		<title>Help:VE215</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=Help:VE215&amp;diff=13777"/>
		<updated>2018-06-25T08:35:30Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: Created page with &amp;quot;&amp;#039;&amp;#039;&amp;#039;Asset has an invalid number of LODs: $(LOD_COUNT)&amp;#039;&amp;#039;&amp;#039;  This error results when a mesh-table-based asset has an improper number of LODs. Generally speaking, only a small ...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Asset has an invalid number of LODs: $(LOD_COUNT)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This error results when a [[mesh-table]]-based asset has an improper number of LODs. Generally speaking, only a small number of LODs (eg. 2-4) is necessary for any given asset, and performance grows worse as the number of LODs increases. Numbers heavily in excess of this range are considered faults.&lt;br /&gt;
&lt;br /&gt;
[[Category:Validation Errors]]&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=Category:Validation_Errors&amp;diff=13776</id>
		<title>Category:Validation Errors</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=Category:Validation_Errors&amp;diff=13776"/>
		<updated>2018-06-25T08:32:51Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Validation Error (VE) numbers are logged during content validation, to allow users to look up particular validation messages to better understand the source of the problem. Normal logs provide a substantial amount of technical detail about the error, but typically assume that the reader is familiar with the subject matter and will understand why the log is relevant. This wiki provides the necessary background information to understanding many of the logs, however a user who is unfamiliar with the area in question may not know where to start looking. VE numbers allow users to quickly find relevant pages in the wiki without any prior knowledge of the subject.&lt;br /&gt;
&lt;br /&gt;
This page serves as a master guide to all VE numbers currently logged by Trainz. This page does not provide detailed information on any given VE number- please refer to the individual VE number pages for specific details. The error text here is correct for the English localisation of Trainz at the time of writing, however the exact text may change from time to time. It is intended that the overall meaning of a VE number will never change- new VE numbers will be issued instead, and old VE numbers may be made obsolete.&lt;br /&gt;
&lt;br /&gt;
Logs which lack VE numbers do not belong on this page.&lt;br /&gt;
&lt;br /&gt;
The individual VE pages can be found at the links below, or can be accessed directly from [[Content Manager]] by right-clicking on the Validation Error in the results log, and selecting &amp;quot;View Help for This Message&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|1||[[Help:VE1|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Decimal value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|2||[[Help:VE2|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Integer value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|3||[[Help:VE3|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|4||[[Help:VE4|&amp;quot;&#039;$(TAG_NAME)&#039; must have a positive value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|5||[[Help:VE5|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|6||[[Help:VE6|&amp;quot;&#039;$(TAG_NAME)&#039; must not be zero.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|7||[[Help:VE7|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|8||[[Help:VE8|&amp;quot;The value for &#039;$(TAG_NAME)&#039; must be between &#039;$(MIN)&#039; and &#039;$(MAX)&#039; but was specified as &#039;$(VALUE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|9||[[Help:VE9|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|10||[[Help:VE10|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|11||[[Help:VE11|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|12||[[Help:VE12|&amp;quot;No string-table entry found with tag &#039;$(VALUE)&#039; for for string-token tag &#039;$(TAG)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|13||[[Help:VE13|&amp;quot;Missing or invalid selection for tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|14||[[Help:VE14|&amp;quot;Missing or invalid selection for tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|15||[[Help:VE15|&amp;quot;Attachment point &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must be found in mesh &#039;$(MESH_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|16||[[Help:VE16|&amp;quot;Container &#039;$(CONT_NAME)&#039; does not have an &#039;att-parent&#039; tag which is required to reference an attachment point.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|17||[[Help:VE17|&amp;quot;Attachment point &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must be found in mesh &#039;$(MESH_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|18||[[Help:VE18|&amp;quot;Attachment point &#039;$(TAG_VAL)&#039; referenced by tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; was not found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|19||[[Help:VE19|&amp;quot;Effect &#039;$(EFFECT_NAME)&#039; in &#039;$(CONT_NAME)&#039; was not found within the mesh table.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|20||[[Help:VE20|&amp;quot;Mesh &#039;$(MESH_NAME)&#039; referenced in &#039;$(CONT_NAME)&#039; was not found within the mesh table.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|21||[[Help:VE21|&amp;quot;Attachment point &#039;$(TAG_VAL)&#039; referenced by tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; was not found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|22||[[Help:VE22|&amp;quot;Missing or invalid selection for tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|23||[[Help:VE23|&amp;quot;Invalid tag name &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|24||[[Help:VE24|&amp;quot;Invalid tag name &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|25||[[Help:VE25|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|26||[[Help:VE26|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|27||[[Help:VE27|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must have a mesh file extension.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|28||[[Help:VE28|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must have an image file extension.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|29||[[Help:VE29|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must have an animation file extension.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|30||[[Help:VE30|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; refers to a nonexistent file: &#039;$(FILENAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|31||[[Help:VE31|&amp;quot;Invalid tag name &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|32||[[Help:VE32|&amp;quot;Alias mesh requires valid parent asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|33||[[Help:VE33|&amp;quot;Alias mesh &#039;$(FILE)&#039; not found in dependency $(KUID).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|34||[[Help:VE34|&amp;quot;Alias mesh &#039;$(FILE)&#039; not found in latest version ($(NEW_KUID)) of dependency $(OLD_KUID).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|35||[[Help:VE35|&amp;quot;Required alias mesh asset $(KUID) is missing and cannot be validated.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|36||[[Help:VE36|&amp;quot;The texture &#039;$(FILE)&#039; failed to load.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|37||[[Help:VE37|&amp;quot;The texture &#039;$(FILE)&#039; is not a power of 2, please resize it.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|38||[[Help:VE38|&amp;quot;The texture &#039;$(FILE)&#039; is not square. Cubemap textures need to have the same width and height.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|39||[[Help:VE39|&amp;quot;The texture &#039;$(FILE)&#039; is a uniform color.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|40||[[Help:VE40|&amp;quot;Unable to load $(TYPE) texture &#039;$(TEXTURE)&#039; for texture file &#039;$(FILE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|41||[[Help:VE41|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Integer value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|42||[[Help:VE42|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Decimal value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|43||[[Help:VE43|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is not a valid Boolean value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|44||[[Help:VE44|&amp;quot;Tag &#039;$(TAG_NAME)&#039; in the container &#039;$(CONT_NAME)&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|45||[[Help:VE45|&amp;quot;The Tag &#039;$(TAG_NAME)&#039; is not permitted within a container of type &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|46||[[Help:VE46|&amp;quot;Internal Error: The template does not specify that a smoke container is valid in the container being parsed.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|47||[[Help:VE47|&amp;quot;Container &#039;$(CONT_NAME)&#039; is not permitted in this section.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|48||[[Help:VE48|&amp;quot;This asset uses an obsolete trainz-build number. Trainz-build numbers below $(LOWEST_TRAINZBUILD) are no longer supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|49||[[Help:VE49|&amp;quot;Required tag &#039;kind&#039; is not present. Ensure this is a valid config file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|50||[[Help:VE50|&amp;quot;Unsupported kind &#039;$(KIND)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|51||[[Help:VE51|&amp;quot;Tag &#039;$(TAG_NAME)&#039; in the container &#039;$(CONT_NAME)&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|52||[[Help:VE52|&amp;quot;The Tag &#039;$(TAG_NAME)&#039; is not permitted within a container of type &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|53||[[Help:VE53|&amp;quot;This container is no longer supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|54||[[Help:VE54|&amp;quot;The Tag &#039;$(TAG_NAME)&#039; is not permitted within a container of type &#039;$(CONT_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|55||[[Help:VE55|&amp;quot;This container is no longer supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|56||[[Help:VE56|&amp;quot;Container &#039;$(CONT_NAME)&#039; is not permitted in this section.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|57||[[Help:VE57|&amp;quot;Container &#039;$(CONT_NAME)&#039; is not permitted in this section.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|58||[[Help:VE58|&amp;quot;The tag &#039;$(TAG_NAME)&#039; is not a valid container type (expected &#039;$(TYPE)&#039;).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|59||[[Help:VE59|&amp;quot;Internal error: unknown dataType - kind &#039;$(KIND)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|60||[[Help:VE60|&amp;quot;Required tag &#039;$(TAG_NAME)&#039; was missing and has been set to default.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|61||[[Help:VE61|&amp;quot;Required tag &#039;$(TAG_NAME)&#039; was missing and has been set to default.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|62||[[Help:VE62|&amp;quot;Required container &#039;$(CONT_NAME)&#039; is missing.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|63||[[Help:VE63|&amp;quot;The cubemap texture &#039;$(FILE)&#039; has missing images. Please verify the texture.txt file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|64||[[Help:VE64|&amp;quot;Cubemap texture &#039;$(FILE)&#039; contains images of different sizes.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|65||[[Help:VE65|&amp;quot;The *.texture.txt file is missing for texture resource &#039;$(FILE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|66||[[Help:VE66|&amp;quot;The texture file &#039;$(FILE)&#039; contains non-ANSI characters. Textures must be ANSI.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|67||[[Help:VE67|&amp;quot;The texture &#039;$(FILE)&#039; does not seem to have a primary texture set. Please verify the texture.txt file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|68||[[Help:VE68|&amp;quot;The primary and alpha texture are not the same size for &#039;$(FILE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|69||[[Help:VE69|&amp;quot;Binary conversion failed for texture resource &#039;$(FILE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|70||[[Help:VE70|&amp;quot;The KUID tag is not a valid KUID value: &#039;$(string)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|71||[[Help:VE71|&amp;quot;Unsupported SpeedTree version for mesh: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|72||[[Help:VE72|&amp;quot;Unable to load mesh file: &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|73||[[Help:VE73|&amp;quot;Image file &#039;$(FILE)&#039; is incorrectly used as both a texture.txt source file and a raw image file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|74||[[Help:VE74|&amp;quot;Image file &#039;$(FILE)&#039; is incorrectly used as both a texture.txt source file and a raw image file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|76||[[Help:VE76|&amp;quot;Unable to load mesh file: &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|77||[[Help:VE77|&amp;quot;Unable to load indexed mesh &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|79||[[Help:VE79|&amp;quot;Unable to load animation file &#039;$(FILE)&#039; (mesh has not been loaded correctly).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|81||[[Help:VE81|&amp;quot;The high-poly mesh &#039;$(FILE)&#039; should have LOD levels.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|82||[[Help:VE82|&amp;quot;High-detail .im files are not supported for traincar assets, as they are likely to perform poorly. It is recommended that you upgrade &#039;$(FILE)&#039; to a .lm file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|83||[[Help:VE83|&amp;quot;The file &#039;$(FILE)&#039; is provided in LM format despite having no attachment points and no animation support. This may have a negative impact on performance.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|84||[[Help:VE84|&amp;quot;The file &#039;$(FILE)&#039; is provided in LM format despite containing only a single mesh. This may have a negative impact on performance.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|85||[[Help:VE85|&amp;quot;The file &#039;$(FILE)&#039; is provided in LM format, however the high-detail mesh is comprised of less than 300 polygons. This may have a negative impact on performance.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|86||[[Help:VE86|&amp;quot;Legacy .pm files are no longer supported, and will perform poorly. It is recommended that you switch to using a .lm file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|87||[[Help:VE87|&amp;quot;Legacy .pm files are no longer supported, and will perform poorly. It is recommended that you switch to using a .lm file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|88||[[Help:VE88|&amp;quot;This asset has a trainz-build number which is not recognised by this tool.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|89||[[Help:VE89|&amp;quot;Tag &#039;$(TAG_NAME)&#039; in the container &#039;$(CONT_NAME)&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|90||[[Help:VE90|&amp;quot;This asset has an invalid KUID user id&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|91||[[Help:VE91|&amp;quot;The dependency $(KUID) has an invalid KUID User ID and cannot be used&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|92||[[Help:VE92|&amp;quot;Duplicate &#039;$(TAG_NAME)&#039; containers in &#039;$(CONT_NAME)&#039;. Containers must have a unique name.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|93||[[Help:VE93|&amp;quot;Duplicate &#039;$(TAG_NAME)&#039; tags in &#039;$(CONT_NAME)&#039;. Tags must have a unique name.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|94||[[Help:VE94|&amp;quot;This asset requires a shadow mesh, but the mesh table does not contain one.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|95||[[Help:VE95|&amp;quot;This asset does not have a mesh that is visible by default.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|96||[[Help:VE96|&amp;quot;Maximum of 5 running number fonts supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|97||[[Help:VE97|&amp;quot;The running number font directory &#039;$(DIR)&#039; could not be found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|98||[[Help:VE98|&amp;quot;The running number font file &#039;$(DIR)/$(FILE)&#039; could not be found.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|99||[[Help:VE99|&amp;quot;The track-sound container &#039;$(NAME)&#039; has no bogey, track or track-parent tag.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|100||[[Help:VE100|&amp;quot;Required tag &#039;$(TAG_NAME)&#039; was missing and has been set to default.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|101||[[Help:VE101|&amp;quot;The file &#039;$(FILE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|102||[[Help:VE102|&amp;quot;Failed to load sound file &#039;$(FILE)&#039;, please ensure this is a valid wav file.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|103||[[Help:VE103|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in container &#039;$(CONT_NAME)&#039; is empty.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|104||[[Help:VE104|&amp;quot;Multiple template property bindings for rule property &#039;$(PROP)&#039; for rule &#039;$(RULE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|105||[[Help:VE105|&amp;quot;The template property &#039;$(NAME)&#039; specified in the rule-template-bindings container of rule &#039;$(RULE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|106||[[Help:VE106|&amp;quot;The high-detail meshes in season $(SEASON) total more than $(LIMIT) polygons. This may have a negative impact on performance: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|107||[[Help:VE107|&amp;quot;The high-detail meshes total more than $(LIMIT) polygons. This may have a negative impact on performance: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|108||[[Help:VE108|&amp;quot;The low-detail meshes in season $(SEASON) total more than 500 polygons. This may have a negative impact on performance: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|109||[[Help:VE109|&amp;quot;The low-detail meshes total more than 500 polygons. This may have a negative impact on performance: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|110||[[Help:VE110|&amp;quot;The meshes in LOD level $(LOD_LEVEL) in season $(SEASON) must total at least 20% fewer polygons than the next higher LOD in the same season: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|111||[[Help:VE111|&amp;quot;The meshes in LOD level $(LOD_LEVEL) must total at least 20% fewer polygons than the next higher LOD: $(LOD_SUMMARY)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|112||[[Help:VE112|&amp;quot;Multiple track stretches between &#039;$(FROM_VERTEX)&#039; and &#039;$(TO_VERTEX)&#039; in container &#039;$(CONT_NAME)&#039;. Track stretches must be unique.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|113||[[Help:VE113|&amp;quot;An image file (&#039;$(FILE)&#039;) has been supplied where a texture file (&#039;*.texture.txt&#039;) is required.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|114||[[Help:VE114|&amp;quot;An image file (&#039;$(FILE)&#039;) has been supplied where a texture file (&#039;*.texture.txt&#039;) is required.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|115||[[Help:VE115|&amp;quot;The texture file &#039;$(FILE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|116||[[Help:VE116|&amp;quot;No texture file has been specified for this texture asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|117||[[Help:VE117|&amp;quot;&#039;$(TAG_0)&#039; must be set to a &#039;$(KIND)&#039; for &#039;$(TAG_1)&#039; to be allowed.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|118||[[Help:VE118|&amp;quot;Tag &#039;$(TAG_0)&#039; requires that &#039;$(TAG_1)&#039; be set to &#039;$(KIND)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|119||[[Help:VE119|&amp;quot;The tag &#039;$(TAG_NAME)&#039; is not valid for kind &#039;$(KIND)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|120||[[Help:VE120|&amp;quot;Tag &#039;$(TAG_0)&#039;, requires the tag &#039;$(TAG_1)&#039; to be present.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|121||[[Help:VE121|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|122||[[Help:VE122|&amp;quot;&#039;$(TAG_NAME)&#039; must have a positive value.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|123||[[Help:VE123|&amp;quot;The script file &#039;$(FILE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|124||[[Help:VE124|&amp;quot;The file &#039;$(FILE)&#039; does not exist.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|125||[[Help:VE125|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|126||[[Help:VE126|&amp;quot;&#039;$(TAG_NAME)&#039; must not be zero.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|127||[[Help:VE127|&amp;quot;No value has been entered for tag &#039;$(TAG_NAME).&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|128||[[Help:VE128|&amp;quot;The value for &#039;$(TAG_NAME)&#039; must be between &#039;$(MIN)&#039; and &#039;$(MAX)&#039; but was specified as &#039;$(VALUE)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|129||[[Help:VE129|&amp;quot;Incorrect number of values for the tag &#039;$(TAG_NAME)&#039;, expected $(NUM_0) values, found $(NUM_1).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|130||[[Help:VE130|&amp;quot;Too many values for the tag &#039;$(TAG_NAME)&#039;, maximum is $(MAX) values, found $(FOUND).&amp;quot;]]]]&lt;br /&gt;
|-&lt;br /&gt;
|131||[[Help:VE131|&amp;quot;Value must be a mesh from the mesh-table (not a parent container).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|132||[[Help:VE132|&amp;quot;The attachment point &#039;$(ATT)&#039; must belong to the parent mesh of the effect (mesh=$(MESH)).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|133||[[Help:VE133|&amp;quot;A light container must be present to link the signals.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|134||[[Help:VE134|&amp;quot;&#039;$(NUM)&#039; must be a valid light number from the light container.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|135||[[Help:VE135|&amp;quot;&#039;$(TAG_0)&#039; requires that the tag &#039;$(TAG_1)&#039; be present.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|136||[[Help:VE136|&amp;quot;&#039;$(TAG_0)&#039; requires that the tag &#039;$(TAG_1)&#039; be present.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|137||[[Help:VE137|&amp;quot;Empty or invalid running number specified at character index $(INDEX)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|138||[[Help:VE138|&amp;quot;Running number specified at character index $(INDEX) is too large, must be less than 9 characters.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|139||[[Help:VE139|&amp;quot;Invalid running number range specified at character index $(INDEX), ($(FROM)-$(TO)).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|140||[[Help:VE140|&amp;quot;Running number range &#039;$(FROM)-$(TO)&#039; specified at character index $(INDEX) overlaps already in use numbers, running numbers must be unique.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|141||[[Help:VE141|&amp;quot;Running number &#039;$(NUMBER)&#039; specified at character index $(INDEX) is already in use.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|142||[[Help:VE142|&amp;quot;Invalid character &#039;$(CHAR)&#039; specified in running number list, only numbers, &#039;,&#039; and &#039;-&#039; are supported.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|143||[[Help:VE143|&amp;quot;Possible running number list is too large, the set must contain less than 20000 possibilities.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|144||[[Help:VE144|&amp;quot;Category code &#039;ZX - Paintshed template&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|145||[[Help:VE145|&amp;quot;Category code &#039;ZX - Paintshed template&#039; is obsolete.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|146||[[Help:VE146|&amp;quot;An asset must be specified for tag &#039;$(TAG_NAME)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|147||[[Help:VE147|&amp;quot;The tag(s) $(MISPLACED_TAGS) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|148||[[Help:VE148|&amp;quot;The tag(s) $(MISPLACED_TAGS) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|149||[[Help:VE149|&amp;quot;The mesh(es) $(MISPLACED_MESHES) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|150||[[Help:VE150|&amp;quot;The mesh(es) $(MISPLACED_MESHES) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|151||[[Help:VE150|&amp;quot;The mesh(es) $(MISPLACED_MESHES) can only be used when track-type = $(CORRECT_TRACK_TYPE). They will be ignored in this asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|152||[[Help:VE152|&amp;quot;The tags $(MISSING_TAGS) are not all defined. The default values will be used and the positions of the elements may not fit your track.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|153||[[Help:VE153|&amp;quot;The mesh $(MESH) is present but the tag $(MISSING_TAG) is not defined.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|154||[[Help:VE154|&amp;quot;The mesh $(MESH) is present but the tag $(MISSING_TAG) is not defined.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|155||[[Help:VE155|&amp;quot;The mesh $(MESH) is present but the tags $(MISSING_TAGS) are not all defined.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|156||[[Help:VE156|&amp;quot;The tag $(MISSING_TAG) is not defined. The default value will be used and the positions of the elements may not fit your track.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|157||[[Help:VE157|&amp;quot;The mesh $(MESH) is present but the tag $(MISSING_TAG) is missing. The default value will be used and the positions of the elements may not fit your track.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|158||[[Help:VE158|&amp;quot;Unable to open .lm.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|159||[[Help:VE159|&amp;quot;Unable to parse .lm.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|160||[[Help:VE160|&amp;quot;No &#039;mesh&#039; keys found in .lm.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|161||[[Help:VE161|&amp;quot;$(LODCOUNT) LODs in .lm.txt file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|162||[[Help:VE162|&amp;quot;One of the LOD reductions of &#039;$(FILE)&#039; introduces a new attachment point: $(ATT)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|163||[[Help:VE163|&amp;quot;Unable to parse .im file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|164||[[Help:VE164|&amp;quot;Invalid position data in .im file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|165||[[Help:VE165|&amp;quot;Texture &#039;$(TEXTURE)&#039; is missing or could not be loaded in mesh &#039;$(FILE)&#039;, material &#039;$(MATERIAL)&#039;.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|166||[[Help:VE166|&amp;quot;$(COMBINEDCOUNT) combined chunks (of $(SOURCECOUNT) source) in .im file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|167||[[Help:VE167|&amp;quot;Source image texture file &#039;$(TEXTUREFILE)&#039; is too large for &#039;$(ASSETFILE)&#039; ($(WIDTH)x$(HEIGHT))&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|168||[[Help:VE168|&amp;quot;File &#039;$(TEXTUREFILE)&#039; is not a valid compiled texture file for &#039;$(ASSETFILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|169||[[Help:VE169|&amp;quot;Compiled texture file &#039;$(TEXTUREFILE)&#039; is unsupported version for &#039;$(ASSETFILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|170||[[Help:VE170|&amp;quot;Failed to open compiled texture &#039;$(TEXTUREFILE)&#039; for &#039;$(ASSETFILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|171||[[Help:VE171|&amp;quot;Expected texture file type but found &#039;$(TEXTUREFILE)&#039; for &#039;$(ASSETFILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|172||[[Help:VE172|&amp;quot;Script class does not match asset kind ($(KIND)).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|173||[[Help:VE173|&amp;quot;Material &#039;$(MATERIAL)&#039; in mesh &#039;$(FILE)&#039; is not of a recognised material type.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|174||[[Help:VE174|&amp;quot;MeshObjectSpec::LinkSpecs&amp;gt; Mesh-table element #$(MESH_INDEX) parent mesh is invalid.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|175||[[Help:VE175|&amp;quot;MeshObjectSpec::LinkSpecs&amp;gt; Mesh-table element #$(MESH_INDEX) is part of invalid hierarchy.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|176||[[Help:VE176|&amp;quot;The tag &#039;$(TAG_NAME)&#039; in &#039;$(CONT_NAME)&#039; must have a texture file extension.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|177||[[Help:VE177|&amp;quot;The kuid &#039;$(KUID)&#039; is not in the database, and could not be found in any known location. Ensure that this is a valid asset.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|178||[[Help:VE178|&amp;quot;The asset specified in &#039;$(KUID)&#039; is not installed locally but is available for download.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|179||[[Help:VE179|&amp;quot;The kuid &#039;$(KUID)&#039; specified in &#039;$(TAG_NAME)&#039; is not of the correct type.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|180||[[Help:VE180|&amp;quot;Integrity check failure on $(FILE). One or more route/session tiles may be missing.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|181||[[Help:VE181|&amp;quot;The tag &#039;$(TAG_NAME)&#039; requires a minimum asset version of $(MIN_VERSION)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|182||[[Help:VE182|&amp;quot;Material &#039;$(MATERIAL)&#039; in mesh &#039;$(FILE)&#039; is missing a texture for a mandatory texture slot.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|183||[[Help:VE183|&amp;quot;FBX file is in an unsupported older format.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|184||[[Help:VE184|&amp;quot;KIND &#039;$(KIND)&#039; requires trainz-build $(TRAINZBUILD).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|185||[[Help:VE185|&amp;quot;Material &#039;$(MATERIAL)&#039; in mesh &#039;$(FILE)&#039; has heightmap texture. Provide a normal map instead.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|186||[[Help:VE186|&amp;quot;Material &#039;$(MATERIAL)&#039; is shared between multiple chunks in this asset but the material parameters conflict.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|187||[[Help:VE187|&amp;quot;The value &#039;$(VALUE)&#039; in not a valid KUID.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|188||[[Help:VE188|&amp;quot;Custom render plugin failed to load mesh &#039;$(FILE)&#039;&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|189||[[Help:VE189|&amp;quot;Collision data exceeds $(LIMIT)KB. Please specify a different generation method or a simplified mesh.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|190||[[Help:VE190|&amp;quot;Tag &#039;$(NAME)&#039; is unable to be converted from $(TYPE1) to $(TYPE2)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|191||[[Help:VE191|&amp;quot;Tag &#039;$(NAME)&#039; does not contain a valid integer: $(VALUE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|192||[[Help:VE192|&amp;quot;Tag &#039;$(NAME)&#039; does not contain a valid float list: $(VALUE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|193||[[Help:VE193|&amp;quot;Tag &#039;$(NAME)&#039; does not contain a valid float&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|194||[[Help:VE194|&amp;quot;Tag &#039;$(NAME)&#039; does not contain a valid kuid: $(VALUE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|195||[[Help:VE195|&amp;quot;Unable to parse chunk $(CHUNK_INDEX) in mesh file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|196||[[Help:VE196|&amp;quot;Failed to load bogey $(KUID)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|197||[[Help:VE197|&amp;quot;Syntax error in script &#039;$(SCRIPT)&#039; for asset $(ASSET)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|198||[[Help:VE198|&amp;quot;Session failed to load route asset: $(KUID)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|199||[[Help:VE199|&amp;quot;Asset $(KUID) failed to load. Unloading resources.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|200||[[Help:VE200|&amp;quot;Unable to load mesh $(NAME) for $(ASSET_ID)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|201||[[Help:VE201|&amp;quot;Traincar is missing required attachment point: $(ATT_NAME)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|202||[[Help:VE202|&amp;quot;Parse error reading twinkles file: $(FILE)&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|203||[[Help:VE203|&amp;quot;Bad sequence order in $(TAG_NAME) list. Each element must be greater than the last.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|204||[[Help:VE204|&amp;quot;Invalid range in $(TAG_NAME) list. Elements must be greater than or equal to $(INC_MIN) and less than $(EXC_MAX).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|205||[[Help:VE205|&amp;quot;Invalid element count in $(TAG_NAME) list. This list must have at least $(COUNT) elements (to match the $(TAG_START) list).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|206||[[Help:VE206|&amp;quot;The season-selector references season &#039;$(SEASON)&#039;, but this does not exist in the texture-variants container.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|207||[[Help:VE207|&amp;quot;Attached track asset $(CHILD) failed to load.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|208||[[Help:VE208|&amp;quot;Attached track asset not specified for track $(INDEX).&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|209||[[Help:VE209|&amp;quot;Asset is missing the required &#039;attached-track&#039; container.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|210||[[Help:VE210|&amp;quot;Asset is missing the required &#039;track&#039; tag.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|211||[[Help:VE211|&amp;quot;Asset is missing the required &#039;road&#039; tag.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|212||[[Help:VE212|&amp;quot;Traincar asset must have at least two bogeys.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|213||[[Help:VE213|&amp;quot;Traincar asset has invalid bogey placement.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|214||[[Help:VE214|&amp;quot;Traincar asset has invalid length.&amp;quot;]]&lt;br /&gt;
|-&lt;br /&gt;
|215||[[Help:VE215|&amp;quot;Asset has an invalid number of LODs: $(LOD_COUNT)&amp;quot;]]&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=HowTo/Export_from_Blender_using_FBX&amp;diff=13130</id>
		<title>HowTo/Export from Blender using FBX</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=HowTo/Export_from_Blender_using_FBX&amp;diff=13130"/>
		<updated>2018-06-06T03:29:14Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
==Introduction==&lt;br /&gt;
&lt;br /&gt;
This guide provides information for the export of FilmBoX (FBX) files from Blender. &lt;br /&gt;
&lt;br /&gt;
===Versions===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;width:100px;&amp;quot;|TANE:||style=&amp;quot;width:200px;&amp;quot;|4.5 or later.&lt;br /&gt;
|-&lt;br /&gt;
|Blender:|| Known to work for Blender 2.78a or later.  The FBX exporter is a standard addon for Blender.&lt;br /&gt;
|-&lt;br /&gt;
|FBX format:|| Binary format only (see discussion below).  FBX 2011, FBX2012, FBX2013.&lt;br /&gt;
|-&lt;br /&gt;
|Special requirements:|| None.  Creators will need their preferred image editors and text editors but there are no special requirements for FBX.&lt;br /&gt;
|-&lt;br /&gt;
|Other software:||  There are free FBX viewers available on the web including {{plain link|http://www.autodesk.com/products/fbx/fbx-review|FBX Review}} and  FBX Converter  programs by Autodesk.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===The FBX format===&lt;br /&gt;
&lt;br /&gt;
A brief discussion on the FBX format history can be found  {{plain link|https://en.wikipedia.org/wiki/FBX here}}.   FBX can be exported, or imported, either as an ASCII (i.e. human readable) file or in binary format.  &lt;br /&gt;
&lt;br /&gt;
==Blender and FBX==&lt;br /&gt;
&lt;br /&gt;
Blender is capable of both importing and exporting FBX formatted files.  Two formats are available: ASCII FBX 6.1 and binary FBX 7.4 (Blender 2.78).  Since TANE will only accept FBX versions between 7.1 (7100) and 7.5 (7500), the ASCII version cannot be used for Trainz.  Note that work on the Blender ASCII importer/exporter is frozen.&lt;br /&gt;
&lt;br /&gt;
The Blender exporter does not export all possible object attributes and it is likely that TANE will not recognise all those attributes that are exported.&lt;br /&gt;
The Blender documentation contains a  {{plain link|https://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/Import-Export/Autodesk_FBX  list of attributes}} that are exported.  &lt;br /&gt;
&lt;br /&gt;
Included in this guide is a list of attributes that have been observed as exported and treatment/acceptance by TANE.  The list is incomplete and will be updated when new information is available.&lt;br /&gt;
&lt;br /&gt;
N3V use the ASSIMP Open Asset Import Library to extract asset model information from the FBX file.  ASSIMP Version 3.3.1 appears to be FBX version 7.3 and the Blender FBX exporter exports FBX 7.4.  This results in some warnings that appear to be generated by Content Manager but actually come from the ASSIMP process.  If you get warnings that you cannot correct, such as those in the warnings section below, try running the Blender generated FBX file through the Autodesk FBX Converter program and choose FBX2013 as the target. These warnings do not appear to affect the outcome so this step may not be necessary.&lt;br /&gt;
 &lt;br /&gt;
==TANE and the FBX Importer==&lt;br /&gt;
A discussion of the FBX format and general guidelines for use with TANE is discussed at this Trainz WiKi page:  [[FBX  file format]]&lt;br /&gt;
&lt;br /&gt;
==Skills Required==&lt;br /&gt;
For this version of the guide, it is assumed the user has some knowledge of the use of Blender and an understanding of the Trainz asset creation process. &lt;br /&gt;
&lt;br /&gt;
==Exporting a mesh object from Blender in FBX format (no animation)==&lt;br /&gt;
&lt;br /&gt;
The FBX exporter addon must be enabled in User Preferences.&lt;br /&gt;
&lt;br /&gt;
Select File-&amp;gt;Export-&amp;gt;Export FBX and the FBX export panel will show in the bottom left hand corner and should look like the following picture.  The panel contents&lt;br /&gt;
vary significantly between the Binary export version and the ASCII export version so make sure you have Binary selected.&lt;br /&gt;
&lt;br /&gt;
===The Main Menu===&lt;br /&gt;
[[File:Blender_FBX_Main_Menu.jpg|380px|left]] &lt;br /&gt;
* Ignore the Operator Presets for now.&lt;br /&gt;
* Ensure FBX 7.4 binary version is selected.&lt;br /&gt;
* The Main/Geometry/Armatures/Animation buttons provide menu options for the item selected.  Select the Main option.&lt;br /&gt;
* Selected Objects.  This option needs careful consideration.  Unlike the Blender XML exporter, the FBX exporter will export all objects in all layers&lt;br /&gt;
which is probably undesirable in many cases and particularly if you have different LOD models in different layers.  So, first select those objects within Blender&lt;br /&gt;
that you want to export and then select Selected Objects in this panel.&lt;br /&gt;
* Scale.  Leave the Scale value as 1.00 and deselect the small icon to the right of the Scale value. (See note below)&lt;br /&gt;
* Forward and Up.  Set these to the values :Y forward and Z Up.&lt;br /&gt;
&lt;br /&gt;
The options below are multi select (i.e. you can select more than one).  For the time being just leave Mesh selected.&lt;br /&gt;
&lt;br /&gt;
* Leave the Experimental and Custom Properties as deselected. &lt;br /&gt;
* Leave Path Mode as Auto and Batch Mode as Off. &lt;br /&gt;
* Choose the FBX filename and export using the Export FBX in the top right hand corner.  There is no exporter log.&lt;br /&gt;
{{clear}}&lt;br /&gt;
&lt;br /&gt;
Note that  Blender 2.79 introduced some options for scaling that need some investigation.  Recommend using &amp;quot;FBX All&amp;quot; until this has been investigated.&lt;br /&gt;
&lt;br /&gt;
====Tip====&lt;br /&gt;
You can save your preferences for a given situation by clicking on the plus button (+) next to Operator Presets and saving the preset with a name.  This is particularly useful for animation.  You will need to reload the preset each time you start Blender.&lt;br /&gt;
&lt;br /&gt;
===The Geometry Menu===&lt;br /&gt;
&lt;br /&gt;
[[File:FBX Geometry Menu.jpg|380px|left]] &lt;br /&gt;
* Leave these values as shown. &lt;br /&gt;
{{clear}}&lt;br /&gt;
&lt;br /&gt;
===The Armatures and Animation Menus===&lt;br /&gt;
&lt;br /&gt;
* See the [http://online.ts2009.com/mediaWiki/index.php?title=HowTo/Export_from_Blender_using_FBX&amp;amp;action=submit#Animation Animation Section].&lt;br /&gt;
{{clear}}&lt;br /&gt;
&lt;br /&gt;
===Config.txt - simple model===&lt;br /&gt;
&lt;br /&gt;
Setting up the CONFIG.TXT&lt;br /&gt;
&lt;br /&gt;
The only changes to the config.txt are in the mesh table.  The mesh entries for FBX files now have a &amp;quot;trainzmesh&amp;quot; extention as per the following example:&lt;br /&gt;
&lt;br /&gt;
  mesh-table {&lt;br /&gt;
    default {&lt;br /&gt;
      auto-create                           1&lt;br /&gt;
      mesh                                  &amp;quot;my-mesh.trainzmesh&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
Note that for the LM.TXT Level of Detail (LOD) you can still use the LM convention but the LM.TXT file must refer to trainzmesh files.&lt;br /&gt;
&lt;br /&gt;
===Files created===&lt;br /&gt;
&lt;br /&gt;
====Mesh files====&lt;br /&gt;
&lt;br /&gt;
The file my-mesh.trainzmesh is created during the asset commit.  Currently the FBX file is not deleted but bundled into the asset.  Since the FBX format is readable by 3D modelling tools, you may want to remove any FBX files from assets uploaded to the DLS or other web sites.&lt;br /&gt;
&lt;br /&gt;
====Texture.txt files====&lt;br /&gt;
&lt;br /&gt;
You can provide your own texture.txt files (advisable) or let the commit process create them for you.  The commit process will create suitable files, such as those required for normal maps, but you can provide your own if you have special requirements.&lt;br /&gt;
&lt;br /&gt;
Warning:  If you get odd effects with your textures, check the associated texture.txt file first.  The FBX importer tends to add an &amp;quot;alpha=&amp;quot; line even though no alpha option has been chosen.  This may be an issue with the Blender FBX exporter.&lt;br /&gt;
&lt;br /&gt;
PEV&#039;s TextureTXT utility can be very useful for creating texture.txt files and its worth adding it into AssetX if you use AssetX for managing your projects.&lt;br /&gt;
&lt;br /&gt;
===Double Sided Meshes===&lt;br /&gt;
It appears that FBX does not support double sided meshes so you need to create a metadata file as described at [[FBX file format#Mesh Metadata Files]].  Note that this is done per material.  i.e. you cannot have the same material for single sided and double sided meshes.&lt;br /&gt;
&lt;br /&gt;
===Self Illuminated Meshes===&lt;br /&gt;
Meshes that require self illumination require a separate material with the Shader-&amp;gt;Emit value set to a value other than 0.  A value of 1.0 is recommended.  The Blender exporter also exports an emissive colour using the diffuse colour value.  It is not known if TANE uses the emissive colour.  You might also experiment with the specular values.&lt;br /&gt;
&lt;br /&gt;
===General warnings and errors===&lt;br /&gt;
Errors and warnings starting with a T, such as T16128, are errors ouput by the ASSIMP converter and are not output by the Trainz FBX importer.&lt;br /&gt;
&lt;br /&gt;
{|  style=&amp;quot;border:1px solid gray;border-collapse:collapse;background:white;font-weight:bold; &amp;quot; cellpadding=5px align=left width=70% &lt;br /&gt;
|- style=&amp;quot;font-weight:bold; text-align:center;&amp;quot;&lt;br /&gt;
  ! width=40% style=&amp;quot; border:1px solid gray;&amp;quot;|Warning/Error&lt;br /&gt;
  ! width=60% style=&amp;quot; border:1px solid gray;&amp;quot;|Help/Explanation&lt;br /&gt;
|-&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Warning:  T16080: ...shading mode not recognised: Phong&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;| You can probably ignore this warning.  The warning may go away if you run the FBX file through Autodesk&#039;s FBX Converter program to the FBX2013 format.&lt;br /&gt;
|-&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Warn,  T15808: FBX-DOM (TOK_KEY, offset 0xnnnn) source object for connection does not exist&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;| You can probably ignore this warning.  The warning may go away if you run the FBX file through Autodesk&#039;s FBX Converter program to the FBX2013 format.&lt;br /&gt;
|-&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Error: Unable to determine vertex format.&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|This can be caused by having multiple UV maps for the same mesh.  For example, baking a painted mesh to a bake mesh requires two UV maps.  Remove old maps before exporting.  If you wish to keep those maps, back up the Blender file and then delete the extra maps.&lt;br /&gt;
|-&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Error, T9068 Failed to triangulate polygon (no ear found). Probably not a simple polygon. This follows a previous info &amp;quot;All polygons triangulated&amp;quot;&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|The exact cause of this problem is unknown but recommend using a mesh edit tool to triangulate all polygons.&lt;br /&gt;
|-&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Error, Error, T16128: FindInvalidDataProcess fails on mesh uvcoords: All vectors are identical&amp;quot;&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Probably caused by having multiple UV maps for the same mesh. Not sure of the relationship between this error and the &amp;quot;Unable to determine vertex format&amp;quot; error.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Level of Detail (LOD)===&lt;br /&gt;
&lt;br /&gt;
The rules for [[Level of Detail]] for FBX models are the same as indexed mesh (IM) models except for the use of the Trainzmesh suffix for mesh files.&lt;br /&gt;
&lt;br /&gt;
====Mesh-Table Method====&lt;br /&gt;
&lt;br /&gt;
This is a very simple scenery model of a coloured ball using three levels of LOD:  [[File:6000101_-_FBX_-_LOD_mesh-table_test1.zip]].&lt;br /&gt;
The Blender source is provided.&lt;br /&gt;
&lt;br /&gt;
====LM.TXT Method====&lt;br /&gt;
&lt;br /&gt;
(TBD)&lt;br /&gt;
&lt;br /&gt;
==Animation==&lt;br /&gt;
&lt;br /&gt;
===Overview===&lt;br /&gt;
&lt;br /&gt;
Trainz will not animate a mesh without the use of helper points using the &amp;quot;b.r&amp;quot; notation.  For Blender, those helper points can be armatures (bones) or empties.  Lattices are not supported by the FBX exporter.&lt;br /&gt;
&lt;br /&gt;
An animation must have a root helper normally called &amp;quot;b.r.main&amp;quot; although &amp;quot;b.r.root&amp;quot; will also work.  Using such names helps identify the overall parent of the animation.&lt;br /&gt;
Other animation helpers are called &amp;quot;b.r.xxx&amp;quot;, where &amp;quot;xxx&amp;quot; can be any name.  These helpers must be children of the main/root helper.&lt;br /&gt;
&lt;br /&gt;
===Exporting an animated mesh object===&lt;br /&gt;
====The Main Menu====&lt;br /&gt;
[[File:Blender FBX export main-anim.jpg|380px|left]] &lt;br /&gt;
* Select Empty and Armature depending on how you set up your animation.&lt;br /&gt;
* Other options are described above.&lt;br /&gt;
{{clear}}&lt;br /&gt;
&lt;br /&gt;
====The Armatures Menu====&lt;br /&gt;
[[File:FBX Armatures Menu.jpg|380px|left]] &lt;br /&gt;
* Use the values as shown.  &lt;br /&gt;
{{clear}}&lt;br /&gt;
&lt;br /&gt;
====The Animation Menu====&lt;br /&gt;
[[File:Blender FBX anim menu1.jpg|380px|left]] &lt;br /&gt;
* Select Baked Animation and disable the other options.&lt;br /&gt;
&lt;br /&gt;
Authors note:  This is completely different from the process described in the 3DS Max FBX animation export.&lt;br /&gt;
If Baked Animation is not ticked, then none of the other animation options are available.  So far, none of those other options have been found useful.&lt;br /&gt;
{{clear}}&lt;br /&gt;
&lt;br /&gt;
===Files created during the export and import process===&lt;br /&gt;
&lt;br /&gt;
The Blender exporter creates a binary file with the name of your choosing plus an FBX suffix.  For animation, the exporter creates an internal name that the TANE importer uses for an animation (KIN) file.&lt;br /&gt;
&lt;br /&gt;
If you choose Baked Animation (recommended), then the animation name is comprised of the FBX name and the word &amp;quot;_scene&amp;quot;.  So, if you export a model called &amp;quot;box.fbx&amp;quot; with animation, then the importer creates a &amp;quot;box.trainsmesh&amp;quot; and &amp;quot;box_scene.fbx&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
If you don&#039;t choose Baked Animation, then the TANE importer uses the name of the animation channel so you might get names like &amp;quot;b.r.main-b.r.mainAction.kin&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===Config.txt - Animation===&lt;br /&gt;
&lt;br /&gt;
The names of mesh and KIN files may not be obvious so you may need to create some dummy names for your mesh and KIN files.   After importing into TANE, open the asset for editing and look for the files created.  Then go back and correct entries in the config.txt.&lt;br /&gt;
&lt;br /&gt;
Sample mesh-table entry with animation:&lt;br /&gt;
&lt;br /&gt;
 mesh-table {&lt;br /&gt;
  default {&lt;br /&gt;
    auto-create                           1&lt;br /&gt;
    mesh                                  &amp;quot;box.trainzmesh&amp;quot;&lt;br /&gt;
    anim                                  &amp;quot;box_scene.kin&amp;quot;&lt;br /&gt;
    animation-loop-speed                  1.00&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Animation warnings and errors===&lt;br /&gt;
&lt;br /&gt;
{|  style=&amp;quot;border:1px solid gray;border-collapse:collapse;background:white;font-weight:bold; &amp;quot; cellpadding=5px align=left width=70% &lt;br /&gt;
|- style=&amp;quot;font-weight:bold; text-align:center;&amp;quot;&lt;br /&gt;
  ! width=40% style=&amp;quot; border:1px solid gray;&amp;quot;|Warning/Error&lt;br /&gt;
  ! width=60% style=&amp;quot; border:1px solid gray;&amp;quot;|Help/Explanation&lt;br /&gt;
|-&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|! ...  T14120: Simplified dummy tracks with just one key.&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;| Not sure what this warning is about but the animation is OK.&lt;br /&gt;
|-&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|! ... Skipping one or more lines with the same contents&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|This is an ASSIMP message and can be ignored.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Sample animations===&lt;br /&gt;
&lt;br /&gt;
The following samples are provided to demonstrate different types of Blender FBX animations.  You are free to use them for any purpose - i.e. no copyright!&lt;br /&gt;
&lt;br /&gt;
====Simple Animation 1 - Uses an empty as animated parent====&lt;br /&gt;
&lt;br /&gt;
[[File:890045 fbx anim1 - empty.zip]]&lt;br /&gt;
&lt;br /&gt;
This animation rotates a coloured cube around the X axis using an empty as parent b.r.main.  The animation action, within Blender, is called b.r.mainAction.  The channel has been set to linear interpolation.&lt;br /&gt;
&lt;br /&gt;
When exporting, you must select Empty and Mesh.&lt;br /&gt;
&lt;br /&gt;
Exported names:  The Blender FBX exporter creates a file called box.fbx.  On commit, TANE creates a mesh file called box.trainzmesh and an animation file called box_scene.kin.  &lt;br /&gt;
&lt;br /&gt;
====Simple Animation 2 - Uses an armature as animated parent====&lt;br /&gt;
&lt;br /&gt;
[[File:890044 fbx anim1 - armatures.zip]]&lt;br /&gt;
&lt;br /&gt;
This animation rotates a coloured cube around the X axis using an armature with a single bone as parent b.r.main.  The animation rotates anti-clockwise.&lt;br /&gt;
&lt;br /&gt;
This is much the same as Sample 1 but demonstrates that you can use either an empty or an armature for simple animations.&lt;br /&gt;
&lt;br /&gt;
When exporting, you must select Armature and Mesh.&lt;br /&gt;
&lt;br /&gt;
Exported names:  The Blender FBX exporter creates a file called box.fbx.  On commit, TANE creates a mesh file called box.trainzmesh and an animation file called box_scene.kin.  &lt;br /&gt;
&lt;br /&gt;
====Simple Animation 3 - Four animated cogs - LOD model====&lt;br /&gt;
&lt;br /&gt;
[[File:4000110 - FBX - anim test 4 - four cogs.zip]]&lt;br /&gt;
&lt;br /&gt;
This animation simulates four rotating cogs.  There are two LOD levels.  LOD0 (the high poly version) is in layer 1 and LOD1 (the low poly version) is in layer 2. Layer 11 contains the animated armatures.  There are four animation tracks.&lt;br /&gt;
&lt;br /&gt;
To export LOD0, select all the objects in layers 1 and 11 so the LOD0 meshes and the armatures are all selected.  On export, ensure Empty, Armature and Mesh are selected and use the name &amp;quot;4cogs-lod0.fbx&amp;quot;.  b.r.main is an empty so Empty must be selected.&lt;br /&gt;
&lt;br /&gt;
To export LOD1, select all the objects in layers 2 and 11 so the LOD1 meshes and the armatures are all selected.  On export, ensure Empty, Armature and Mesh are selected and use the name &amp;quot;4cogs-lod1.fbx&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
You can choose any names you want but a meaningful name is useful.&lt;br /&gt;
&lt;br /&gt;
This is the relevant section of config.txt:&lt;br /&gt;
&lt;br /&gt;
mesh-table {&lt;br /&gt;
  gears-lod0 {&lt;br /&gt;
    auto-create                           1&lt;br /&gt;
    mesh                                  &amp;quot;4cogs-lod0.trainzmesh&amp;quot;&lt;br /&gt;
    lod-level                             0&lt;br /&gt;
    anim                                  &amp;quot;4cogs-lod0_scene.kin&amp;quot;&lt;br /&gt;
    animation-loop-speed                  1.00&lt;br /&gt;
  }&lt;br /&gt;
  gears-lod1 {&lt;br /&gt;
    auto-create                           1&lt;br /&gt;
    mesh                                  &amp;quot;4cogs-lod1.trainzmesh&amp;quot;&lt;br /&gt;
    lod-level                             1&lt;br /&gt;
    anim                                  &amp;quot;4cogs-lod1_scene.kin&amp;quot;&lt;br /&gt;
    animation-loop-speed                  1.00&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
mesh-detail-level-count                   2&lt;br /&gt;
&lt;br /&gt;
Note that the transition from LOD0 to LOD1 is obvious. &lt;br /&gt;
&lt;br /&gt;
====More complex animations====&lt;br /&gt;
&lt;br /&gt;
=====A Sample Steam Piston Animation=====&lt;br /&gt;
[[File:Bsa.zip]]&lt;br /&gt;
&lt;br /&gt;
[[File:Circle_guided_steam_animation.jpg|380px]] &lt;br /&gt;
&lt;br /&gt;
This example shows how to animate a steam piston and crankshaft using a circle to guide the location of the piston shaft.  This is a variation of Torsten&#039;s sample for the XML exporter.  General instructions for export are contained in the Blender file as a text object.&lt;br /&gt;
&lt;br /&gt;
==Legacy Materials==&lt;br /&gt;
  &lt;br /&gt;
This section identifies the legacy material options used by the FBX exporter (i.e. prior to the introduction of [[TRS19]]).  For detailed descriptions on how Trainz uses material types, including TRS19 PBR materials, see [[Material Types]] and the child pages detailing different Trainz material types.&lt;br /&gt;
&lt;br /&gt;
The exporter treats material options based on the chosen material shader model.  Even though Trainz uses its own shaders, it may be worthwhile selecting different shader models in Blender to see the effect.  In particular, choosing the Phong model for the specular shader will enable the export of a number of extra material options.  These may, or may not, actually result in observable changes in Trainz.&lt;br /&gt;
&lt;br /&gt;
The FBX exporter uses the following material options:&lt;br /&gt;
&lt;br /&gt;
{|  style=&amp;quot;border:1px solid gray;border-collapse:collapse;background:white;font-weight:bold; &amp;quot; cellpadding=5px align=left width=70% &lt;br /&gt;
  &lt;br /&gt;
|- style=&amp;quot;font-weight:bold; text-align:center;&amp;quot;&lt;br /&gt;
  ! width=20% style=&amp;quot; border:1px solid gray;&amp;quot;|Material Option&lt;br /&gt;
  ! width=10% style=&amp;quot; border:1px solid gray;&amp;quot;|Shader&lt;br /&gt;
  ! width=70% style=&amp;quot; border:1px solid gray;&amp;quot;|Comment&lt;br /&gt;
|-&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Diffuse -&amp;gt; Color &lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Any&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Used for both diffuse and emissive colour&lt;br /&gt;
|-&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Diffuse -&amp;gt; Intensity&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Any&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Factor applied to diffuse colour&lt;br /&gt;
|-&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Shading -&amp;gt; Emit&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;| Any&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Factor applied to emissive colour&lt;br /&gt;
|-&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|World -&amp;gt; Ambient_Color&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Any&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Not sure what effect this may have, if any, on the exported result.  See also Shading -&amp;gt; Ambient.&lt;br /&gt;
|-&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Shading -&amp;gt; Ambient&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;| Any&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Amount of global ambient colour the material receives.&lt;br /&gt;
|-&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Transparency&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Any&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Use transparency if checked.&lt;br /&gt;
|-&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Transparency -&amp;gt; Alpha&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Any&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Transparency (opacity) factor.&lt;br /&gt;
|-&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Specular -&amp;gt; Color&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Phong&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|&lt;br /&gt;
|-&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Specular -&amp;gt; Intensity&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Phong&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|&lt;br /&gt;
|-&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Specular -&amp;gt; Hardness&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Phong&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Shininess&lt;br /&gt;
|-&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Mirror -&amp;gt; Color&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Phong&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Mirror must be checked.&lt;br /&gt;
|-&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Mirror -&amp;gt; Reflectivity&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Phong&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Mirror must be checked&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Be wary of checking Shading-&amp;gt;Shadeless as this  stops the export of several attributes including: Specular Color, Specular Factor, Shininess Exponent, Reflection Color, Reflection Factor, Specular, and Shininess.&lt;br /&gt;
&lt;br /&gt;
In summary, material values you can play with in any material include:&lt;br /&gt;
:* Diffuse colour&lt;br /&gt;
:* Diffuse specular&lt;br /&gt;
:* Transparency&lt;br /&gt;
:* Specular colour&lt;br /&gt;
:* Specular intensity&lt;br /&gt;
:* Specular hardness&lt;br /&gt;
:* Shading Emit &lt;br /&gt;
:* Mirror&lt;br /&gt;
:* Ambient (in World)&lt;br /&gt;
&lt;br /&gt;
===Sample Assets===&lt;br /&gt;
&lt;br /&gt;
====Notex====&lt;br /&gt;
&lt;br /&gt;
Description: TBD&lt;br /&gt;
&lt;br /&gt;
Sample asset:   A notex material applied to a box. [[File:4000001- FBX paint-test-notex.zip]]&lt;br /&gt;
&lt;br /&gt;
====Onetex====&lt;br /&gt;
&lt;br /&gt;
Description: TBD&lt;br /&gt;
&lt;br /&gt;
Sample asset:  A onetex material applied to a box. [[File:4000002 - FBX paint-test-onetex.zip]]&lt;br /&gt;
&lt;br /&gt;
====Reflect====&lt;br /&gt;
&lt;br /&gt;
Description: This works well when an image is used to influence the material base colour.  Check/tick the Mirror option in the Material panel and select the amount of reflectively you need.  Start with 0.5 and experiment.&lt;br /&gt;
The attached example uses env_metal.tga as a reflection texture. You can set the Mapping Coordinates to either UV or Reflection.  Reflection makes the model look correct in Blender but makes no difference to TANE.&lt;br /&gt;
In the Texture Influence-&amp;gt;Diffuse section, check both Color and Mirror.  Don&#039;t change the values of either field as the FBX exporter ignores them.&lt;br /&gt;
&lt;br /&gt;
M.reflect doesn&#039;t work well with a diffuse texture.  Other materials are probably better suited for that purpose.&lt;br /&gt;
&lt;br /&gt;
Sample asset: A reflect material applied to a box. [[File:4000003_-_FBX_-_paint-test-reflect.zip]] &lt;br /&gt;
&lt;br /&gt;
====Gloss====&lt;br /&gt;
&lt;br /&gt;
Description: TBD&lt;br /&gt;
&lt;br /&gt;
====Tbumptex====&lt;br /&gt;
&lt;br /&gt;
Description: TBD&lt;br /&gt;
&lt;br /&gt;
Sample asset: A tbumptex material applied to a box. [[File:4000004 - FBX - paint-test tbumptex.zip]]&lt;br /&gt;
&lt;br /&gt;
====Tbumpgloss====&lt;br /&gt;
&lt;br /&gt;
Description: TBD&lt;br /&gt;
&lt;br /&gt;
====Tbumpenv====&lt;br /&gt;
&lt;br /&gt;
Description: TBD&lt;br /&gt;
&lt;br /&gt;
Sample asset: A tbumpenv material applied to a box. [[File:4000005 - FBX - paint-test tbumpenv.zip]]&lt;br /&gt;
&lt;br /&gt;
====Transparency and Double Sided Meshes====&lt;br /&gt;
&lt;br /&gt;
This asset demonstrates transparency using notex materials and a double sided mesh using a onetex material.  In particular, it shows how metadata files can be used for this purpose.&lt;br /&gt;
[[File:6000011_-_FBX_-_transparency_test_1.zip]]&lt;br /&gt;
&lt;br /&gt;
===Textures===&lt;br /&gt;
&lt;br /&gt;
This section identifies the texture options used by the FBX exporter.  Very few of the available options are actually exported and the only exported item relevant to normal/bump maps is the Mapping-&amp;gt;Coordinates value.  In practice, this isn&#039;t an issue as test assets using Trainz bump mapped materials work fine.  You might need to provide your own texture.txt files when normal maps are required.&lt;br /&gt;
&lt;br /&gt;
The FBX exporter uses the following texture slot options:&lt;br /&gt;
&lt;br /&gt;
{|  style=&amp;quot;border:1px solid gray;border-collapse:collapse;background:white;font-weight:bold; &amp;quot; cellpadding=5px align=left width=70% &lt;br /&gt;
  &lt;br /&gt;
|- style=&amp;quot;font-weight:bold; text-align:center;&amp;quot;&lt;br /&gt;
  ! width=20% style=&amp;quot; border:1px solid gray;&amp;quot;|Texture Option&lt;br /&gt;
  ! width=70% style=&amp;quot; border:1px solid gray;&amp;quot;|Comment&lt;br /&gt;
|-&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Texture name&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Can be any name but recommend names such as Diffuse, Normal or similar to identify purpose.&lt;br /&gt;
|-&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Texture type&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Must be &amp;quot;Image or movie&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Image -&amp;gt; Name&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Filename of image.&lt;br /&gt;
|-&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Image -&amp;gt; Use Alpha&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Tick if alpha channel is to be used.&lt;br /&gt;
  |-&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Image -&amp;gt; Alpha Mode&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|This value is exported but probably not used by Trainz so leave it as &amp;quot;straight&amp;quot;.&lt;br /&gt;
|-&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Mapping -&amp;gt; Coordinates&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Use UV, Normal or Reflection&lt;br /&gt;
|-&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Mapping -&amp;gt; Map&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|UV map name&lt;br /&gt;
|-&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Image Mapping -&amp;gt; Extension&lt;br /&gt;
  | style=&amp;quot;border:1px solid gray;font-weight:normal;&amp;quot;|Use Repeat if UV wrapping required.  Probably only of value within Blender since Trainz texture.txt files define image wrapping.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Return to Index==&lt;br /&gt;
 &lt;br /&gt;
[[HowToGuides|&amp;lt;&amp;lt; How To Guides]]&lt;br /&gt;
&lt;br /&gt;
[[Category:How-to guides]]&lt;br /&gt;
[[Category:Modeling]]&lt;br /&gt;
[[Category:Content creation]]&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=Asset_Validation&amp;diff=13129</id>
		<title>Asset Validation</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=Asset_Validation&amp;diff=13129"/>
		<updated>2018-06-06T03:28:19Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;All Trainz assets must be correctly formed in order to work properly across a wide range of software and hardware configurations. To aid in this process, Trainz includes asset validation functionality which checks each item of content for a range of known flaws. This validation process is performed both on your local Trainz installation, and also as part of the [[Download Station]] Upload Process. Assets which fail validation cannot be used in-game.&lt;br /&gt;
&lt;br /&gt;
This page documents recent changes to the asset validation process. It is not intended as a complete list of possible failure cases, nor does it seek to provide information on how to fix each error condition. If a fault is discovered in your own content, you should review the relevant [[Content Configuration]] documents to understand the rules and restrictions which are relevant to the asset in question.&lt;br /&gt;
&lt;br /&gt;
== Common Misunderstandings ==&lt;br /&gt;
There are two common misunderstandings that our users often have regarding asset validation:&lt;br /&gt;
&lt;br /&gt;
1. That built-in content is exempt from validation, and may be faulty. This is incorrect; all built-in content is validated at the [[N3V Games]] offices using the same tools as are available to end users. We do not perform validation of built-in content on end-user machines because (1) it is slow, and (2) the content cannot be modified and was known to be good at the time it was made built-in.&lt;br /&gt;
&lt;br /&gt;
:: It is important, however, to note that built-in content does not contain source textures. This means that a user who attempts to clone or edit built-in content will be faced with a faulty result unless they provide their own source textures. This does not indicate that the built-in content was faulty, but rather that the user&#039;s manipulations have left the game with a faulty copy of the asset.&lt;br /&gt;
&lt;br /&gt;
2. That warnings must be fixed. Warnings are generated when the game believes that there may be reason for the content creator to review their asset. It is purely a courtesy to highlight cases which are known to be frequently problematic. This does not necessarily mean that the content is faulty, or that anything needs to be changed. Modifying your own created content to resolve warnings is encouraged, but not mandatory. Modifying content created by others to resolve warnings is strongly discouraged as it is likely to introduce compatibility issues for no benefit.&lt;br /&gt;
&lt;br /&gt;
:: Note that it is also a myth that &amp;quot;today&#039;s warning is tomorrow&#039;s error&amp;quot;. In some cases we warn people about errors prior to making the changes mandatory in future versions, but this is a guide not a rule.&lt;br /&gt;
&lt;br /&gt;
== Validation Error Messages ==&lt;br /&gt;
The list of error messages that can be created during the validation process is at [[:Category:Validation_Errors|Validation Errors]].&lt;br /&gt;
&lt;br /&gt;
== Recent Validation Changes ==&lt;br /&gt;
The following changes are reasonably new additions that many users may not yet have experience with. They are included here to highlight the requirements and to advise users that they are legitimate problems.&lt;br /&gt;
&lt;br /&gt;
* Content is now loaded by the game engine during validation, in addition to the existing practice of checking the content files for known errors. This means that some number of errors which previously only occurred at runtime will now be detected during validation.&lt;br /&gt;
* Limited sanity checks for incorrect use of [[material sharing]] are now present.&lt;br /&gt;
&lt;br /&gt;
== Recent Additions ==&lt;br /&gt;
The following changes are recent additions to the config format.&lt;br /&gt;
&lt;br /&gt;
TBD.&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=HowTo/Make_your_first_Trainz_Asset&amp;diff=13128</id>
		<title>HowTo/Make your first Trainz Asset</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=HowTo/Make_your_first_Trainz_Asset&amp;diff=13128"/>
		<updated>2018-06-06T03:27:23Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;&amp;lt;span style=&amp;quot;color:#ff0000&amp;quot;&amp;gt;NOTE: This information is out of date.&#039;&#039;&#039;&amp;lt;/span&amp;gt; While many of the techniques here are still valid, please see the [[TRS19]] page for links to the latest content creation information.&lt;br /&gt;
&lt;br /&gt;
This is a step by step tutorial that will teach you how to create a 3D model, create the Level of Detail (lower resolution) versions of the model, and import it into Trainz. &lt;br /&gt;
&lt;br /&gt;
== Determine what software you&#039;ll need ==&lt;br /&gt;
&lt;br /&gt;
Before you start you will need:&lt;br /&gt;
&lt;br /&gt;
* A copy of Trainz Simulator 12 (or technically, a copy of Trainz).&lt;br /&gt;
&lt;br /&gt;
* A copy of 3DS Max studio that has a supported Trainz Exporter. We are using 3DS Max 2008 in this example. Information on all exporters can be found [[Max Exporters|here]] and the download files can be found on the [[Downloads]] page.&lt;br /&gt;
&lt;br /&gt;
* To setup the exporter in 3DS Max you will want to extract the .zip file and then place the correct versions &amp;quot;JetExporter.dle&amp;quot; file into the plugins directory of your installed 3DS Max. For example, it might look like &amp;quot;C:\Program Files (x86)\Autodesk\3ds Max 2008\plugins&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
* (OPTIONAL SOFTWARE) [http://quixel.se/ndo/ nDo2] is a Photoshop plugin that makes creating normal (or bump) maps for your models a breeze.&lt;br /&gt;
&lt;br /&gt;
== How to setup the model and materials in 3DS Max ==&lt;br /&gt;
&lt;br /&gt;
===Recommended Reading===&lt;br /&gt;
&lt;br /&gt;
Before you start modelling you might want to read [[Modeling Trains for Trainz]] as it explains things like setting up the Unit Scale correctly to model in and a few other good pointers.&lt;br /&gt;
&lt;br /&gt;
===Create Highest LOD First===&lt;br /&gt;
Model your object at the highest detail required to look good up close. The distance that the highest level of detail model (LOD 0) will be seen in Trainz could be from 0 up to about 40 meters away from the camera.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:lod_0.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Additional LOD Levels===&lt;br /&gt;
Continue making a further 2 lower level detail models (LODs) for the exact same item you are modelling.&lt;br /&gt;
The 2nd highest detail model (LOD 1) is required to still look decent at 40 up to 80 meters away. You will want to remove about 50% of the original polygons found in the highest detailed model (LOD 0 - above).&lt;br /&gt;
The 3rd highest detail model (LOD 2) is required to still look decent at 80 up to 160 meters away. You will want to remove about 50% of the original polygons found in the 2nd highest detailed model (LOD 1).&lt;br /&gt;
&lt;br /&gt;
This is an example of the LOD 0 detailed versus LOD 1 and LOD 2 detail.&lt;br /&gt;
&lt;br /&gt;
[[File:lod_0_v_lod_2.jpg]] [[File:lod_0_v_lod_2_distance.jpg]]&lt;br /&gt;
&lt;br /&gt;
===LOD 3 - Extremely low poly LOD===&lt;br /&gt;
&lt;br /&gt;
Create an extremely low detailed model (LOD 3) to be used in the distance. In this example we are saying this model will be used 160 meters and beyond. Usually the lowest detail model which is used in the distance is a billboard (2 polygon object) or a cube type object (8 - 10 polygons). Whatever you choose, this detail must use as fewer polygons as possible.&lt;br /&gt;
&lt;br /&gt;
[[File:lod_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
===Materials===&lt;br /&gt;
Setting up the materials is pretty easy but you&#039;ll need to work out what type of material (look) you want for your object. All the Trainz materials available for you to use in 3DS Max can be found [[Material Types|here]] and you&#039;ll also want to read about [[Exporting with 3D Studio Max]] for additional lighting material setup details.&lt;br /&gt;
&lt;br /&gt;
You should setup your image files as .TGA files and save them as 32-bits/pixel without &amp;quot;Compress (RLE)&amp;quot; checked. We are using Photoshop in the example below:&lt;br /&gt;
&lt;br /&gt;
[[File:32-bits.jpg]]&lt;br /&gt;
&lt;br /&gt;
== How to create the Trainz Asset and import it into Trainz Content Manager ==&lt;br /&gt;
Once your models have LOD and materials applied, it&#039;s time to export from 3DS Max and get them into Trainz!&lt;br /&gt;
&lt;br /&gt;
===Exporting your model===&lt;br /&gt;
To export into Trainz format you will want to Click File -&amp;gt; Export, Save as type, drop down and select Trainz format (*.IM, *.KIN)&lt;br /&gt;
&lt;br /&gt;
===Creating a Trainz Config File===&lt;br /&gt;
When you have exported all your different LODs from 3DS Max to a folder (all your .IM and .texture.txt files, without errors), you are ready to use Content Manager to import your object into Trainz.&lt;br /&gt;
&lt;br /&gt;
First you need to create a [[config.txt file]] - this file holds all the information the the Trainz code uses to manage your asset in the game. To do this, create a new file in the folder named &amp;quot;config.txt&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;[[KIND TrainzBaseSpec]]&amp;quot; and &amp;quot;[[Content Configuration]]&amp;quot; pages give an enormous amount of information on everything to do with the config.txt options. Reading the Content Configuration pages can be very overwhelming to start with so below we have created the minimum information a config.txt file needs to get your LOD asset working in-game. (As you gain confidence, be sure to see what else Trainz can do though as it is very powerful!)&lt;br /&gt;
&lt;br /&gt;
This is the very basic &amp;quot;scenery&amp;quot; object config.txt file. (Not to worry, we explain each part of this below)&lt;br /&gt;
&lt;br /&gt;
 kind                                    &amp;quot;scenery&amp;quot;&lt;br /&gt;
 username                                &amp;quot;Car_Example&amp;quot;&lt;br /&gt;
 trainz-build                            3.7&lt;br /&gt;
 category-class                          &amp;quot;FT&amp;quot;&lt;br /&gt;
 mesh-detail-level-count                 4&lt;br /&gt;
 mesh-table&lt;br /&gt;
 {&lt;br /&gt;
  default-lod0&lt;br /&gt;
  {&lt;br /&gt;
    mesh                                &amp;quot;car_lod_0.im&amp;quot;&lt;br /&gt;
    auto-create                         1&lt;br /&gt;
    lod-level                           0&lt;br /&gt;
  }&lt;br /&gt;
  default-lod1&lt;br /&gt;
  {&lt;br /&gt;
    mesh                                &amp;quot;car_lod_1.im&amp;quot;&lt;br /&gt;
    auto-create                         1&lt;br /&gt;
    lod-level                           1&lt;br /&gt;
  }&lt;br /&gt;
  default-lod2&lt;br /&gt;
  {&lt;br /&gt;
    mesh                                &amp;quot;car_lod_2.im&amp;quot;&lt;br /&gt;
    auto-create                         1&lt;br /&gt;
    lod-level                           2&lt;br /&gt;
  }&lt;br /&gt;
  default-lod3&lt;br /&gt;
  {&lt;br /&gt;
    mesh                                &amp;quot;car_lod_3.im&amp;quot;&lt;br /&gt;
    auto-create                         1&lt;br /&gt;
    lod-level                           3&lt;br /&gt;
  }&lt;br /&gt;
 }&lt;br /&gt;
 thumbnails&lt;br /&gt;
 {&lt;br /&gt;
  0&lt;br /&gt;
  {&lt;br /&gt;
    image                               &amp;quot;screenshot.jpg&amp;quot;&lt;br /&gt;
    width                               240&lt;br /&gt;
    height                              180&lt;br /&gt;
  }&lt;br /&gt;
 }&lt;br /&gt;
 kuid                                    &amp;lt;kuid:661281:11003&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Let&#039;s break this down to understand what each part is / does.&lt;br /&gt;
&lt;br /&gt;
 kind                                    &amp;quot;scenery&amp;quot;&lt;br /&gt;
 username                                &amp;quot;Car_Example&amp;quot;&lt;br /&gt;
 trainz-build                            3.7&lt;br /&gt;
 category-class                          &amp;quot;FT&amp;quot;&lt;br /&gt;
You will find these first 4 parameters in the config.txt file outlined in [[KIND TrainzBaseSpec]].&lt;br /&gt;
&lt;br /&gt;
====Number of LODs====&lt;br /&gt;
 mesh-detail-level-count                 4&lt;br /&gt;
This parameter is set manually. This specifies the number of LODs our content will use. If you have 2 LODs in your object then you would change the 4 to a 2. Additional information can be found here in [[KIND Mesh]].&lt;br /&gt;
&lt;br /&gt;
====Mesh Table Structure====&lt;br /&gt;
 mesh-table&lt;br /&gt;
 {&lt;br /&gt;
  default-lod0&lt;br /&gt;
  {&lt;br /&gt;
    mesh                                &amp;quot;car_lod_0.im&amp;quot;&lt;br /&gt;
    auto-create                         1&lt;br /&gt;
    lod-level                           0&lt;br /&gt;
  }&lt;br /&gt;
  default-lod1&lt;br /&gt;
  {&lt;br /&gt;
    mesh                                &amp;quot;car_lod_1.im&amp;quot;&lt;br /&gt;
    auto-create                         1&lt;br /&gt;
    lod-level                           1&lt;br /&gt;
  }&lt;br /&gt;
  default-lod2&lt;br /&gt;
  {&lt;br /&gt;
    mesh                                &amp;quot;car_lod_2.im&amp;quot;&lt;br /&gt;
    auto-create                         1&lt;br /&gt;
    lod-level                           2&lt;br /&gt;
  }&lt;br /&gt;
  default-lod3&lt;br /&gt;
  {&lt;br /&gt;
    mesh                                &amp;quot;car_lod_3.im&amp;quot;&lt;br /&gt;
    auto-create                         1&lt;br /&gt;
    lod-level                           3&lt;br /&gt;
  }&lt;br /&gt;
 }&lt;br /&gt;
Let&#039;s explain what we are doing with the mesh-table section. We have a container which is &#039;mesh-table&#039; with two brackets &#039;{&#039; and &#039;}&#039;. You&#039;ll notice everything contained within these brackets for the mesh-table so it knows what parameters are to be part of the mesh-table section.&lt;br /&gt;
&lt;br /&gt;
Inside the first &#039;{&#039; bracket we find another section called default-lod0 and it too has it&#039;s own &#039;{&#039; and &#039;}&#039; brackets as it too has parameters that it controls. You will notice there are 4 &#039;default-lod&#039; sections that look very similar. Each of the &#039;default-lod&#039; sections are a level of detail that is manually specified. &lt;br /&gt;
&lt;br /&gt;
In the first section &#039;default-lod0&#039; we have the &#039;mesh&#039; parameter and have given it our highest detailed mesh called &amp;quot;car_lod_0.im&amp;quot;. We also specify another parameter called &#039;auto-create&#039; which tells Trainz to make this object visible as soon as the mesh loads, so we set this to &#039;1&#039;. &lt;br /&gt;
&lt;br /&gt;
Following those 2 parameters we have a final parameter called &#039;lod-level&#039; with the value of &#039;0&#039;. This means that our &#039;mesh&#039; which we specified as &amp;quot;car_lod_0.im&amp;quot; is to be used as &#039;lod-level&#039; 0. NOTE: LOD detail reduces the higher the lod-level number specified, e.g. &#039;lod-level 0&#039; should be the highest detailed polygon model you are using. &#039;lod-level 1&#039; should use the model that has significantly less polygons than the one being used in &#039;lod-level 0&#039; ... and so on. You only need to specify a number of &#039;default-lod&#039; sections that is equal to the number of LOD meshes you have exported. Also worth noting, the &#039;default-lod&#039; section names are not used by the game itself, but they have to be unique. The &#039;lod-level&#039; parameter is what determines the level of detail for that section, not the &#039;default-lod0&#039; name.&lt;br /&gt;
&lt;br /&gt;
The mesh-table section has a lot of parameters to choose from. Additional parameters can be found here &amp;quot;[[%22mesh-table%22_Container]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====Thumbnails====&lt;br /&gt;
 thumbnails&lt;br /&gt;
 {&lt;br /&gt;
  0&lt;br /&gt;
  {&lt;br /&gt;
    image                               &amp;quot;screenshot.jpg&amp;quot;&lt;br /&gt;
    width                               240&lt;br /&gt;
    height                              180&lt;br /&gt;
  }&lt;br /&gt;
 }&lt;br /&gt;
The thumbnails section can be found here &amp;quot;[[KIND_TrainzBaseSpec]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Simply create a 240 wide by 180 high .jpg image of your object and save it in the directory where you have your .IM, .texture.txt and config.txt files.&lt;br /&gt;
&lt;br /&gt;
Here is the car example:&lt;br /&gt;
&lt;br /&gt;
[[File:car_screenshot.jpg]]&lt;br /&gt;
&lt;br /&gt;
====Creating a KUID====&lt;br /&gt;
&lt;br /&gt;
 kuid                                    &amp;lt;kuid:661281:11003&amp;gt;&lt;br /&gt;
This KUID is the unique ID for your Trainz Asset. The first number &amp;quot;661281&amp;quot; is your user ID (if you&#039;re not sure, see the next section on how to find your UserID). The second number &amp;quot;11003&amp;quot; is any old number we want BUT, it has to be unique to your content! A good idea is to come up with a numbering system such as having 0 - 1000 for locos, 1001 to 5000 for scenery objects and so on. For detailed information can be found on &amp;quot;[[KUID]]s&amp;quot; page.&lt;br /&gt;
&lt;br /&gt;
====Finding your User ID====&lt;br /&gt;
In Content Manager, once you login to your [[Planet Auran account]], you&#039;ll find your User ID by going to File -&amp;gt; Settings, then click on the Internet tab. You will need this number to create any Trainz assets as it is used in the unique number that each asset requires (called a [[KUID]].)&lt;br /&gt;
&lt;br /&gt;
[[File:your_kuid.jpg]]&lt;br /&gt;
===Importing Content into Trainz===&lt;br /&gt;
&lt;br /&gt;
Now that you have everything in a folder ready to go, you can drag that folder onto Trainz Content Manager to start to get this content into Trainz.&lt;br /&gt;
&lt;br /&gt;
[[File:folder.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If the files exist in Content Manager already, a prompted will show asking if you want to write over the files. If you know the files existed previously because you put them there, you will always want to say &amp;quot;Overwrite All&amp;quot; but if you are not sure, best to &amp;quot;Skip All&amp;quot; and investigate which content you are actually copying over.&lt;br /&gt;
&lt;br /&gt;
[[File:overwrite.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Once you copy over the top of the content you will see a couple of warnings. You can ignore these if they are the following:&lt;br /&gt;
* &amp;quot;Asset [KUID] is already installed.&amp;quot;&lt;br /&gt;
* &amp;quot;Replaced previously installed an open for edit asset [ASSET NAME]&amp;quot;&lt;br /&gt;
&lt;br /&gt;
[[File:warnings.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Once you have no errors with the import you can commit your assets by right clicking on the asset and going to &amp;quot;Edit&amp;quot; -&amp;gt; &amp;quot;Commit&amp;quot; or using the CTRL+M shortcut key (you will use this a lot so might be good to learn the shortcuts)&lt;br /&gt;
&lt;br /&gt;
[[File:commit.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Import Errors====&lt;br /&gt;
Make sure you don&#039;t get any errors after you commit your Trainz asset. You will see the big exclamation mark icon appear if your Trainz asset has errors.&lt;br /&gt;
&lt;br /&gt;
[[File:commit_with_errors.jpg]]&lt;br /&gt;
&lt;br /&gt;
To find out what the errors are you right click on the Trainz asset and go to &amp;quot;View Errors &amp;amp; Warnings&amp;quot;. You must fix all errors before the asset will appear in Trainz. If you can&#039;t work out how to solve an error, check out the &amp;quot;Potential Problems&amp;quot; section below.&lt;br /&gt;
&lt;br /&gt;
[[File:commit_with_errors_view.jpg]]&lt;br /&gt;
&lt;br /&gt;
== Finding the new Asset in Trainz Simulator 12 ==&lt;br /&gt;
&lt;br /&gt;
Time to load up Trainz and give this content a spin! When you get into Trainz, click on Create Route to start a new route.&lt;br /&gt;
&lt;br /&gt;
Depending on what asset type (kind) you have specified will determine where you will find you asset. We have created a &amp;quot;Scenery&amp;quot; type so we will find this in the &amp;quot;Objects&amp;quot; -&amp;gt; &amp;quot;Object Mode&amp;quot; (or hit &amp;quot;O&amp;quot; for the shortcut key). Place one of these in your scene and zoom your camera to view all the LODs change as your distance from the object changes. If you can barely notice the level of detail changing (but it does actually work!) then you have done a really good job of making the LOD models change seamlessly.&lt;br /&gt;
&lt;br /&gt;
In the examples below to make it very easy for you to spot the LOD change, we have given the highest detail (LOD 0) a RED dot, the medium detail (LOD 1) an orange color and the lowest detail (LOD 3) a green color. We have skipped LOD 2 in this instance but it is recommended to have 4 LODs to a high detailed model if possible.&lt;br /&gt;
&lt;br /&gt;
LOD 0 - In Trainz Surveyor&lt;br /&gt;
&lt;br /&gt;
[[File:surveyor_lod_0.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
LOD 1 - In Trainz Surveyor&lt;br /&gt;
&lt;br /&gt;
[[File:surveyor_lod_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
LOD 3 - In Trainz Surveyor&lt;br /&gt;
&lt;br /&gt;
[[File:surveyor_lod_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
==Potential Problems==&lt;br /&gt;
&lt;br /&gt;
To see additional stats while working in Surveyor to help determine potential problems with your Trainz asset or even just route creation in general using others assets, you might want to take a look here &amp;quot;[[Runtime_Performance_Statistics]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Furthermore, you can also find some really good information about content creation on the [http://forums.auran.com/trainz/blog.php?769929-Trainz-Developer-Blog Trainz Developer Blog].&lt;br /&gt;
&lt;br /&gt;
If you have read all there is to read on this wiki, and are still having problems getting this tutorial or other content working, then you probably should join in the discussions on on our Trainz Community on the [http://forums.auran.com/trainz/index.php Trainz Forums]. The forums are very active and if you show you are keen to learn, the people are very helpful!&lt;br /&gt;
&lt;br /&gt;
==Source Files==&lt;br /&gt;
&lt;br /&gt;
You can download the source files to the Car Example (asset folder) used in this tutorial here: [[File:Carpackage.zip]] or [http://online.ts2009.com/mediaWiki/images/d/db/Carpackage.zip here]. Please note we have not referenced the same image for all 3 LODs. In this example we are changing colors to show you the different distances the LODs pop in. You should generally try and share one diffuse texture between the different LODs so that it saves on memory and performance.&lt;br /&gt;
&lt;br /&gt;
If the source files you download look scary, don&#039;t worry! The Trainz Exporter for 3DS Max creates all those files except the &amp;quot;config.txt&amp;quot; file for you.&lt;br /&gt;
&lt;br /&gt;
Good Luck and we can&#039;t wait to see your high detailed content for Trainz (with LODs!!!).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Return to Index==&lt;br /&gt;
 &lt;br /&gt;
[[HowToGuides|&amp;lt;&amp;lt; How To Guides]]&lt;br /&gt;
&lt;br /&gt;
[[Category:How-to guides]]&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=Content_Creation&amp;diff=13127</id>
		<title>Content Creation</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=Content_Creation&amp;diff=13127"/>
		<updated>2018-06-06T03:26:49Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;These pages are intended for information-sharing between N3V employees and content creators. Information contained herein may refer to future Trainz versions or proposed functionality, and should not be construed as a promise of support. Registered users should feel free to edit content to provide additional information, or clarification and corrections to existing information. Please keep discussion to the comment areas and forums.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Content Creation Guides==&lt;br /&gt;
[[HowToGuides]] - &#039;&#039;A list of &#039;How To&#039; Guides explaining various content creation tasks.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Modeling]] - &#039;&#039;Preparing models, textures, LOD and animation.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Content Configuration]] - &#039;&#039;A reference manual covering all content types.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Scripting]] - &#039;&#039;Script programming.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Physics]] - &#039;&#039;Simulation and tuning.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Terminology]] - &#039;&#039;A summary of Trainz terms.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Route and Session Creation]] - &#039;&#039;Techniques relating to building a route and the associated gameplay sessions.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Asset Validation]] - &#039;&#039;The latest information about asset validation changes and DLS uploads.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Performance]] - &#039;&#039;The master page for all things performance-optimisation related.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==All Things Trainz==&lt;br /&gt;
&lt;br /&gt;
[[TRS19]] - &#039;&#039;The upcoming release of Trainz.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[TANE]] - &#039;&#039;The current release version of Trainz.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Trainz Release Versions]] - &#039;&#039;A history of the Trainz family.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Download Station]] - &#039;&#039;What it is, and what we&#039;re doing with it.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Content Management]] - &#039;&#039;The zen of content management.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Trainz Online]] - &#039;&#039;Detailing the in-game web experience.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Tools]] - &#039;&#039;Executables which complement the Trainz game environment.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Downloads]] - &#039;&#039;Downloadable builds and tools for development and test purposes.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==News==&lt;br /&gt;
[[Special:Recentchanges|Recent changes]] to this wiki.&lt;br /&gt;
&lt;br /&gt;
[[:Category:Feature Request|Feature Request Pages]]&lt;br /&gt;
&lt;br /&gt;
[[Special:Search|Search]] the wiki.&lt;br /&gt;
&lt;br /&gt;
[[TRS19]] Content Creator Documentation (work in progress).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Community==&lt;br /&gt;
[[Content]] - &#039;&#039;A list of Trainz content, both released and work in progress.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Routes]] - &#039;&#039;Planning and building routes in Surveyor.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Content Creation Groups]] - &#039;&#039;Third party content creation groups.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Content Creation Projects]] - &#039;&#039;Third party content creation projects.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Want to help us improve this documentation? Check out the [[:Category:TBD]] page for a list of topics which have been flagged for attention.&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=Albedo_map&amp;diff=13126</id>
		<title>Albedo map</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=Albedo_map&amp;diff=13126"/>
		<updated>2018-06-06T03:26:01Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The albedo map defines the base RGB color of each [[texel]]. It is configured using a [[texture.txt file]] which is directly referenced from the material (usually within a [[mesh file]] although sometimes from the asset&#039;s [[config.txt]] directly).&lt;br /&gt;
&lt;br /&gt;
The albedo map is the [[Physically Based Rendering]] equivalent of the &#039;&#039;diffuse map&#039;&#039; used in legacy materials. At a casual glance, these fill the same role and the terms can be interchanged, however to be strictly accurate the albedo is the surface color irrespective of any lighting effects, whereas the diffuse map frequently included burned-in lighting (pre-baked [[ambient occlusion]], etc.) The albedo map should never include pre-baked lighting, as that would interfere with the correct operation of the PBR equations.&lt;br /&gt;
&lt;br /&gt;
= Color Space =&lt;br /&gt;
Unless otherwise specified by the [[Material Types|material]] in use, the RGB channels use the sRGB color space.&lt;br /&gt;
&lt;br /&gt;
= Alpha Channel =&lt;br /&gt;
It is common for (semi-)transparent materials to store the alpha blend factor (ie. opacity level) in the albedo map&#039;s alpha channel. Materials which are fully opaque may use the albedo&#039;s alpha channel for some other purpose, or not at all.&lt;br /&gt;
&lt;br /&gt;
If no alpha channel is specified, the outcome is identical to a fully white (1.0) alpha channel.&lt;br /&gt;
&lt;br /&gt;
Some legacy [[Material Types|material types]] offer automatic selection of [[alpha blending]], [[alpha masking]] or opaque rendering modes based on the contents and configuration of the albedo map. This introduces uncertainties when texture replacement is used as to what material configuration will result. [[TRS19]] materials do not attempt this, and instead rely on the content creator to select the appropriate material type.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Examples =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;TBD: See [[Normal map]] for examples.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Texture mapping]]&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=Animation&amp;diff=13125</id>
		<title>Animation</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=Animation&amp;diff=13125"/>
		<updated>2018-06-06T03:25:27Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Any [[mesh]] with a [[skeleton]] may have animations applied. Animations in Trainz are stored in the &amp;quot;*.kin&amp;quot; file format. These are created during [[FBX file]] import and are referenced in the [[&amp;quot;mesh-table&amp;quot; Container]] etc. If a mesh has a skeleton but does not have any animation applied, it will be displayed in its [[bind pose]]. Animations are not strongly tied to the mesh from which they are initially exported; they may be reused with any compatible mesh.&lt;br /&gt;
&lt;br /&gt;
= Partial Animation =&lt;br /&gt;
Multiple animations may be applied to a single mesh.&lt;br /&gt;
&lt;br /&gt;
Each animation may affect any subset of the skeleton&#039;s bones.&lt;br /&gt;
&lt;br /&gt;
Multiple animations may affect the same bones.&lt;br /&gt;
&lt;br /&gt;
Any bones unaffected by animation remain in the bind pose.&lt;br /&gt;
&lt;br /&gt;
= Idle Animations=&lt;br /&gt;
Whether an animation is actively playing/progressing or not is a separate concept from whether it is applied to the mesh. An animation which is paused but still enabled will still deform its mesh.&lt;br /&gt;
&lt;br /&gt;
= Animating Multiple Meshes =&lt;br /&gt;
An animation file may be reused for multiple meshes. Aside from a small memory saving, this does not have any performance benefits, but can help simplify complex configurations which require multiple meshes to animate simultaneously. As an example of this, a full-body humanoid figure may be animated to walk. The animation is exported. The mesh may then be broken into separate pieces (arms, torso, legs, head) which are added to the scene individually. Finally, the single original animation is applied to each of the pieces. As long as the animation is played in sync on all of the meshes, the humanoid walks as before.&lt;br /&gt;
&lt;br /&gt;
The important thing to understand here is that there are more bones in the animation than exist in any individual mesh. The animation is fully simulated for all bones, but each mesh only receives its appropriate bone transforms.&lt;br /&gt;
&lt;br /&gt;
[[Category:Modeling]]&lt;br /&gt;
[[Category:Content creation]]&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=Clutter_Effect_Layer&amp;diff=13124</id>
		<title>Clutter Effect Layer</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=Clutter_Effect_Layer&amp;diff=13124"/>
		<updated>2018-06-06T03:25:17Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The [[Clutter Effect Layer]] is an [[Effect Layer]] type which is used to render small localised ground clutter (small foliage, stones, etc.) As with all effect layers, clutter is painted onto the terrain and automatically generates appropriate geometry for the area surrounding the camera.&lt;br /&gt;
&lt;br /&gt;
= Modelling Configuration =&lt;br /&gt;
&lt;br /&gt;
Before you start looking at creating assets for Clutter Effect Layers you should have a very good knowledge on how you go about modelling efficient meshes for each LOD level and what textures you should be using for each mesh LOD. You can find an excellent reference on how to model and texture assets under the [[Art_Recommendations#Modeling_Overview|Modelling Overview]] on the Art Recommendations Trainz wiki page.&lt;br /&gt;
&lt;br /&gt;
When using a large amount of clutter objects onscreen at one time, it&#039;s best to have at least the lowest LODs (which shouldn&#039;t be very far from the camera) using a [[Texture Atlas]]. The texture atlas should be as small as it can be while maintaining good visual results (256x256 perhaps) and will hold all the images for all the assets lowest LODs. This means when the lowest LODs are showing (which should be the majority of clutter onscreen most of the time) you&#039;ll only be paying the cost of 1 material shared across all the lowest LODs. &lt;br /&gt;
&lt;br /&gt;
You will also want to share as many single textures between as many assets as possible to cut-down on draw calls where possible - If you have 3 ferns all of different sizes, don&#039;t make 3 copies of the same texture.&lt;br /&gt;
&lt;br /&gt;
You will want to make sure you understand how to create a Trainz [[Mesh Libraries|Mesh Library]] asset so you can utilise Texture Atlases and sharing of textures between multiple meshes.&lt;br /&gt;
&lt;br /&gt;
Once you start to construct your Trainz mesh library asset be sure to use the [[m.clutter]] material for all your meshes. This will allow your clutter asset to fade in and out where required. You will also want to take note about the fadeInEndDistance and fadeOutEndDistance in your [[mesh metadata file|mesh metadata files]] to get your fade transitions correct.&lt;br /&gt;
&lt;br /&gt;
== Clutter Asset Selection ==&lt;br /&gt;
There are several factors to consider when determining which assets you should put in a clutter layer:&lt;br /&gt;
&lt;br /&gt;
1. How big is the asset? Anything that has a size of ~1 meter cubed or smaller can be considered as clutter. This is not to say it must be clutter but anything larger than that you should place with the Objects tab.&lt;br /&gt;
&lt;br /&gt;
2. To get the nice fade-out transition (and fade-in if you&#039;ve configured that) your clutter asset should use the material [[m.clutter]].&lt;br /&gt;
&lt;br /&gt;
3. LODs are a MUST! If your asset has no LOD or poor LOD don&#039;t even consider using it for clutter as it will be very performance heavy.&lt;br /&gt;
&lt;br /&gt;
= Example Usage =&lt;br /&gt;
&lt;br /&gt;
[[File:clutterexample1.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
= Asset Creation =&lt;br /&gt;
The clutter effect layer is a pre-release feature and details of the asset creation techniques may change prior to release.&lt;br /&gt;
&lt;br /&gt;
You can find all the information on creating clutter assets under [[m.clutter]].&lt;br /&gt;
&lt;br /&gt;
It is strongly recommended that assets created for use in a clutter effect layer are small, relatively low polygon (100-500 polygons at highest LOD), with very efficient LOD (typically down to 5-10 polygons at lowest LOD) and using the [[m.clutter]] material type. It is possible to create very attractive and high-density scenery with well-built clutter assets. However inefficient asset creation can very quickly lead to very poor performance.&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
[[TurfFX_Effect_Layer]]&lt;br /&gt;
&lt;br /&gt;
For specific guidance how to create and paint clutter layers in Surveyor see: [[Help:Effect_Layer_Dialog]]&lt;br /&gt;
&lt;br /&gt;
Back to [[Effect_Layer]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Modeling]]&lt;br /&gt;
[[Category:Content creation]]&lt;br /&gt;
[[Category:TRS19]]&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
	<entry>
		<id>https://wiki.trainzsimulator.com/index.php?title=Effect_Layer&amp;diff=13123</id>
		<title>Effect Layer</title>
		<link rel="alternate" type="text/html" href="https://wiki.trainzsimulator.com/index.php?title=Effect_Layer&amp;diff=13123"/>
		<updated>2018-06-06T03:25:07Z</updated>

		<summary type="html">&lt;p&gt;Windwalkr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Effect Layer]]s are a new [[TRS19]] feature which offer the ability to use Surveyor to paint various effects beyond the traditional ground height and ground texture. Each effect layer typically offers a number of configuration options, including a configurable data density so that route creators can tune the outcome to their specific requirements, dedicating performance to areas which are important to their route while lowering detail and/or flexibility in other less-important areas in order to maintain high overall performance.&lt;br /&gt;
&lt;br /&gt;
= Effect Layers UI =&lt;br /&gt;
Effect Layers are configured per route. A new &amp;quot;Edit Effect Layers&amp;quot; menu item in the Surveyor main menu pops up an editing dialog which allows the route builder to add, remove, and edit effect layers. An effect layer type is selected when adding a new effect layer, and the type-specific properties for that layer may be adjusted repeatedly until the desired result is achieved. Effect layers are also named, for user convenience.&lt;br /&gt;
&lt;br /&gt;
Most properties of the effect layer are configured on a route-wide basis, however some special properties may be configured to change across the route, using data bindings.&lt;br /&gt;
&lt;br /&gt;
= Configuring Effect Layer Data Bindings =&lt;br /&gt;
Specific effect layer properties support data binding. This allows the route builder to paint (eg. using the ground height tools) the property onto the terrain, rather than setting it to a single value route-wide. For many effect types, this is used to configure the intensity of the effect at various locations on the route, although other properties and data types are also configurable in this manner.&lt;br /&gt;
&lt;br /&gt;
There is a limited amount of data reserved in the route for effect layer data bindings. It is up to the route builder to determine how best to use the available data space to best effect. Each property which supports data binding may be configured with a set resolution (higher resolutions consume more data) and precision (higher precision consumes more data). The route builder determines which effect layer need the most precise control, and dedicates the majority of the available data space to those layers.&lt;br /&gt;
&lt;br /&gt;
Adjusting data bindings is a computationally expensive operation. On a large route, this process can take a number of seconds. An uninterruptible progress indication will show during this process. It is not possible to &amp;quot;undo&amp;quot; a change to a data binding, so the route builder should save changes before editing bindings in an existing route.&lt;br /&gt;
&lt;br /&gt;
= Painting Effect Layers =&lt;br /&gt;
Once an effect layer data binding has been configured, the route builder may begin painting in the effect layer. Surveyor&#039;s &amp;quot;Topology - Advanced&amp;quot; tab offers a new &amp;quot;Effect Layer&amp;quot; picker which allows the route builder to select either &amp;quot;Ground&amp;quot; or one of the effect layer data bindings. A button is also present in this location to quick-open the relevant Effect Layer properties. After selecting the target data binding, the route builder may use the topology tools (height up, height down, etc.) to manipulate the bound data.&lt;br /&gt;
&lt;br /&gt;
As the Surveyor brush size is variable, it is possible to configure a brush which is finer than the precision of the effect layer data binding. This makes it possible to move the brush to a location where painting will have no effect (since it lies between the bound locations, rather than overlapping one or more). In this scenario, the brush will turn red to indicate that painting will have no effect. The route builder must either increase the brush size, or move the brush to a location which overlaps one of the bound locations. Alternatively, the user can consider adjusting the data bindings to have a higher resolution, at the expense of increase data usage.&lt;br /&gt;
&lt;br /&gt;
= Effect Layer Types =&lt;br /&gt;
The current effect layer types are supported:&lt;br /&gt;
&lt;br /&gt;
* [[Clutter Effect Layer]] - for ground clutter such as rocks and foliage.&lt;br /&gt;
* [[TurfFX Effect Layer]] - for various types of grass and grass-like flora.&lt;br /&gt;
&lt;br /&gt;
[[Category:Modeling]]&lt;br /&gt;
[[Category:Content creation]]&lt;br /&gt;
[[Category:TRS19]]&lt;/div&gt;</summary>
		<author><name>Windwalkr</name></author>
	</entry>
</feed>