├── .gitignore ├── .vscode └── settings.json ├── GeneralInfo.md ├── README.md ├── blender_addon ├── __init__.py ├── binreader.py ├── lib_run8 │ ├── run8_common.py │ ├── run8_tilescenery.py │ └── run8_tr2.py ├── terrain │ ├── ter.py │ ├── terrain_utils.py │ ├── tr2.py │ ├── tr2_kaitai.py │ ├── tr3.py │ └── tr4.py ├── terrain_importer.py └── utils.py ├── blender_scripts ├── .gitignore ├── README.md ├── autocomplete │ └── README.md ├── avatar_export.py ├── avatar_import.py ├── binstream.py ├── model_export.py ├── model_import.py └── terrain_import.py ├── docs ├── README.md ├── TKB.md ├── ai_signal_database.md ├── ai_special_locations.md ├── ai_track_speed_database.md ├── avatar.md ├── common.md ├── key_settings.md ├── old │ ├── AISignalDatabase.md │ ├── AISpecialLocations.md │ ├── AITrackSpeed.md │ ├── Avatar.md │ ├── BlockDetectorDatabase.md │ ├── CarSpewerDatabase.md │ ├── CommTowerDatabase.md │ ├── Common.md │ ├── DefectDetectorList.md │ ├── DispatcherBlockLightDatabase.md │ ├── DispatcherSignalControllerDatabase.md │ ├── DispatcherSwitchIconDatabase.md │ ├── HornBellConfiguration.md │ ├── Hump.md │ ├── HumpControllerList.md │ ├── IndustryConfiguration.md │ ├── MilepostDatabase.md │ ├── Model.md │ ├── README.md │ ├── RoadDatabase.md │ ├── Signal.md │ ├── Stars4.md │ ├── TKB.md │ ├── Terrain.md │ ├── TrackDatabase.md │ ├── Traffic.md │ └── XNG.md ├── service_area_database.md ├── settings.md ├── stars4.md ├── tilescenery.md ├── tr2.md └── traffic.md ├── lib └── CS │ └── Run8 │ ├── .gitignore │ ├── Installer │ ├── Environment.wxs │ ├── Folders.wxs │ ├── Installer.wixproj │ ├── Package.en-us.wxl │ ├── Package.wxs │ └── assets │ │ └── License.rtf │ ├── LibRun8 │ ├── Common │ │ ├── Class252.cs │ │ ├── DecalLoader.cs │ │ ├── DispatcherLight.cs │ │ ├── Int4.cs │ │ ├── LightLoader.cs │ │ ├── Matrix.cs │ │ ├── ModelObject.cs │ │ ├── ModelObjectDefinition.cs │ │ ├── ProceduralVegetation.cs │ │ ├── Quaternion.cs │ │ ├── Rectangle.cs │ │ ├── SceneryAssetLoader.cs │ │ ├── TileIndex.cs │ │ ├── Vector2.cs │ │ ├── Vector3.cs │ │ ├── Vector4.cs │ │ └── VertexStruct.cs │ ├── Formats │ │ ├── AISignalDatabase.cs │ │ ├── AITrackSpeedDatabase.cs │ │ ├── BlockDetectorDatabase.cs │ │ ├── CarSpewerDatabase.cs │ │ ├── CommTowerDatabase.cs │ │ ├── DefectDetector.cs │ │ ├── DefectDetectorList.cs │ │ ├── DispatcherLightBlockDatabase.cs │ │ ├── DispatcherSignalControllerDatabase.cs │ │ ├── DispatcherSwitchIconDatabase.cs │ │ ├── FileFormat.cs │ │ ├── HumpConfigDatabase.cs │ │ ├── HumpControllerList.cs │ │ ├── Model.cs │ │ ├── RoadDatabase.cs │ │ ├── Signal.cs │ │ ├── Stars4.cs │ │ ├── Terrain │ │ │ ├── Chunk.cs │ │ │ ├── ChunkStitcher.cs │ │ │ ├── ETileType.cs │ │ │ ├── Terrain.cs │ │ │ ├── TerrainTile.cs │ │ │ ├── TerrainTileLoadData.cs │ │ │ ├── Tr2Loader.cs │ │ │ └── Tr4Loader.cs │ │ ├── TileScenery.cs │ │ ├── TrackDatabase.cs │ │ └── XNG.cs │ ├── LibRun8.csproj │ └── Utils │ │ ├── BinaryReaderExtensions.cs │ │ ├── BinaryWriterExtensions.cs │ │ ├── Collada141.cs │ │ ├── ColladaUtils.cs │ │ ├── R8String.cs │ │ ├── Texture.cs │ │ ├── TileUtil.cs │ │ └── Utils.cs │ ├── MappingTest │ ├── ClassInfo.cs │ ├── ClassPair.cs │ ├── Extractor.cs │ ├── Labeling.cs │ ├── MappingTest.csproj │ ├── MethodInfo.cs │ ├── PairGenerator.cs │ ├── Program.cs │ └── Properties │ │ └── launchSettings.json │ ├── ModelLoaderTest │ ├── Class141.cs │ ├── Class251.cs │ ├── Class252.cs │ ├── Class678.cs │ ├── ModelLoaderTest.csproj │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── Struct7.cs │ └── VertexPositionNormalTexture.cs │ ├── R8Explorer │ ├── FileFilterManager.cs │ ├── MainForm.Designer.cs │ ├── MainForm.cs │ ├── MainForm.resx │ ├── Program.cs │ ├── R8Explorer.csproj │ └── Run8Version.cs │ ├── RN8ToObj │ ├── ColladaConverter.csproj │ ├── Program.cs │ └── Properties │ │ └── launchSettings.json │ ├── Run8.sln │ ├── Test │ ├── Program.cs │ └── Test.csproj │ └── TextureTools │ ├── Program.cs │ ├── Properties │ └── launchSettings.json │ └── TextureTool.csproj ├── misc ├── README.md ├── ksy │ ├── README.md │ ├── compile.bat │ ├── gen_docs.bat │ ├── generate_docs.py │ ├── ksy │ │ ├── ai_signal_database.ksy │ │ ├── ai_special_locations.ksy │ │ ├── ai_track_speed_database.ksy │ │ ├── avatar.ksy │ │ ├── common.ksy │ │ ├── key_settings.ksy │ │ ├── service_area_database.ksy │ │ ├── settings.ksy │ │ ├── stars4.ksy │ │ ├── tilescenery.ksy │ │ ├── tr2.ksy │ │ └── traffic.ksy │ ├── lib_run8 │ │ ├── kaitai │ │ │ ├── ai_signal_database.py │ │ │ ├── ai_special_locations.py │ │ │ ├── ai_track_speed_database.py │ │ │ ├── avatar.py │ │ │ ├── common.py │ │ │ ├── key_settings.py │ │ │ ├── service_area_database.py │ │ │ ├── settings.py │ │ │ ├── stars4.py │ │ │ ├── terrain_tr2.py │ │ │ ├── tile_scenery.py │ │ │ ├── tr2.py │ │ │ └── traffic.py │ │ ├── string_utils.py │ │ └── visualizer.py │ └── test.py ├── read_tkb.py └── terrain_exporter │ ├── generate_tiles.py │ ├── index.html │ ├── rename.py │ ├── terrain-generator.py │ └── view.py └── misc_scripts ├── binreader.py ├── binwriter.py ├── custom_device_reader.py ├── custom_device_writer.py ├── gen_terrain_tr2.py ├── get_latlon_center.py ├── obj_to_rn8.py ├── parse_tr2.py ├── parse_tr4.py ├── skydome_test.py ├── split_geotif.py ├── structs.py ├── structs2.py ├── tr4_to_tr2.py └── updater.py /.gitignore: -------------------------------------------------------------------------------- 1 | **/**/Samples/* 2 | __pycache__ 3 | *.dae 4 | *.obj 5 | *.rn8 6 | *.r8 7 | *.fbx 8 | *.tr2 9 | *.tr3 10 | *.ter 11 | *.tr4 12 | *.bin 13 | *.tiff 14 | *.tif -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.analysis.extraPaths": [ 3 | "./blender_scripts/autocomplete" 4 | ] 5 | } -------------------------------------------------------------------------------- /GeneralInfo.md: -------------------------------------------------------------------------------- 1 | # Misc Info 2 | Valid up to: `Update9` 3 | 4 | ## Regions 5 | - SouthernCA 6 | - HRS_Southeast 7 | - SelkirkRegion 8 | - NorthernCA 9 | - Pennsylvania 10 | 11 | ## Routes 12 | | Route Name | ID | Region | 13 | | ---------------------- | --- | ---------------------- | 14 | | BNSF_MojaveSub | 100 | SouthernCA | 15 | | BNSF_NeedlesSub | 110 | SouthernCA | 16 | | BNSF_CajonSub | 120 | SouthernCA | 17 | | BNSF_SeligmanSub | 130 | SouthernCA | 18 | | CSX_ALine | 140 | HRS_Southeast | 19 | | BarstowYermo | 150 | SouthernCA | 20 | | CSX_SelkirkTerminal | 170 | SelkirkRegion | 21 | | BNSF_SanBernardinoSub | 200 | SouthernCA | 22 | | CSX_Waycross | 210 | HRS_Southeast | 23 | | CSX_Fitzgerald | 230 | HRS_Southeast | 24 | | CSX_MohawkSub | 240 | SelkirkRegion | 25 | | BNSF_BakersfieldSub | 250 | SouthernCA | 26 | | SP-UP_RosevilleSub | 260 | NorthernCA | 27 | | NS_PittsburghLine_East | 290 | Pennsylvania | 28 | | ArvinOakCreekBranches | 310 | SouthernCA | 29 | | TronaRailway | 320 | SouthernCA | 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Run8 Train Simulator V3 Reverse Engineering 2 | 3 | This repository contains reverse engineered documentation about various Run8 V3 file formats and file parsers. This information is intended for modding. 4 | 5 | [/docs](/docs) - Contains file format specs 6 | 7 | [GeneralInfo.md](/GeneralInfo.md) - Contains misc info such as routes 8 | 9 | [/Run8](/Run8) - C# Library for working with file formats 10 | 11 | [/blender_scripts](/blender_scripts) - Import/Export scripts for Blender 3.x 12 | 13 | ### Progress 14 | 15 | - [ ] AISignalDatabase.r8 (Yes, but low accuracy, will come back to it) 16 | - [ ] AISpecialLocations.r8 17 | - [ ] AITrackSpeedDatabase.r8 (Yes, but low accuracy, will come back to it) 18 | - [x] BlockDetectorDatabase.r8 19 | - [x] CarSpewerDatabase.r8 20 | - [x] CommTowerDatabase.r8 21 | - [ ] DarkSignalDatabase.r8 22 | - [x] DefectDetectorList.r8 23 | - [x] DispatcherBlockLightDatabase.r8 24 | - [x] DispatcherSignalControllerDatabase.r8 25 | - [x] DispatcherSwitchIconDatabase.r8 26 | - [ ] DispatchLabelConfig.r8 27 | - [ ] DispatchNextScreenConfig.r8 28 | - [x] HumpControllerList.r8 29 | - [x] Hump.r8 30 | - [ ] MilepostDatabase.r8 31 | - [ ] RoadDatabase.r8 32 | - [ ] ServiceAreaDatabase.r8 33 | - [ ] SignalHeadDatabase.r8 34 | - [x] TrackDatabase.r8 35 | - [ ] TunnelConfiguration.r8 36 | - [ ] XingDetectorList.r8 37 | - [ ] XingGateDatabase.r8 38 | - [ ] Industry Configuration (.ind) 39 | - [ ] Traffic.r8 40 | - [ ] Tile Scenery (x_y.rn8) 41 | - [ ] Tile Scenery Vegetation (x_y.veg) 42 | - [ ] Terrain Tiles 2 (x_y.tr2) 43 | - [ ] Terrain Tiles 3 (x_y.tr3) 44 | - [ ] Terrain Tiles 4 (x_y.tr4) 45 | - [ ] HornBellConfiguration.r8 46 | - [ ] 3D Model (.rn8) (Partially, implementations are very crude and barely working) 47 | - [ ] Texture (.tx8) 48 | - [ ] Avatars (Partially, implementations are very crude and barely working) 49 | - [x] Shaders/Effects (.tkb) 50 | - .xsb (XACT Sound Bank) 51 | - .xwb (XACT Wave Bank; `unxwb` from http://aluigi.altervista.org/papers.htm) 52 | - [x] Signal (.sig) 53 | - [ ] Run8Settings.r8 54 | - [x] stars4.r8 55 | - [x] Crossing Gate (.xng) 56 | - [ ] Timetable.xnb (Microsoft XNA) 57 | - [ ] .xnb (Microsoft XNA, can apparently store data and images) 58 | -------------------------------------------------------------------------------- /blender_addon/__init__.py: -------------------------------------------------------------------------------- 1 | # This program is free software; you can redistribute it and/or modify 2 | # it under the terms of the GNU General Public License as published by 3 | # the Free Software Foundation; either version 3 of the License, or 4 | # (at your option) any later version. 5 | # 6 | # This program is distributed in the hope that it will be useful, but 7 | # WITHOUT ANY WARRANTY; without even the implied warranty of 8 | # MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 9 | # General Public License for more details. 10 | # 11 | # You should have received a copy of the GNU General Public License 12 | # along with this program. If not, see . 13 | 14 | bl_info = { 15 | "name": "io_run8", 16 | "author": "Puyodead1", 17 | "description": "", 18 | "blender": (4, 1, 1), 19 | "version": (0, 0, 1), 20 | "location": "", 21 | "warning": "", 22 | "category": "Generic", 23 | } 24 | 25 | from . import terrain_importer 26 | 27 | 28 | def register(): 29 | terrain_importer.register() 30 | 31 | 32 | def unregister(): 33 | ... 34 | # terrain_importer.unregister() 35 | -------------------------------------------------------------------------------- /blender_addon/lib_run8/run8_common.py: -------------------------------------------------------------------------------- 1 | # This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild 2 | 3 | import kaitaistruct 4 | from kaitaistruct import KaitaiStruct, KaitaiStream, BytesIO 5 | 6 | 7 | if getattr(kaitaistruct, 'API_VERSION', (0, 9)) < (0, 9): 8 | raise Exception("Incompatible Kaitai Struct Python API: 0.9 or later is required, but you have %s" % (kaitaistruct.__version__)) 9 | 10 | class Run8Common(KaitaiStruct): 11 | def __init__(self, _io, _parent=None, _root=None): 12 | self._io = _io 13 | self._parent = _parent 14 | self._root = _root if _root else self 15 | self._read() 16 | 17 | def _read(self): 18 | pass 19 | 20 | class Vector2(KaitaiStruct): 21 | def __init__(self, _io, _parent=None, _root=None): 22 | self._io = _io 23 | self._parent = _parent 24 | self._root = _root if _root else self 25 | self._read() 26 | 27 | def _read(self): 28 | self.x = self._io.read_f4le() 29 | self.y = self._io.read_f4le() 30 | 31 | 32 | class Tilexz(KaitaiStruct): 33 | def __init__(self, _io, _parent=None, _root=None): 34 | self._io = _io 35 | self._parent = _parent 36 | self._root = _root if _root else self 37 | self._read() 38 | 39 | def _read(self): 40 | self.x = self._io.read_s4le() 41 | self.z = self._io.read_s4le() 42 | 43 | 44 | class CsString(KaitaiStruct): 45 | def __init__(self, _io, _parent=None, _root=None): 46 | self._io = _io 47 | self._parent = _parent 48 | self._root = _root if _root else self 49 | self._read() 50 | 51 | def _read(self): 52 | self.len = self._io.read_u1() 53 | self.value = (self._io.read_bytes(self.len)).decode(u"UTF-8") 54 | 55 | 56 | class Matrix4(KaitaiStruct): 57 | def __init__(self, _io, _parent=None, _root=None): 58 | self._io = _io 59 | self._parent = _parent 60 | self._root = _root if _root else self 61 | self._read() 62 | 63 | def _read(self): 64 | self.m11 = self._io.read_f4le() 65 | self.m12 = self._io.read_f4le() 66 | self.m13 = self._io.read_f4le() 67 | self.m14 = self._io.read_f4le() 68 | self.m21 = self._io.read_f4le() 69 | self.m22 = self._io.read_f4le() 70 | self.m23 = self._io.read_f4le() 71 | self.m24 = self._io.read_f4le() 72 | self.m31 = self._io.read_f4le() 73 | self.m32 = self._io.read_f4le() 74 | self.m33 = self._io.read_f4le() 75 | self.m34 = self._io.read_f4le() 76 | self.m41 = self._io.read_f4le() 77 | self.m42 = self._io.read_f4le() 78 | self.m43 = self._io.read_f4le() 79 | self.m44 = self._io.read_f4le() 80 | 81 | 82 | class Vector3(KaitaiStruct): 83 | def __init__(self, _io, _parent=None, _root=None): 84 | self._io = _io 85 | self._parent = _parent 86 | self._root = _root if _root else self 87 | self._read() 88 | 89 | def _read(self): 90 | self.x = self._io.read_f4le() 91 | self.y = self._io.read_f4le() 92 | self.z = self._io.read_f4le() 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /blender_addon/lib_run8/run8_tilescenery.py: -------------------------------------------------------------------------------- 1 | # This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild 2 | 3 | import kaitaistruct 4 | from kaitaistruct import KaitaiStruct, KaitaiStream, BytesIO 5 | from .run8_common import Run8Common 6 | 7 | if getattr(kaitaistruct, 'API_VERSION', (0, 9)) < (0, 9): 8 | raise Exception("Incompatible Kaitai Struct Python API: 0.9 or later is required, but you have %s" % (kaitaistruct.__version__)) 9 | 10 | class Run8Tilescenery(KaitaiStruct): 11 | def __init__(self, _io, _parent=None, _root=None): 12 | self._io = _io 13 | self._parent = _parent 14 | self._root = _root if _root else self 15 | self._read() 16 | 17 | def _read(self): 18 | self.num_assets = self._io.read_s4le() 19 | self.assets = [] 20 | for i in range(self.num_assets): 21 | self.assets.append(Run8Tilescenery.Asset(self._io, self, self._root)) 22 | 23 | 24 | class Asset(KaitaiStruct): 25 | def __init__(self, _io, _parent=None, _root=None): 26 | self._io = _io 27 | self._parent = _parent 28 | self._root = _root if _root else self 29 | self._read() 30 | 31 | def _read(self): 32 | self.num_decals = self._io.read_s4le() 33 | self.decals = [] 34 | for i in range(self.num_decals): 35 | self.decals.append(Run8Tilescenery.Decal(self._io, self, self._root)) 36 | 37 | self.disregard_bounding_test = self._io.read_bits_int_be(1) != 0 38 | self._io.align_to_byte() 39 | self.model_name = Run8Common.CsString(self._io, self, self._root) 40 | self.position = Run8Common.Vector3(self._io, self, self._root) 41 | self.rotation = Run8Common.Vector3(self._io, self, self._root) 42 | self.scale = Run8Common.Vector3(self._io, self, self._root) 43 | self.tile_xz = Run8Common.Tilexz(self._io, self, self._root) 44 | 45 | 46 | class Decal(KaitaiStruct): 47 | def __init__(self, _io, _parent=None, _root=None): 48 | self._io = _io 49 | self._parent = _parent 50 | self._root = _root if _root else self 51 | self._read() 52 | 53 | def _read(self): 54 | self.color_r = self._io.read_f4le() 55 | self.color_g = self._io.read_f4le() 56 | self.color_b = self._io.read_f4le() 57 | self.num_digits = self._io.read_s4le() 58 | self.digits = [] 59 | for i in range(self.num_digits): 60 | self.digits.append(Run8Tilescenery.Digit(self._io, self, self._root)) 61 | 62 | self.offset = Run8Common.Vector3(self._io, self, self._root) 63 | self.rotation_deg = Run8Common.Vector3(self._io, self, self._root) 64 | self.size = self._io.read_f4le() 65 | self.texture_name = Run8Common.CsString(self._io, self, self._root) 66 | 67 | 68 | class Digit(KaitaiStruct): 69 | def __init__(self, _io, _parent=None, _root=None): 70 | self._io = _io 71 | self._parent = _parent 72 | self._root = _root if _root else self 73 | self._read() 74 | 75 | def _read(self): 76 | self.digit = self._io.read_s4le() 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /blender_addon/lib_run8/run8_tr2.py: -------------------------------------------------------------------------------- 1 | # This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild 2 | 3 | from typing import List 4 | import kaitaistruct 5 | from kaitaistruct import KaitaiStruct, KaitaiStream, BytesIO 6 | from .run8_common import Run8Common 7 | 8 | 9 | if getattr(kaitaistruct, 'API_VERSION', (0, 9)) < (0, 9): 10 | raise Exception("Incompatible Kaitai Struct Python API: 0.9 or later is required, but you have %s" % (kaitaistruct.__version__)) 11 | 12 | class Run8Tr2(KaitaiStruct): 13 | def __init__(self, _io, _parent=None, _root=None): 14 | self._io = _io 15 | self._parent = _parent 16 | self._root = _root if _root else self 17 | self._read() 18 | 19 | def _read(self): 20 | self.texture_1 = Run8Common.CsString(self._io, self, self._root) 21 | self.texture_2 = Run8Common.CsString(self._io, self, self._root) 22 | self.texture_3 = Run8Common.CsString(self._io, self, self._root) 23 | self.texture_4 = Run8Common.CsString(self._io, self, self._root) 24 | self.chunks: List[Run8Tr2.ChunkRow] = [] 25 | for i in range(25): 26 | self.chunks.append(Run8Tr2.ChunkRow(self._io, self, self._root)) 27 | 28 | self.lon_east = self._io.read_f4le() 29 | self.lon_west = self._io.read_f4le() 30 | self.lat_north = self._io.read_f4le() 31 | self.lat_south = self._io.read_f4le() 32 | 33 | class ChunkRow(KaitaiStruct): 34 | def __init__(self, _io, _parent=None, _root=None): 35 | self._io = _io 36 | self._parent = _parent 37 | self._root = _root if _root else self 38 | self._read() 39 | 40 | def _read(self): 41 | self.chunks: List[Run8Tr2.Chunk] = [] 42 | for i in range(25): 43 | self.chunks.append(Run8Tr2.Chunk(self._io, self, self._root)) 44 | 45 | 46 | 47 | class Chunk(KaitaiStruct): 48 | def __init__(self, _io, _parent=None, _root=None): 49 | self._io = _io 50 | self._parent = _parent 51 | self._root = _root if _root else self 52 | self._read() 53 | 54 | def _read(self): 55 | self.chunk_size = self._io.read_u4le() 56 | self.elevations: List[Run8Tr2.ElevationCol] = [] 57 | for i in range(self.chunk_size): 58 | self.elevations.append(Run8Tr2.ElevationCol(self._io, self, self._root)) 59 | 60 | 61 | 62 | class ElevationCol(KaitaiStruct): 63 | def __init__(self, _io, _parent=None, _root=None): 64 | self._io = _io 65 | self._parent = _parent 66 | self._root = _root if _root else self 67 | self._read() 68 | 69 | def _read(self): 70 | self.elevation: List[float] = [] 71 | for i in range(self._parent.chunk_size): 72 | self.elevation.append(self._io.read_f4le()) 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /blender_addon/terrain/ter.py: -------------------------------------------------------------------------------- 1 | from ..binreader import BinaryReader 2 | from .terrain_utils import ETileType, TerrainTile 3 | 4 | 5 | class TER(TerrainTile): 6 | def __init__(self, reader: BinaryReader, x: float, y: float) -> None: 7 | super().__init__(reader, ETileType.TER, x, y) 8 | 9 | self.read() 10 | 11 | def read(self): 12 | pass 13 | -------------------------------------------------------------------------------- /blender_addon/terrain/tr3.py: -------------------------------------------------------------------------------- 1 | from ..binreader import BinaryReader 2 | from .terrain_utils import ETileType, TerrainTile 3 | 4 | 5 | class TR3(TerrainTile): 6 | def __init__(self, reader: BinaryReader, x: float, y: float) -> None: 7 | super().__init__(reader, ETileType.TR3, x, y) 8 | 9 | self.read() 10 | 11 | def read(self): 12 | pass 13 | -------------------------------------------------------------------------------- /blender_addon/terrain/tr4.py: -------------------------------------------------------------------------------- 1 | from ..binreader import BinaryReader 2 | from .terrain_utils import ETileType, TerrainTile 3 | 4 | 5 | class TR4(TerrainTile): 6 | def __init__(self, reader: BinaryReader, x: float, y: float) -> None: 7 | super().__init__(reader, ETileType.TR4, x, y) 8 | 9 | self.read() 10 | 11 | def read(self): 12 | pass 13 | -------------------------------------------------------------------------------- /blender_addon/terrain_importer.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | from bpy.props import StringProperty 3 | from bpy.types import Operator 4 | from bpy_extras.io_utils import ImportHelper 5 | 6 | from .binreader import BinaryReader 7 | from .terrain.ter import TER 8 | from .terrain.tr2 import TR2 9 | from .terrain.tr2_kaitai import TR2Kaitai 10 | from .terrain.tr3 import TR3 11 | from .terrain.tr4 import TR4 12 | 13 | 14 | def import_model(context, filepath): 15 | print("\n" * 10) 16 | print("Importing Run8 Terrain Tile: %r..." % (filepath)) 17 | 18 | with open(filepath, "rb") as f: 19 | reader = BinaryReader(f) 20 | split = filepath.split("\\")[-1].split("_") 21 | x = int(split[0]) 22 | y = int(split[1].split(".")[0]) 23 | 24 | if filepath.endswith(".ter"): 25 | tile = TER(reader, x, y) 26 | elif filepath.endswith(".tr2"): 27 | # tile = TR2(reader, x, y) 28 | tile = TR2Kaitai(filepath, x, y) 29 | elif filepath.endswith(".tr3"): 30 | tile = TR3(reader, x, y) 31 | elif filepath.endswith(".tr4"): 32 | tile = TR4(reader, x, y) 33 | else: 34 | raise Exception("Unknown file type") 35 | 36 | tile.draw() 37 | 38 | return {"FINISHED"} 39 | 40 | 41 | class ImportRun8TerrainTile(Operator, ImportHelper): 42 | bl_idname = "io_run8.import_terrain_tile" 43 | bl_label = "Import Terrain Tile" 44 | 45 | filter_glob: StringProperty( 46 | default="*.tr2;*.tr2;*.tr4;*.ter", 47 | options={"HIDDEN"}, 48 | maxlen=255, # Max internal buffer length, longer would be clamped. 49 | ) # type: ignore 50 | 51 | def execute(self, context): 52 | return import_model(context, self.filepath) 53 | 54 | 55 | def run8_terrain_menu_func_import(self, context): 56 | self.layout.operator(ImportRun8TerrainTile.bl_idname, text="Run8 Terrain Tile (.tr2/.tr3/.tr4/.ter)") 57 | 58 | 59 | def register(): 60 | bpy.utils.register_class(ImportRun8TerrainTile) 61 | 62 | # prevent duplicate menu entries 63 | if hasattr(bpy.types.TOPBAR_MT_file_import.draw, "_draw_funcs"): 64 | if run8_terrain_menu_func_import.__name__ not in ( 65 | f.__name__ for f in bpy.types.TOPBAR_MT_file_import.draw._draw_funcs 66 | ): 67 | bpy.types.TOPBAR_MT_file_import.append(run8_terrain_menu_func_import) 68 | else: 69 | bpy.types.TOPBAR_MT_file_import.append(run8_terrain_menu_func_import) 70 | 71 | 72 | def unregister(): 73 | clazz = bpy.types.NodeTree.bl_rna_get_subclass_py("io_run8.import_terrain_tile") 74 | bpy.utils.unregister_class(clazz) 75 | bpy.types.TOPBAR_MT_file_import.remove(run8_terrain_menu_func_import) 76 | -------------------------------------------------------------------------------- /blender_addon/utils.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | import mathutils 4 | 5 | 6 | class Vertex(object): 7 | position: mathutils.Vector = None 8 | normal: mathutils.Vector = None 9 | uv: mathutils.Vector = None 10 | 11 | def to_json(self) -> dict: 12 | return {"position": self.position.to_tuple(), "normal": self.normal.to_tuple(), "uv": self.uv.to_tuple()} 13 | 14 | def __str__(self) -> str: 15 | return json.dumps(self.to_json()) 16 | -------------------------------------------------------------------------------- /blender_scripts/.gitignore: -------------------------------------------------------------------------------- 1 | autocomplete/* 2 | !autocomplete/README.md -------------------------------------------------------------------------------- /blender_scripts/README.md: -------------------------------------------------------------------------------- 1 | import/export scripts for blender, these would be made into an `io_scene_run8` addon at some point. 2 | 3 | I cannot for the life of me get skeleton import working for avatars. 4 | 5 | currently includes: 6 | - Avatars 7 | - Mesh Import 8 | - Mesh Export (Game crashes, skeleton and animations are required) 9 | - Railcar Models 10 | - Mesh Import -------------------------------------------------------------------------------- /blender_scripts/autocomplete/README.md: -------------------------------------------------------------------------------- 1 | You can get this from https://github.com/Korchy/blender_autocomplete/tree/master/3.4 -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | New style of file format specs, 99% of these are autogenerated from the .ksy files 2 | -------------------------------------------------------------------------------- /docs/TKB.md: -------------------------------------------------------------------------------- 1 | # Shader File (.tkb) 2 | 3 | These files are from SharpDX, they are compiled shaders/effects. I am not going to write a dedicated tool for these as they're a pain in the ass (for me at least) and the compiler already has the ability to dump the bytecode. 4 | 5 | ## Dump Bytecode 6 | 7 | You will need to get `tkfxc.exe` from SharpDX, rather then having to compile it, you can just get it precompiled from Nuget: https://www.nuget.org/api/v2/package/SharpDX/2.6.3. This will download `sharpdx.2.6.3.nupkg` which is just a zip file, you can either change the file extension from `.nupkg` to `.zip` or just open it with 7zip (or any other archive program really). The binary can be found in at `sharpdx.2.6.3\Bin\DirectX11_2-net40\tkfxc.exe`. 8 | 9 | Now you can just run: 10 | 11 | - `tkfxc.exe > bytecode.txt` 12 | -------------------------------------------------------------------------------- /docs/ai_signal_database.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # AISignalDatabase (AISignalDatabase.r8) 4 | 5 | Contains a list of AI Signals 6 | 7 | ## Root Structure 8 | 9 | | Type | ID | Description | 10 | | ---------- | ---- | ----------- | 11 | | Int32 | reserved | This field is unused | 12 | | Int32 | num_entries | | 13 | | ai_signal[] | entries | | 14 | 15 | 16 | ## Types 17 | 18 | ### ai_signal 19 | 20 | | Type | ID | Description | 21 | | ---------- | ---- | ----------- | 22 | | Int32 | reserved | This field is unused | 23 | | Int32 | num_entries | | 24 | | Int32[] | entries | | 25 | | Boolean | bool1 | | 26 | | Int32 | int1 | | 27 | | Int32 | int2 | | 28 | | Boolean | bool2 | | 29 | | class_341 | class_341_11 | | 30 | | Boolean | bool3 | | 31 | | class_341 | class_341_22 | | 32 | 33 | - 1: Only if bool2 is true 34 | - 2: Only if bool3 is true 35 | 36 | ### class_341 37 | 38 | | Type | ID | Description | 39 | | ---------- | ---- | ----------- | 40 | | Int32 | int1 | | 41 | | Int32 | int2 | | 42 | 43 | 44 | -------------------------------------------------------------------------------- /docs/ai_special_locations.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # AISpecialLocations (AISpecialLocations.r8) 4 | 5 | Contains a list of AI Special Locations 6 | 7 | ## Root Structure 8 | 9 | | Type | ID | Description | 10 | | ---------- | ---- | ----------- | 11 | | Int32 | reserved | This field is unused | 12 | | Int32 | num_entries | | 13 | | ai_special_location[] | entries | | 14 | 15 | 16 | ## Types 17 | 18 | ### ai_special_location 19 | 20 | | Type | ID | Description | 21 | | ---------- | ---- | ----------- | 22 | | Int32 | reserved | This field is unused | 23 | | [R8String](common.md#r8string) | name | | 24 | | UInt8 ([ai_special_location_type](#enums)) | type | | 25 | | Int32 | int1 | | 26 | | Int32 | int2 | | 27 | | Int32 | int3 | | 28 | | Float | float1 | | 29 | | Int32 | int4 | | 30 | | Boolean | bool1 | | 31 | 32 | 33 | ## Enums 34 | ### ai_special_location_type 35 | 36 | | Value | Name | 37 | | ------- | ------ | 38 | | spawn_point | 0 | 39 | | crew_change | 1 | 40 | | crew_change_and_hold | 2 | 41 | | passenger | 3 | 42 | | passenger_crew_change | 4 | 43 | | passenger_crew_change_and_hold | 5 | 44 | | reliquish | 6 | 45 | | passenger_reliquish | 7 | 46 | 47 | -------------------------------------------------------------------------------- /docs/ai_track_speed_database.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # AITrackSpeedDatabase (AITrackSpeedDatabase.r8) 4 | 5 | Contains a list of AI Track Speeds 6 | 7 | ## Root Structure 8 | 9 | | Type | ID | Description | 10 | | ---------- | ---- | ----------- | 11 | | Int32 | reserved | This field is unused | 12 | | Int32 | num_entries | | 13 | | ai_track_speed[] | entries | | 14 | 15 | 16 | ## Types 17 | 18 | ### ai_track_speed 19 | 20 | | Type | ID | Description | 21 | | ---------- | ---- | ----------- | 22 | | Int32 | reserved | This field is unused | 23 | | Int32 | int1 | | 24 | | Int32 | num_entries | | 25 | | class_322[] | entries | | 26 | 27 | 28 | ### class_322 29 | 30 | | Type | ID | Description | 31 | | ---------- | ---- | ----------- | 32 | | Int32 | reserved | This field is unused | 33 | | Int32 | int1 | | 34 | | Int32 | int2 | | 35 | | Int32 | int3 | | 36 | 37 | 38 | -------------------------------------------------------------------------------- /docs/avatar.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Avatar File 4 | 5 | There are currently 3 avatars: 6 | - Brian 7 | - Chris 8 | - Pablo 9 | 10 | 11 | Avatar files are 3D model files with the `rn8` file extension. Model units are in centimeters. 12 | 13 | ## Root Structure 14 | 15 | | Type | ID | Description | 16 | | ---------- | ---- | ----------- | 17 | | Int32 | vertex_count | Divide by 7 | 18 | | vertex_struct[] | vertices | | 19 | | Int32 | texture_count | Add 6 | 20 | | [C# String](common.md#cs_string)[] | textures | | 21 | | Boolean | is_ushort_index_buffer | True if the indices are stored as ushorts | 22 | | Int32 | num_index_buffer | | 23 | | UShort[] | ushort_index_buffer1 | | 24 | | Int32[] | index_buffer2 | | 25 | | Int32 | num_unknown_structs | Subtract 9 | 26 | | unknown_struct[] | unknown_structs | | 27 | | Int32 | num_skeleton_hierarchy | | 28 | | Int32[] | skeleton_hierarchy | | 29 | | Int32 | num_bone_indices | | 30 | | bone_index_struct[] | bone_indices | | 31 | | Int32 | num_bind_poses | | 32 | | [Matrix4x4](common.md#matrix4)[] | bind_poses | | 33 | | Int32 | num_inverse_bind_poses | | 34 | | [Matrix4x4](common.md#matrix4)[] | inverse_bind_poses | | 35 | | Int32 | num_animations | Seems to always be 16 | 36 | | animation_clip[] | animations | | 37 | 38 | - 1: Only if the index buffer is ushort 39 | - 2: Only if the index buffer is not ushort 40 | 41 | ## Types 42 | 43 | ### vertex_struct 44 | 45 | | Type | ID | Description | 46 | | ---------- | ---- | ----------- | 47 | | Float | reserved1 | | 48 | | Float | position_x | Multiply by 63.7f | 49 | | Float | normal_y | Divide by -1.732f | 50 | | Float | position_z | Divide by 16f | 51 | | Float | tex_coord_x | Divide by 4.8f | 52 | | Float | normal_x | Divide by 10.962f | 53 | | Float | reserved2 | | 54 | | Float | normal_z | Divide by 11.432f | 55 | | Float | tex_coord_y | Divide by 9.6f | 56 | | Float | position_y | Multiply by 6f | 57 | | UInt8 | blend_index_w | | 58 | | Float | blend_weight_z | | 59 | | UInt8 | blend_index_x | | 60 | | Float | blend_weight_y | | 61 | | UInt8 | blend_index_y | | 62 | | Float | blend_weight_w | | 63 | | UInt8 | blend_idex_z | | 64 | | Float | blend_weight_x | | 65 | 66 | 67 | ### unknown_struct 68 | 69 | | Type | ID | Description | 70 | | ---------- | ---- | ----------- | 71 | | Int32 | reserved | This field is unused | 72 | | Int32 | texture_index1 | | 73 | | Int32 | num_index_buffer | | 74 | | Int32 | start_index_location | | 75 | | Int32 | base_vertex_location | | 76 | 77 | - 1: `_mrao` is appended to the texture name 78 | 79 | ### bone_index_struct 80 | 81 | | Type | ID | Description | 82 | | ---------- | ---- | ----------- | 83 | | [C# String](common.md#cs_string) | key | | 84 | | Int32 | bone_index | | 85 | 86 | 87 | ### animation_clip 88 | 89 | | Type | ID | Description | 90 | | ---------- | ---- | ----------- | 91 | | [C# String](common.md#cs_string) | clip_name | | 92 | | Double | duration | Duration in ms | 93 | | Int32 | num_keyframes | | 94 | | animation_keyframe[] | keyframes | | 95 | 96 | 97 | ### animation_keyframe 98 | 99 | | Type | ID | Description | 100 | | ---------- | ---- | ----------- | 101 | | Int32 | bone_index | | 102 | | Double | time | | 103 | | [Matrix4x4](common.md#matrix4) | transform | | 104 | 105 | 106 | -------------------------------------------------------------------------------- /docs/common.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Common 4 | 5 | Common Types 6 | 7 | ## Encoding Strings 8 | ```c# 9 | string s = "1ST COAST RECYCLING"; 10 | byte[] bytes = Encoding.UTF8.GetBytes(s); 11 | byte[] encoded = new byte[bytes.Length * 2]; 12 | int num = 0; 13 | for (int i = 0; i < bytes.Length; i++) 14 | { 15 | encoded[num++] = (byte)(bytes[i] >> 4); 16 | encoded[num++] = (byte)(bytes[i] << 4); 17 | } 18 | ``` 19 | 20 | ## Decoding Strings 21 | ```c# 22 | byte[] encoded = ; 23 | byte[] decodedBytes = new byte[encoded.Length / 2]; 24 | int num = 0; 25 | for (int i = 0; i < decodedBytes.Length; i++) 26 | { 27 | decodedBytes[i] |= (byte)(encoded[num++] << 4); 28 | decodedBytes[i] |= (byte)(encoded[num++] >> 4); 29 | } 30 | 31 | string decodedString = Encoding.UTF8.GetString(decodedBytes); 32 | ``` 33 | 34 | ## Types 35 | 36 | ### r8string 37 | 38 | Run8 specific string format 39 | 40 | | Type | ID | Description | 41 | | ---------- | ---- | ----------- | 42 | | Int32 | len_value | Length of the encoded string, x2 len of decoded string | 43 | | Bytes | value | Decoded string | 44 | 45 | 46 | ### cs_string 47 | 48 | C# style string 49 | 50 | | Type | ID | Description | 51 | | ---------- | ---- | ----------- | 52 | | UInt8 | len | Length of the string as a 7 bit encoded int | 53 | | String | value | | 54 | 55 | 56 | ### vector2 57 | 58 | | Type | ID | Description | 59 | | ---------- | ---- | ----------- | 60 | | Float | x | | 61 | | Float | y | | 62 | 63 | 64 | ### vector3 65 | 66 | | Type | ID | Description | 67 | | ---------- | ---- | ----------- | 68 | | Float | x | | 69 | | Float | y | | 70 | | Float | z | | 71 | 72 | 73 | ### tilexz 74 | 75 | | Type | ID | Description | 76 | | ---------- | ---- | ----------- | 77 | | Int32 | x | | 78 | | Int32 | z | | 79 | 80 | 81 | ### matrix4 82 | 83 | | Type | ID | Description | 84 | | ---------- | ---- | ----------- | 85 | | Float | m11 | | 86 | | Float | m12 | | 87 | | Float | m13 | | 88 | | Float | m14 | | 89 | | Float | m21 | | 90 | | Float | m22 | | 91 | | Float | m23 | | 92 | | Float | m24 | | 93 | | Float | m31 | | 94 | | Float | m32 | | 95 | | Float | m33 | | 96 | | Float | m34 | | 97 | | Float | m41 | | 98 | | Float | m42 | | 99 | | Float | m43 | | 100 | | Float | m44 | | 101 | 102 | 103 | ### color 104 | 105 | | Type | ID | Description | 106 | | ---------- | ---- | ----------- | 107 | | UInt8 | a | | 108 | | UInt8 | r | | 109 | | UInt8 | g | | 110 | | UInt8 | b | | 111 | 112 | 113 | ### boolean 114 | 115 | This is just a bullshit stub 116 | 117 | | Type | ID | Description | 118 | | ---------- | ---- | ----------- | 119 | | UInt8 | value | | 120 | 121 | 122 | -------------------------------------------------------------------------------- /docs/key_settings.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Key Settings (Run8KeySettings.r8) 4 | 5 | Stores game keybind settings 6 | 7 | ## Root Structure 8 | 9 | | Type | ID | Description | 10 | | ---------- | ---- | ----------- | 11 | | Int32 | reserved | This field is unused | 12 | | Int32 | num_settings | | 13 | | key_setting[] | settings | | 14 | 15 | 16 | ## Types 17 | 18 | ### key_setting 19 | 20 | | Type | ID | Description | 21 | | ---------- | ---- | ----------- | 22 | | Int32 | reserved | This field is unused | 23 | | [R8String](common.md#r8string) | name | | 24 | | Int8 | enum70 | | 25 | | Int32 | num_keys | | 26 | | Int32[] | keys | | 27 | 28 | 29 | -------------------------------------------------------------------------------- /docs/old/AISignalDatabase.md: -------------------------------------------------------------------------------- 1 | # AI Signal Database (AISignalDatabase.r8) 2 | 3 | Contains a list of signals and their information 4 | 5 | ## Header 6 | 7 | | Offset | Type | Explaination | 8 | | ------ | -------- | -------------- | 9 | | 0 | Int32 | Reserved | 10 | | 4 | Int32 | AISignal Count | 11 | | 8 | AISignal | AISignals | 12 | 13 | ## AISignal 14 | 15 | | Offset | Type | Explaination | 16 | | ------ | -------- | ----------------- | 17 | | 0 | Int32 | Reserved | 18 | | 4 | Int32 | Unknown | 19 | | 8 | Unknown1 | Unknown1 | 20 | | ... | Byte | Unknown Boolean | 21 | | ... | Int32 | Unknown | 22 | | ... | Int32 | Unknown | 23 | | ... | Byte | Unknown Boolean n | 24 | | ... | Unknown2 | Unknown2 (if n) | 25 | | ... | Byte | Unknown Boolean m | 26 | | ... | Unknown2 | Unknown2 (if m) | 27 | 28 | ## Unknown1 29 | 30 | | Offset | Type | Explaination | 31 | | ------ | ----- | ------------ | 32 | | 0 | Int32 | Unknown | 33 | 34 | ## Unknown2 35 | 36 | | Offset | Type | Explaination | 37 | | ------ | ----- | ------------ | 38 | | 0 | Int32 | Unknown | 39 | | 4 | Int32 | Unknown | 40 | -------------------------------------------------------------------------------- /docs/old/AISpecialLocations.md: -------------------------------------------------------------------------------- 1 | # AI Special Locations (AISpecialLocations.r8) 2 | 3 | Seems to contain information about "special" track locations. 4 | 5 | ## Header 6 | 7 | | Offset | Type | Explaination | 8 | | ------ | ----------------- | ----------------------- | 9 | | 0 | Int32 | Reserved | 10 | | 4 | Int32 | AISpecialLocation Count | 11 | | 8 | AISpecialLocation | AISpecialLocation | 12 | 13 | ## AISpecialLocation 14 | 15 | | Offset | Type | Explaination | 16 | | ------ | -------- | ------------------- | 17 | | 0 | Int32 | Reserved | 18 | | 4 | R8String | Location Name | 19 | | ... | Byte | SpecialLocationType | 20 | | ... | Int32 | Unknown | 21 | | ... | Int32 | Unknown | 22 | | ... | Int32 | Unknown | 23 | | ... | Float | Unknown | 24 | | ... | Int32 | Unknown | 25 | | ... | Byte | Unknown Boolean | 26 | 27 | ## SpecialLocationType 28 | 29 | | Key | Value | 30 | | --- | -------------------------- | 31 | | 0 | SpawnPoint | 32 | | 1 | CrewChange | 33 | | 2 | CrewChangeAndHold | 34 | | 3 | Passenger | 35 | | 4 | PassengerCrewChange | 36 | | 5 | PassengerCrewChangeAndHold | 37 | | 6 | Relinquish | 38 | | 7 | PassengerRelinquish | 39 | -------------------------------------------------------------------------------- /docs/old/AITrackSpeed.md: -------------------------------------------------------------------------------- 1 | # AI Track Speed (AITrackSpeed.r8) 2 | 3 | Seems to contain information related to track speeds 4 | 5 | ## Header 6 | 7 | | Offset | Type | Explaination | 8 | | ------ | ----- | ------------ | 9 | | 0 | Int32 | Reserved | 10 | | 4 | Int32 | Entry count | 11 | | 8 | Entry | Entries | 12 | 13 | ## Entry 14 | 15 | | Offset | Type | Explaination | 16 | | ------ | -------- | -------------- | 17 | | 0 | Int32 | Reserved | 18 | | 4 | Int32 | Unknown | 19 | | 8 | Int32 | Unknown1 Count | 20 | | 12 | Unknown1 | Unknown1s | 21 | 22 | ## Unknown1 23 | 24 | | Offset | Type | Explaination | 25 | | ------ | ----- | ------------ | 26 | | 0 | Int32 | Reserved | 27 | | 4 | Int32 | Unknown | 28 | | 8 | Int32 | Unknown | 29 | | 12 | Int32 | Unknown | 30 | -------------------------------------------------------------------------------- /docs/old/Avatar.md: -------------------------------------------------------------------------------- 1 | # Avatar 2 | 3 | There are currently 3 avatars: 4 | 5 | - Brian 6 | - Chris 7 | - Pablo 8 | 9 | Avatar files are 3D model files with the `rn8` file extension. Models are in cm 10 | 11 | ## Header 12 | 13 | | Offset | Type | Explaination | 14 | | ------ | ----------------- | ------------------------------ | 15 | | 0 | Int32 | VertexStruct Count1 | 16 | | 4 | VertexStruct[] | VertexStructs | 17 | | ... | Int32 | Texture Name Count2 | 18 | | ... | String[] | Texture Names | 19 | | ... | Bool | IsUshortBuffer | 20 | | ... | Int32 | Index Buffer Size | 21 | | ... | Int32[] | Index Buffer | 22 | | ... | Int32 | Unknown1 Count3 | 23 | | ... | UnknownStruct1 | UnknownStruct1s4 | 24 | | ... | Int32 | Skeleton Hierarchy Count | 25 | | ... | Int32[] | Skeleton Hierarchy | 26 | | ... | Int32 | Bone Index Count | 27 | | ... | BoneIndexStruct[] | Bone Indices | 28 | | ... | Int32 | Bind Pose Count | 29 | | ... | Matrix4x4[] | Bind Poses | 30 | | ... | Int32 | Inverse Bind Pose Count | 31 | | ... | Matrix4x4[] | Inverse Bind Poses | 32 | | ... | Int32 | Animation Clip Count | 33 | | ... | AnimationClip[] | Animation Clips | 34 | 35 | - 1: This number gets divided by 7 36 | - 2: 6 is added to the number 37 | - 3: 9 is subtracted from the number 38 | - 4: These are only read when the count is not 0, otherwise only a single entry is created 39 | 40 | ## UnknownStruct1 41 | 42 | | Offset | Type | Explaination | Value If Single | 43 | | ------ | ----- | ------------------------- | ----------------- | 44 | | 0 | Int32 | Reserved | | 45 | | 4 | Int32 | Texture Index1 | | 46 | | 8 | Int32 | Index Count | Index Buffer Size | 47 | | 12 | Int32 | Start Index Location | 0 | 48 | | 16 | Int32 | Base Vertex Location | 0 | 49 | 50 | - 1: Gets the texture at the index and appends `_mrao` 51 | 52 | ## BoneIndexStruct 53 | 54 | | Offset | Type | Explaination | 55 | | ------ | ------ | ------------ | 56 | | 0 | String | Key | 57 | | ... | Int32 | Bone Index | 58 | 59 | ## AnimationClip 60 | 61 | | Offset | Type | Explaination | 62 | | ------ | ---------- | -------------- | 63 | | 0 | String | Key | 64 | | ... | Double | Duration (ms) | 65 | | ... | Int32 | Keyframe Count | 66 | | ... | Keyframe[] | Keyframes | 67 | 68 | ## Keyframe 69 | 70 | | Offset | Type | Explaination | 71 | | ------ | --------- | ------------ | 72 | | 0 | Int32 | Bone | 73 | | 4 | Double | Time (ms) | 74 | | 12 | Matrix4x4 | Transform | 75 | -------------------------------------------------------------------------------- /docs/old/BlockDetectorDatabase.md: -------------------------------------------------------------------------------- 1 | # BlockDetectorDatabase (BlockDetectorDatabase.r8) 2 | 3 | Contains information for Block Detectors. 4 | 5 | ## Header 6 | 7 | | Offset | Type | Explaination | 8 | | ------ | ------------- | -------------- | 9 | | 0 | Int32 | Reserved | 10 | | 4 | Int32 | Detector Count | 11 | | 8 | BlockDetector | Detectors | 12 | 13 | ## Block Detector 14 | 15 | | Offset | Type | Explaination | 16 | | ------ | --------- | ---------------- | 17 | | 0 | Int32 | Reserved | 18 | | 4 | Int32 | Index | 19 | | 8 | Int32 | Number of Tracks | 20 | | 12 | Int32[] | Track Indices | 21 | | ... | TileIndex | Tile XZ | 22 | | ... | Vector3 | Position | 23 | -------------------------------------------------------------------------------- /docs/old/CarSpewerDatabase.md: -------------------------------------------------------------------------------- 1 | # CarSpewerDatabase (CarSpewerDatabase.r8) 2 | 3 | Contains information for Car Spewers (Spawners) 4 | 5 | ## Header 6 | 7 | | Offset | Type | Explaination | 8 | | ------ | ----------- | ----------------- | 9 | | 0 | Int32 | Reserved | 10 | | 4 | Int32 | Number of Spewers | 11 | | 8 | CarSpewer[] | Spewers | 12 | 13 | ## Car Spewer 14 | 15 | | Offset | Type | Explaination | 16 | | ------ | ----------------- | -------------------------- | 17 | | 0 | Int32 | Unknown (num) | 18 | | 4 | Int32 | Unknown (Not used) | 19 | | 8 | Int32 | Road Node Index | 20 | | 12 | Int32 | Max Cars | 21 | | 16 | Int32 | Min Time between Spews | 22 | | 20 | Int32 | Max Time between Spews | 23 | | 24 | Float | Max Speed (Only if num==2) | 24 | | 28 | Int32 | Number of Spew Points | 25 | | 32 | CarSpewStartPoint | Spew Start Points | 26 | 27 | ## Car Spew Start Point 28 | 29 | | Offset | Type | Explaination | 30 | | ------ | --------- | ---------------------- | 31 | | 0 | Int32 | Reserved | 32 | | 4 | Vector3 | Position | 33 | | 12 | TileIndex | Tile Index | 34 | | 24 | Float | Heading (Default -999) | 35 | -------------------------------------------------------------------------------- /docs/old/CommTowerDatabase.md: -------------------------------------------------------------------------------- 1 | # Comm Tower Database (CommTowerDatabase.r8) 2 | 3 | Contains a list of Comm Towers 4 | 5 | ## Header 6 | 7 | | Offset | Type | Explaination | 8 | | ------ | ----------- | -------------------- | 9 | | 0 | Int32 | Reserved | 10 | | 4 | Int32 | Number of CommTowers | 11 | | 8 | CommTower[] | CommTowers | 12 | 13 | ## CommTower 14 | 15 | | Offset | Type | Explaination | 16 | | ------ | --------- | ---------------------- | 17 | | 0 | Int32 | Reserved | 18 | | 4 | TileIndex | TileXZ | 19 | | 12 | Vector3 | Position | 20 | | 24 | R8String | Tower ID/Name | 21 | | ... | Byte | Channel | 22 | | ... | R8String | Dial Code | 23 | | ... | R8String | Emergency Dial Code | 24 | | ... | Float | Range Meters | 25 | | ... | R8String | Dispatch Tone Cue Name | 26 | -------------------------------------------------------------------------------- /docs/old/DefectDetectorList.md: -------------------------------------------------------------------------------- 1 | # Defect Detector List (DefectDetectorList.r8) 2 | 3 | Contains a list of defect detectors. 4 | 5 | ## Header 6 | 7 | | Offset | Type | Explaination | 8 | | ------ | ---------------- | -------------------------- | 9 | | 0 | Int32 | Reserved | 10 | | 4 | Int32 | Number of Defect Detectors | 11 | | 8 | DefectDetector[] | Defect Detectors | 12 | 13 | ## Defect Detector 14 | 15 | | Offset | Type | Explaination | 16 | | ------ | --------- | ----------------------------- | 17 | | 0 | Int32 | Version (v) | 18 | | 4 | Int32 | Milepost | 19 | | 8 | Int32 | Milepost Decimal | 20 | | 16 | TileIndex | Tile Index | 21 | | 28 | Vector3 | Position | 22 | | ... | Byte | IsAEI (IF v=2 otherwise skip) | 23 | | 29 | Byte | SquawkOnDefectOnly | 24 | | 30 | Byte | DraggingEquipment | 25 | | 31 | Byte | SquawkTemperature | 26 | | 32 | Byte | SquawkTrainSpeed | 27 | | 33 | Byte | Hotbox | 28 | | 34 | Byte | HiWide (Legacy, not used) | 29 | | 35 | R8String | WaveBankName | 30 | | ... | R8String | SoundBankName | 31 | | ... | Int32 | Track Number | 32 | -------------------------------------------------------------------------------- /docs/old/DispatcherBlockLightDatabase.md: -------------------------------------------------------------------------------- 1 | # Dispatcher Block Light Database (DispatcherBlockLightDatabase.r8) 2 | 3 | List of Dispatcher Lights (whatever those are? something with lights in the dispatcher screen) 4 | 5 | ## Header 6 | 7 | | Offset | Type | Explaination | 8 | | ------ | ----------------- | --------------------------- | 9 | | 0 | Int32 | Reserved | 10 | | 4 | Int32 | Number of Dispatcher Lights | 11 | | 8 | DispatcherLight[] | Dispatcher Lights | 12 | -------------------------------------------------------------------------------- /docs/old/DispatcherSignalControllerDatabase.md: -------------------------------------------------------------------------------- 1 | # Dispatcher Signal Controller Database (DispatcherSignalControllerDatabase.r8) 2 | 3 | List of Dispatcher Signal Controllers (whatever those are? something to do with dispatcher screen) 4 | 5 | ## Header 6 | 7 | | Offset | Type | Explaination | 8 | | ------ | ---------------------------- | ----------------------------- | 9 | | 0 | Int32 | Reserved | 10 | | 4 | Int32 | Number of Controllers | 11 | | 8 | DispatcherSignalController[] | Dispatcher Signal Controllers | 12 | 13 | ## DispatcherSignalController 14 | 15 | | Offset | Type | Explaination | 16 | | ------ | --------------- | ------------------------------------------------- | 17 | | 0 | Int32 | Unknown n | 18 | | 4 | Vector2 | ScreenXY1 | 19 | | 12 | DispatcherLight | See [DispatcherLight](/Common.md#DispatcherLight) | 20 | | ... | Int32 | Number of Signals | 21 | | ... | Int32[] | Signal Head IDs | 22 | | ... | String | Name? If n == 2 | 23 | 24 | - 1: This overrides the ScreenXY in DispatcherLightBlock 25 | -------------------------------------------------------------------------------- /docs/old/DispatcherSwitchIconDatabase.md: -------------------------------------------------------------------------------- 1 | # Dispatcher Switch Icon Database (DispatcherSwitchIconDatabase.r8) 2 | 3 | Contains a list of Dispatcher Switch Icons 4 | 5 | ## Header 6 | 7 | | Offset | Type | Explaination | 8 | | ------ | ------------------ | --------------- | 9 | | 0 | Int32 | Reserved | 10 | | 4 | Int32 | Number of Icons | 11 | | 8 | DispatcherButton[] | Icons | 12 | 13 | ## DispatcherButton 14 | 15 | | Offset | Type | Explaination | 16 | | ------ | --------- | --------------------------- | 17 | | 0 | Int32 | Unknown n | 18 | | 4 | Rectangle | Button | 19 | | 16 | Vector2 | ScreenXY | 20 | | ... | Int32 | Route Prefix | 21 | | ... | Int32 | Index | 22 | | ... | Int32 | Number of SignalControllers | 23 | | ... | Int32[] | Signal Controller IDs | 24 | | ... | String | Name? If n == 2 | 25 | -------------------------------------------------------------------------------- /docs/old/HornBellConfiguration.md: -------------------------------------------------------------------------------- 1 | # Horn Bell Configuration (HornBellConfiguration.r8) 2 | 3 | Mapping of horn and bell names to xml file configurations 4 | 5 | ## Header 6 | 7 | | Offset | Type | Explaination | 8 | | ------ | ----- | ------------ | 9 | | 0 | Int32 | Reserved | 10 | | 4 | Int32 | Horn Count | 11 | | 8 | Horn | Horns | 12 | | 12 | Int32 | Bell Count | 13 | | 16 | Bell | Bells | 14 | 15 | ## Horn 16 | 17 | | Offset | Type | Explaination | 18 | | ------ | -------- | ----------------------------------------------- | 19 | | 0 | R8String | Key: Locomotive XML filename | 20 | | ... | R8String | Value (regular string, no custom bs): Horn name | 21 | 22 | ## Bell 23 | 24 | | Offset | Type | Explaination | 25 | | ------ | -------- | ----------------------------------------------- | 26 | | 0 | R8String | Key: Locomotive XML Filename | 27 | | ... | R8String | Value (regular string, no custom bs): Bell name | 28 | -------------------------------------------------------------------------------- /docs/old/Hump.md: -------------------------------------------------------------------------------- 1 | # Hump (Hump.r8) 2 | 3 | Contains hump configurations for a region 4 | 5 | ## Header 6 | 7 | | Offset | Type | Explaination | 8 | | ------ | ----- | --------------- | 9 | | 0 | Int32 | Reserved | 10 | | 4 | Int32 | Number of Humps | 11 | | 8 | Hump | Hump | 12 | 13 | ## Hump 14 | 15 | | Offset | Type | Explaination | 16 | | ------ | ---------- | --------------------- | 17 | | 0 | Int32 | Reserved | 18 | | 4 | R8String | Hump Name | 19 | | ... | Int32 | Number of HumpConfigs | 20 | | ... | HumpConfig | Configs | 21 | 22 | ## HumpConfig 23 | 24 | | Offset | Type | Explaination | 25 | | ------ | --------- | ----------------------- | 26 | | 0 | Int32 | Reserved | 27 | | 4 | Boolean | HasName | 28 | | 5 | R8String | Config Name1 | 29 | | ... | Int32 | Number of Tracks | 30 | | ... | HumpTrack | Tracks | 31 | 32 | - 1: Only read if HasName is True 33 | 34 | ## HumpTrack 35 | 36 | | Offset | Type | Explaination | 37 | | ------ | ---------- | -------------- | 38 | | 0 | Int32 | Reserved | 39 | | 4 | R8String | Track Name | 40 | | ... | Int32 | Number of Tags | 41 | | ... | R8String[] | Tags | 42 | -------------------------------------------------------------------------------- /docs/old/HumpControllerList.md: -------------------------------------------------------------------------------- 1 | # Hump Controller List (HumpControllerList.r8) 2 | 3 | Contains hump controllers 4 | 5 | ## Header 6 | 7 | | Offset | Type | Explaination | 8 | | ------ | -------------- | --------------------- | 9 | | 0 | Int32 | Reserved | 10 | | 4 | Int32 | Number of Controllers | 11 | | 8 | HumpController | Controllers | 12 | 13 | ## HumpController 14 | 15 | | Offset | Type | Explaination | 16 | | ------ | --------- | ------------------- | 17 | | 0 | Int32 | Reserved | 18 | | 4 | R8String | Hump Name | 19 | | ... | TileIndex | TileXZ | 20 | | ... | Vector3 | Position | 21 | | ... | R8String | Unused | 22 | | ... | Int32 | Number of TrackPath | 23 | | ... | TrackPath | TrackPaths | 24 | 25 | ## TrackPath 26 | 27 | | Offset | Type | Explaination | 28 | | ------ | ---------------- | -------------------------- | 29 | | 0 | Int32 | Reserved | 30 | | 4 | String | Track Name | 31 | | ... | Int32 | Number of SwitchConnection | 32 | | ... | SwitchConnection | SwitchConnections | 33 | 34 | ## SwitchConnection 35 | 36 | | Offset | Type | Explaination | 37 | | ------ | ------- | ------------------- | 38 | | 0 | Int32 | Reserved | 39 | | 4 | Int32 | Track Section Index | 40 | | 8 | Boolean | Is Reversed | 41 | -------------------------------------------------------------------------------- /docs/old/IndustryConfiguration.md: -------------------------------------------------------------------------------- 1 | # Industry Configuration (.ind) 2 | 3 | Stores information about industries 4 | 5 | ## Header 6 | 7 | | Offset | Type | Explaination | 8 | | ------ | -------- | -------------- | 9 | | 0 | Int32 | Reserved | 10 | | 4 | Int32 | Industry Count | 11 | | 8 | Industry | Industries | 12 | 13 | ## Industry 14 | 15 | | Offset | Type | Explaination | 16 | | ------ | -------- | -------------------- | 17 | | 0 | Int32 | Reserved | 18 | | 4 | R8String | Industry Name | 19 | | ... | R8String | Local Freight Code | 20 | | ... | R8String | Industry Tag | 21 | | ... | Byte | Unknown Boolean | 22 | | ... | Int32 | Industry Track Count | 23 | | ... | IndTrack | Industry Tracks | 24 | 25 | ## Industry Track 26 | 27 | | Offset | Type | Explaination | 28 | | ------ | ----- | ------------ | 29 | | 0 | Int32 | Unknown Int | 30 | | 4 | Int32 | Prefix | 31 | | 8 | Int32 | Section | 32 | | 12 | Int32 | Node | 33 | 34 | ## Car 35 | 36 | | Offset | Type | Explaination | 37 | | ------ | ----- | --------------- | 38 | | 0 | Int32 | Reserved | 39 | | 4 | Byte | Car Type | 40 | | 8 | Byte | Unknown Boolean | 41 | | 12 | Int32 | Unknown Int | 42 | | 16 | Int32 | Unknown Int | 43 | | 20 | Int32 | Unknown Int | 44 | -------------------------------------------------------------------------------- /docs/old/MilepostDatabase.md: -------------------------------------------------------------------------------- 1 | # Milepost Database (MilepostDatabase.r8) 2 | 3 | Contains a list of mileposts and their information 4 | 5 | ## Header 6 | 7 | | Offset | Type | Explaination | 8 | | ------ | -------- | -------------- | 9 | | 0 | Int32 | Reserved | 10 | | 4 | Int32 | Milepost Count | 11 | | 8 | Milepost | Mileposts | 12 | 13 | ## Milepost 14 | 15 | | Offset | Type | Explaination | 16 | | ------ | --------- | ------------ | 17 | | 0 | Int32 | Reserved | 18 | | 4 | R8String | Mile Marker? | 19 | | ... | R8String | Name | 20 | | ... | TileIndex | Tile Index | 21 | | ... | Vector3 | Location | 22 | -------------------------------------------------------------------------------- /docs/old/README.md: -------------------------------------------------------------------------------- 1 | Old style of file format specs that were hand written 2 | -------------------------------------------------------------------------------- /docs/old/RoadDatabase.md: -------------------------------------------------------------------------------- 1 | # Road Database (RoadDatabase.r8) 2 | 3 | Contains road information. 4 | 5 | ## Header 6 | 7 | | Offset | Type | Explaination | 8 | | ------ | ----------- | ------------------ | 9 | | 0 | Int32 | Reserved | 10 | | 4 | Int32 | Number of Sections | 11 | | 8 | RoadSection | Sections | 12 | 13 | ## RoadSection 14 | 15 | | Offset | Type | Explaination | 16 | | ------ | -------- | ------------------------- | 17 | | 0 | Int32 | Unknown Int | 18 | | 4 | Int32 | Number of Nodes | 19 | | 8 | RoadNode | Nodes | 20 | | ... | Int32 | Unknown Int | 21 | | ... | Float | Reserved | 22 | | ... | Byte | RoadExtrusionType | 23 | | ... | Int32 | Num Lanes Per Side | 24 | | ... | Int32 | Lane Center Offset Meters | 25 | | ... | Int32 | Lane Spacing Meters | 26 | 27 | ## RoadNode 28 | 29 | | Offset | Type | Explaination | 30 | | ------ | --------- | ----------------- | 31 | | 0 | Int32 | Reserved | 32 | | 4 | TileIndex | TileXZ | 33 | | 12 | Vector3 | PositionXYZ | 34 | | 24 | Vector3 | TangentXYZ | 35 | | 36 | Vector3 | Reserved | 36 | | 48 | Int32 | Index | 37 | | 52 | Float | Unknown | 38 | | 56 | Int32 | Curve Sign | 39 | | 60 | Float | Unknown | 40 | | 64 | Float | Arc Length Meters | 41 | | 68 | Int32 | Num of Segments | 42 | | 72 | Int32 | Unknown | 43 | | 76 | Float | Max Speed MPH | 44 | 45 | ## RoadExtrusionType 46 | 47 | | Key | Value | 48 | | --- | ------- | 49 | | 0 | Unknown | 50 | | 1 | Unknown | 51 | | 2 | Unknown | 52 | | 3 | Unknown | 53 | | 4 | Unknown | 54 | | 5 | Unknown | 55 | | 6 | Unknown | 56 | | 7 | Unknown | 57 | | 8 | Unknown | 58 | | 9 | Unknown | 59 | | 10 | Unknown | 60 | | 11 | Unknown | 61 | | 12 | Unknown | 62 | | 13 | Unknown | 63 | -------------------------------------------------------------------------------- /docs/old/Signal.md: -------------------------------------------------------------------------------- 1 | # Signal (.sig) 2 | 3 | Contains information related to a signal 4 | 5 | ## Header 6 | 7 | | Offset | Type | Explaination | 8 | | ------ | ------------ | ------------------------------------------------------------- | 9 | | 0 | String | Model Name | 10 | | ... | Int32 | leastRestrictiveSignalState | 11 | | ... | Byte | Unknown Boolean (might be related to signal instruction stop) | 12 | | ... | Byte | isDwarf | 13 | | ... | Int32 | SignalEntry1 Count | 14 | | ... | SignalEntry1 | SignalEntry1s | 15 | 16 | ## SignalLight 17 | 18 | | Offset | Type | Explaination | 19 | | ------ | --------- | --------------------------- | 20 | | 0 | Vector3 | Light Offset | 21 | | 12 | Vector4 | Color\* | 22 | | 24 | Float | Light Glare Radius (meters) | 23 | | 28 | Float | Light Range | 24 | | 32 | Int32 | Glare Count | 25 | | 36 | Vector3[] | Glares | 26 | 27 | \* W is constant at 1f 28 | -------------------------------------------------------------------------------- /docs/old/Stars4.md: -------------------------------------------------------------------------------- 1 | # Stars4 (stars4.r8) 2 | 3 | Stars4 file seems to contain file paths to other r8 database files, along with some random strings which are all identified by their array index. 4 | 5 | ## Header 6 | 7 | | Offset | Type | Explaination | 8 | | ------ | -------- | -------------------- | 9 | | 0 | Int32 | Reserved | 10 | | 4 | Int32 | Number of Strings | 11 | | 8 | R8String | Run8 Encoded Strings | 12 | -------------------------------------------------------------------------------- /docs/old/TKB.md: -------------------------------------------------------------------------------- 1 | # Shader File (.tkb) 2 | 3 | These files are from SharpDX, they are compiled shaders/effects. I am not going to write a dedicated tool for these as they're a pain in the ass (for me at least) and the compiler already has the ability to dump the bytecode. 4 | 5 | ## Dump Bytecode 6 | 7 | You will need to get `tkfxc.exe` from SharpDX, rather then having to compile it, you can just get it precompiled from Nuget: https://www.nuget.org/api/v2/package/SharpDX/2.6.3. This will download `sharpdx.2.6.3.nupkg` which is just a zip file, you can either change the file extension from `.nupkg` to `.zip` or just open it with 7zip (or any other archive program really). The binary can be found in at `sharpdx.2.6.3\Bin\DirectX11_2-net40\tkfxc.exe`. 8 | 9 | Now you can just run: 10 | 11 | - `tkfxc.exe > bytecode.txt` 12 | -------------------------------------------------------------------------------- /docs/old/TrackDatabase.md: -------------------------------------------------------------------------------- 1 | # Track Database (TrackDatabase.r8) 2 | 3 | Contain a list of track locations as well as other track related information. 4 | 5 | ## Header 6 | 7 | | Offset | Type | Explaination | 8 | | ------ | -------------- | ------------------ | 9 | | 0 | Int32 | Reserved | 10 | | 4 | Int32 | Number of Sections | 11 | | 8 | TrackSection[] | Sections | 12 | 13 | ## Track Section 14 | 15 | | Offset | Type | Explaination | 16 | | ------ | ----------- | ------------------------- | 17 | | 0 | Int32 | Reserved | 18 | | 4 | Int32 | Number of Nodes | 19 | | 8 | TrackNode[] | Nodes | 20 | | ... | Int32 | Index | 21 | | ... | Byte | Switch Lever Position | 22 | | ... | Int32 | Number of Section Indices | 23 | | ... | Int32[] | Next Section Indices | 24 | | ... | Byte | Track Type | 25 | | ... | Double | Retarder MPH | 26 | | ... | Byte | Is Occupied | 27 | | ... | Byte | Switch Stand Left Side | 28 | | ... | Int32 | Switch Stand Type | 29 | | ... | Byte | Is CTC Switch | 30 | 31 | ## Track Node 32 | 33 | | Offset | Type | Explaination | 34 | | ------ | --------- | ---------------------------- | 35 | | 0 | Int32 | Reserved | 36 | | 4 | TileIndex | Tile Index | 37 | | 12 | Vector3 | Position | 38 | | 24 | Vector3 | Tangent Degrees | 39 | | 32 | Vector3 | End Position | 40 | | 44 | Int32 | Index | 41 | | 48 | Byte | Is Switch Node | 42 | | 49 | Byte | Is Reverse Path | 43 | | 50 | Float | Curvature Degrees | 44 | | 54 | Int32 | Curve Sign | 45 | | 58 | Float | Radius Meters | 46 | | 62 | Float | Arc Length Meters | 47 | | 66 | Int32 | Num Segments | 48 | | 70 | Int32 | Section this Node belongs to | 49 | | 74 | Byte | Is Selected | 50 | -------------------------------------------------------------------------------- /docs/old/XNG.md: -------------------------------------------------------------------------------- 1 | # XNG 2 | 3 | Crossing Gates 4 | 5 | ## Header 6 | 7 | | Offset | Type | Explaination | 8 | | ------ | ------ | ----------------------------- | 9 | | 0 | Byte | Gate Rotation Type | 10 | | ... | String | Gate Model Name | 11 | | ... | String | Stand Model Name | 12 | | ... | Float | Active Degrees | 13 | | ... | Float | Inactive Degrees | 14 | | ... | Float | Rotation Degrees Per Second\* | 15 | 16 | \* This gets multiplied by a random float between the range of `-4f` and `3f` 17 | 18 | ## GateRotationType 19 | 20 | | Key | Value | 21 | | --- | ----------- | 22 | | 0 | Vertical | 23 | | 1 | Horizontal | 24 | | 2 | XBuckNoBell | 25 | 26 | Some methods to look into in the future: 27 | 28 | - 0x06002B51 29 | -------------------------------------------------------------------------------- /docs/service_area_database.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # ServiceAreaDatabase (ServiceAreaDatabase.r8) 4 | 5 | ## Root Structure 6 | 7 | | Type | ID | Description | 8 | | ---------- | ---- | ----------- | 9 | | Int32 | reserved | This field is unused | 10 | | Int32 | num_service_areas | | 11 | | service_area[] | service_areas | | 12 | 13 | 14 | ## Types 15 | 16 | ### service_area 17 | 18 | | Type | ID | Description | 19 | | ---------- | ---- | ----------- | 20 | | Int32 | num | | 21 | | path1 | path11 | | 22 | | path2 | path22 | | 23 | 24 | - 1: Only if num == 1 25 | - 2: Only if num == 2 26 | 27 | ### path1 28 | 29 | | Type | ID | Description | 30 | | ---------- | ---- | ----------- | 31 | | [TileXZ](common.md#tilexz) | tile_xz | | 32 | | [Vector3](common.md#vector3) | position | | 33 | | Float | float0 | | 34 | | Boolean | bool0 | | 35 | | Boolean | bool1 | | 36 | | Boolean | bool2 | | 37 | | Boolean | bool3 | | 38 | 39 | 40 | ### path2 41 | 42 | | Type | ID | Description | 43 | | ---------- | ---- | ----------- | 44 | | [TileXZ](common.md#tilexz) | tile_xz | | 45 | | [Vector3](common.md#vector3) | position | | 46 | | Float | float0 | | 47 | | class646 | class646 | | 48 | 49 | 50 | ### class646 51 | 52 | | Type | ID | Description | 53 | | ---------- | ---- | ----------- | 54 | | Int8 | enum50_0 | | 55 | | Int8 | enum60_0 | | 56 | | Double | double1 | | 57 | | Double | double2 | | 58 | 59 | 60 | -------------------------------------------------------------------------------- /docs/stars4.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Stars4 (stars4.r8) 4 | 5 | Contains a list of strings, including file paths. Strings are referenced by their index. 6 | 7 | ## Root Structure 8 | 9 | | Type | ID | Description | 10 | | ---------- | ---- | ----------- | 11 | | Int32 | reserved | This field is unused | 12 | | Int32 | num_entries | | 13 | | [R8String](common.md#r8string)[] | entries | | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/tilescenery.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Tile Scenery File 4 | 5 | ## Root Structure 6 | 7 | | Type | ID | Description | 8 | | ---------- | ---- | ----------- | 9 | | Int32 | num_assets | | 10 | | asset[] | assets | | 11 | 12 | 13 | ## Types 14 | 15 | ### asset 16 | 17 | | Type | ID | Description | 18 | | ---------- | ---- | ----------- | 19 | | Int32 | num_decals | | 20 | | decal[] | decals | | 21 | | Int8 | disregard_bounding_test | | 22 | | [C# String](common.md#cs_string) | model_name | | 23 | | [Vector3](common.md#vector3) | position | | 24 | | [Vector3](common.md#vector3) | rotation | | 25 | | [Vector3](common.md#vector3) | scale | | 26 | | [TileXZ](common.md#tilexz) | tile_xz | | 27 | 28 | 29 | ### decal 30 | 31 | | Type | ID | Description | 32 | | ---------- | ---- | ----------- | 33 | | Float | color_r | | 34 | | Float | color_g | | 35 | | Float | color_b | | 36 | | Int32 | num_digits | | 37 | | digit[] | digits | | 38 | | [Vector3](common.md#vector3) | offset | | 39 | | [Vector3](common.md#vector3) | rotation_deg | | 40 | | Float | size | | 41 | | [C# String](common.md#cs_string) | texture_name | | 42 | 43 | 44 | ### digit 45 | 46 | | Type | ID | Description | 47 | | ---------- | ---- | ----------- | 48 | | Int32 | digit | | 49 | 50 | 51 | -------------------------------------------------------------------------------- /docs/tr2.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # TR2 Terrain Tile 4 | 5 | ## Root Structure 6 | 7 | | Type | ID | Description | 8 | | ---------- | ---- | ----------- | 9 | | [C# String](common.md#cs_string) | texture_1 | | 10 | | [C# String](common.md#cs_string) | texture_2 | | 11 | | [C# String](common.md#cs_string) | texture_3 | | 12 | | [C# String](common.md#cs_string) | texture_4 | | 13 | | chunk_row[] | chunks | Tile X | 14 | | Float | lon_east | | 15 | | Float | lon_west | | 16 | | Float | lat_north | | 17 | | Float | lat_south | | 18 | 19 | 20 | ## Types 21 | 22 | ### chunk_row 23 | 24 | | Type | ID | Description | 25 | | ---------- | ---- | ----------- | 26 | | chunk[] | chunks | Tile Y | 27 | 28 | 29 | ### chunk 30 | 31 | | Type | ID | Description | 32 | | ---------- | ---- | ----------- | 33 | | UInt32 | chunk_size | Number of elevation points in this chunk | 34 | | elevation_col[] | elevations_row | Chunk X | 35 | 36 | 37 | ### elevation_col 38 | 39 | | Type | ID | Description | 40 | | ---------- | ---- | ----------- | 41 | | Float[] | elevation | Chunk Y | 42 | 43 | 44 | -------------------------------------------------------------------------------- /lib/CS/Run8/Installer/Environment.wxs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 14 | 15 | 16 | 17 | 18 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /lib/CS/Run8/Installer/Folders.wxs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /lib/CS/Run8/Installer/Installer.wixproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Run8Tools Installer 4 | true 5 | true 6 | 7 | 8 | 9 | TextureToolFiles 10 | TextureTool 11 | true 12 | 13 | 14 | 15 | 16 | ColladaConverterFiles 17 | ColladaConverter 18 | true 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /lib/CS/Run8/Installer/Package.en-us.wxl: -------------------------------------------------------------------------------- 1 |  4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /lib/CS/Run8/Installer/Package.wxs: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /lib/CS/Run8/Installer/assets/License.rtf: -------------------------------------------------------------------------------- 1 | {\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Segoe UI;}} 2 | {\*\generator Riched20 10.0.18362}\viewkind4\uc1 3 | \pard\nowidctlpar\sb120\sa120\b\f0\fs20 MIT License\par 4 | \b0 Copyright (c) Puyodead1. All rights reserved.\par 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\par 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\par 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE\par 8 | } 9 | -------------------------------------------------------------------------------- /lib/CS/Run8/LibRun8/Common/Class252.cs: -------------------------------------------------------------------------------- 1 | namespace LibRun8.Common 2 | { 3 | public class Class252 4 | { 5 | public Quaternion[] quaternion_0 { get; set; } 6 | 7 | public Vector3[] vector3_0 { get; set; } 8 | 9 | public Quaternion quaternion_1 { get; set; } 10 | 11 | public Vector3 vector3_1 { get; set; } 12 | 13 | internal void method_0(float float_0) 14 | { 15 | if (this.quaternion_0.Length < 2) 16 | { 17 | this.quaternion_1 = Quaternion.Identity; 18 | this.vector3_1 = Vector3.Zero; 19 | return; 20 | } 21 | int num = Util.Utils.Clamp((int)(float_0 * (float)this.quaternion_0.Length - 2f), 0, this.quaternion_0.Length - 2); 22 | int num2 = Util.Utils.Clamp(num + 1, 0, this.quaternion_0.Length - 1); 23 | Quaternion quaternion = this.quaternion_0[num]; 24 | Quaternion quaternion2 = this.quaternion_0[num2]; 25 | Vector3 vector = this.vector3_0[num]; 26 | Vector3 vector2 = this.vector3_0[num2]; 27 | float num3 = 1f / (this.quaternion_0.Length - 1); 28 | float num4 = Util.Utils.Lerp(0f, 1f, float_0 - num3 * (float)num / num3); 29 | if (quaternion != quaternion2) 30 | { 31 | this.quaternion_1 = Quaternion.Lerp(quaternion, quaternion2, num4); 32 | } 33 | else 34 | { 35 | this.quaternion_1 = quaternion; 36 | } 37 | this.vector3_1 = Vector3.Lerp(vector, vector2, num4); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/CS/Run8/LibRun8/Common/DecalLoader.cs: -------------------------------------------------------------------------------- 1 | namespace LibRun8.Common 2 | { 3 | public class DecalLoader 4 | { 5 | public List Digits { get; set; } = new List(); 6 | public string TextureName { get; set; } 7 | public float Size { get; set; } 8 | public Vector3 OffsetXYZ { get; set; } 9 | public Vector3 RotationDegXYZ { get; set; } 10 | public Vector3 ColorRGB { get; set; } 11 | public bool IsGaugeNeedle { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lib/CS/Run8/LibRun8/Common/DispatcherLight.cs: -------------------------------------------------------------------------------- 1 | using LibRun8.Util; 2 | 3 | namespace LibRun8.Common 4 | { 5 | public class DispatcherLight 6 | { 7 | public Rectangle ButtonRectangle { get; set; } 8 | public List Indices { get; set; } = new List(); 9 | public Vector2 ScreenXY { get; set; } 10 | public string String0 { get; set; } = string.Empty; 11 | 12 | public static DispatcherLight Read(BinaryReader reader) 13 | { 14 | DispatcherLight dispatcherBlockLight = new DispatcherLight(); 15 | int num = reader.ReadInt32(); 16 | dispatcherBlockLight.ButtonRectangle = reader.ReadRectangle(); 17 | dispatcherBlockLight.ScreenXY = reader.ReadVector2(); 18 | int numOfIndices = reader.ReadInt32(); 19 | for (int i = 0; i < numOfIndices; i++) 20 | { 21 | dispatcherBlockLight.Indices.Add(reader.ReadInt32()); 22 | } 23 | if (num == 2) 24 | { 25 | dispatcherBlockLight.String0 = reader.ReadString(); 26 | } 27 | 28 | return dispatcherBlockLight; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lib/CS/Run8/LibRun8/Common/Int4.cs: -------------------------------------------------------------------------------- 1 | namespace LibRun8.Common 2 | { 3 | public struct Int4 4 | { 5 | // 6 | // Summary: 7 | // The X component of the vector. 8 | public int X { get; set; } 9 | 10 | // 11 | // Summary: 12 | // The Y component of the vector. 13 | public int Y { get; set; } 14 | 15 | // 16 | // Summary: 17 | // The Z component of the vector. 18 | public int Z { get; set; } 19 | 20 | // 21 | // Summary: 22 | // The W component of the vector. 23 | public int W { get; set; } 24 | 25 | // 26 | // Summary: 27 | // Initializes a new instance of the Int4 struct. 28 | // 29 | // Parameters: 30 | // value: 31 | // The value that will be assigned to all components. 32 | public Int4(int value) 33 | { 34 | X = value; 35 | Y = value; 36 | Z = value; 37 | W = value; 38 | } 39 | 40 | // 41 | // Summary: 42 | // Initializes a new instance of the Int4 struct. 43 | // 44 | // Parameters: 45 | // x: 46 | // Initial value for the X component of the vector. 47 | // 48 | // y: 49 | // Initial value for the Y component of the vector. 50 | // 51 | // z: 52 | // Initial value for the Z component of the vector. 53 | // 54 | // w: 55 | // Initial value for the W component of the vector. 56 | public Int4(int x, int y, int z, int w) 57 | { 58 | X = x; 59 | Y = y; 60 | Z = z; 61 | W = w; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /lib/CS/Run8/LibRun8/Common/LightLoader.cs: -------------------------------------------------------------------------------- 1 | namespace LibRun8.Common 2 | { 3 | public class LightLoader 4 | { 5 | public bool billboardGlare { get; set; } 6 | 7 | public float LightRange { get; set; } 8 | 9 | public float lightWidth { get; set; } 10 | 11 | public float LightIntensity { get; set; } 12 | 13 | public float decayExponent { get; set; } = 1f; 14 | 15 | public Vector3 LightOffsetXYZ { get; set; } 16 | 17 | public bool isSpotLight { get; set; } 18 | 19 | public Vector4 Color { get; set; } 20 | 21 | public Vector3 LightDirectionDeg { get; set; } 22 | 23 | public bool flashing { get; set; } 24 | 25 | public float flashTimeRandomVariation { get; set; } 26 | 27 | public double flashTimerSeconds { get; set; } 28 | 29 | public bool hasDayNiteSensor { get; set; } 30 | 31 | public float dayNiteSensorAmbientLevel { get; set; } 32 | 33 | public Vector3[] GlareList { get; set; } 34 | 35 | public float LightGlareRadiusMeters { get; set; } = 0.35f; 36 | 37 | public bool isHepPowered { get; set; } 38 | 39 | public bool isMarkerLight { get; set; } 40 | 41 | public bool isNumberboardLight { get; set; } 42 | 43 | public bool IsLimitedYardLight { get; set; } 44 | 45 | public bool renderGlareOnly { get; set; } 46 | 47 | public bool isIncandescent { get; set; } = true; 48 | 49 | public float glowScalar { get; set; } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /lib/CS/Run8/LibRun8/Common/ModelObjectDefinition.cs: -------------------------------------------------------------------------------- 1 | namespace LibRun8.Common 2 | { 3 | public class ModelObjectDefinition 4 | { 5 | public string texture2D_0 { get; set; } 6 | 7 | public string texture2D_1 { get; set; } 8 | 9 | public string texture2D_2 { get; set; } 10 | 11 | public int BaseVertexLocation { get; set; } 12 | 13 | public int StartIndexLocation { get; set; } 14 | 15 | public int IndexCountPerInstance { get; set; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lib/CS/Run8/LibRun8/Common/ProceduralVegetation.cs: -------------------------------------------------------------------------------- 1 | namespace LibRun8.Common 2 | { 3 | public class ProceduralVegetation 4 | { 5 | public TileIndex TileXZ { get; set; } 6 | public int PlantCount { get; set; } 7 | public List Plants { get; set; } = new List(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /lib/CS/Run8/LibRun8/Common/Rectangle.cs: -------------------------------------------------------------------------------- 1 | using System.Drawing; 2 | using System.Globalization; 3 | 4 | namespace LibRun8.Common 5 | { 6 | public class Rectangle 7 | { 8 | public int X { get; set; } 9 | 10 | public int Y { get; set; } 11 | 12 | public int Width { get; set; } 13 | 14 | public int Height { get; set; } 15 | 16 | public override string ToString() 17 | { 18 | return string.Format(CultureInfo.InvariantCulture, "X:{0} Y:{1} Width:{2} Height:{3}", new object[] { this.X, this.Y, this.Width, this.Height }); 19 | } 20 | 21 | public Rectangle(int x, int y, int width, int height) 22 | { 23 | this.X = x; 24 | this.Y = y; 25 | this.Width = width; 26 | this.Height = height; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/CS/Run8/LibRun8/Common/SceneryAssetLoader.cs: -------------------------------------------------------------------------------- 1 | namespace LibRun8.Common 2 | { 3 | public class SceneryAssetLoader 4 | { 5 | public string ModelName { get; set; } 6 | public TileIndex TileXZ { get; set; } 7 | public Vector3 PositionXYZ { get; set; } 8 | public Vector3 RotationXYZ { get; set; } 9 | public Vector3 Scale { get; set; } 10 | public bool DisregardBoundingTest { get; set; } 11 | public bool Bool0 { get; set; } 12 | public List DecalLoadList { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /lib/CS/Run8/LibRun8/Common/TileIndex.cs: -------------------------------------------------------------------------------- 1 | namespace LibRun8.Common 2 | { 3 | public class TileIndex 4 | { 5 | public int X { get; set; } 6 | public int Z { get; set; } 7 | 8 | public TileIndex() 9 | { 10 | X = 0; 11 | Z = 0; 12 | } 13 | 14 | public TileIndex(int x, int y) 15 | { 16 | X = x; 17 | Z = y; 18 | } 19 | 20 | public static TileIndex Read(BinaryReader reader) 21 | { 22 | TileIndex tileXZ = new TileIndex(); 23 | 24 | tileXZ.X = reader.ReadInt32(); 25 | tileXZ.Z = reader.ReadInt32(); 26 | 27 | return tileXZ; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/CS/Run8/LibRun8/Common/Vector2.cs: -------------------------------------------------------------------------------- 1 | namespace LibRun8.Common 2 | { 3 | public struct Vector2 4 | { 5 | // 6 | // Summary: 7 | // The X component of the vector. 8 | public float X { get; set; } 9 | 10 | // 11 | // Summary: 12 | // The Y component of the vector. 13 | public float Y { get; set; } 14 | 15 | // 16 | // Summary: 17 | // Initializes a new instance of the Vector2 struct. 18 | // 19 | // Parameters: 20 | // value: 21 | // The value that will be assigned to all components. 22 | public Vector2(float value) 23 | { 24 | X = value; 25 | Y = value; 26 | } 27 | 28 | // 29 | // Summary: 30 | // Initializes a new instance of the Vector2 struct. 31 | // 32 | // Parameters: 33 | // x: 34 | // Initial value for the X component of the vector. 35 | // 36 | // y: 37 | // Initial value for the Y component of the vector. 38 | public Vector2(float x, float y) 39 | { 40 | X = x; 41 | Y = y; 42 | } 43 | 44 | public override string ToString() 45 | { 46 | return string.Format("X={0};Y={1}", X, Y); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /lib/CS/Run8/LibRun8/Common/Vector4.cs: -------------------------------------------------------------------------------- 1 | namespace LibRun8.Common 2 | { 3 | public struct Vector4 4 | { 5 | public float X { get; set; } 6 | public float Y { get; set; } 7 | public float Z { get; set; } 8 | public float W { get; set; } 9 | 10 | // 11 | // Summary: 12 | // Initializes a new instance of the Vector4 struct. 13 | // 14 | // Parameters: 15 | // value: 16 | // The value that will be assigned to all components. 17 | public Vector4(float value) 18 | { 19 | X = value; 20 | Y = value; 21 | Z = value; 22 | W = value; 23 | } 24 | 25 | // 26 | // Summary: 27 | // Initializes a new instance of the Vector4 struct. 28 | // 29 | // Parameters: 30 | // x: 31 | // Initial value for the X component of the vector. 32 | // 33 | // y: 34 | // Initial value for the Y component of the vector. 35 | // 36 | // z: 37 | // Initial value for the Z component of the vector. 38 | // 39 | // w: 40 | // Initial value for the W component of the vector. 41 | 42 | public Vector4(float x, float y, float z, float w) 43 | { 44 | X = x; 45 | Y = y; 46 | Z = z; 47 | W = w; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /lib/CS/Run8/LibRun8/Common/VertexStruct.cs: -------------------------------------------------------------------------------- 1 | namespace LibRun8.Common 2 | { 3 | public struct VertexStruct 4 | { 5 | public Vector3 Position; 6 | 7 | public Vector3 Normal; 8 | 9 | public Vector2 TextureCoordinate; 10 | 11 | public Vector3 Tangent; 12 | 13 | public Vector3 Binormal; 14 | 15 | public override string ToString() 16 | { 17 | return string.Format("Position: {0}; Normal: {1}; TextureCoordinate: {2}", Position.ToString(), Normal.ToString(), TextureCoordinate.ToString()); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/CS/Run8/LibRun8/Formats/AISignalDatabase.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Low Accuracy 3 | */ 4 | 5 | namespace LibRun8.Formats 6 | { 7 | public class AISignalDatabase : FileFormat 8 | { 9 | public List Signals { get; set; } = new List(); 10 | 11 | public static AISignalDatabase Read(string path) 12 | { 13 | AISignalDatabase aiSignalDatabase = new AISignalDatabase(); 14 | using (FileStream fileStream = new FileStream(path, FileMode.Open)) 15 | { 16 | using (BinaryReader reader = new BinaryReader(fileStream)) 17 | { 18 | reader.ReadInt32(); // reserved 19 | 20 | var signalCount = reader.ReadInt32(); 21 | for (int i = 0; i < signalCount; i++) 22 | { 23 | AISignal aiSignal = AISignal.Read(reader); 24 | aiSignalDatabase.Signals.Add(aiSignal); 25 | } 26 | } 27 | } 28 | 29 | return aiSignalDatabase; 30 | } 31 | 32 | public override void Write(string path) 33 | { 34 | throw new NotImplementedException(); 35 | } 36 | 37 | public class AISignal 38 | { 39 | public List SignalIndices { get; set; } = new List(); // maps signal head signal index -> signal 40 | public bool Bool0 { get; set; } 41 | public int Int0 { get; set; } 42 | public int Int1 { get; set; } 43 | public Class336 Class336_0 { get; set; } 44 | public Class336 Class336_1 { get; set; } 45 | 46 | public static AISignal Read(BinaryReader reader) 47 | { 48 | AISignal aiSignal = new AISignal(); 49 | 50 | reader.ReadInt32(); // reserved 51 | var count = reader.ReadInt32(); 52 | for (int i = 0; i < count; i++) 53 | { 54 | aiSignal.SignalIndices.Add(reader.ReadInt32()); 55 | } 56 | 57 | aiSignal.Bool0 = reader.ReadBoolean(); 58 | aiSignal.Int0 = reader.ReadInt32(); 59 | aiSignal.Int1 = reader.ReadInt32(); 60 | 61 | if(reader.ReadBoolean()) 62 | { 63 | aiSignal.Class336_0 = Class336.Read(reader); 64 | } 65 | 66 | if(reader.ReadBoolean()) 67 | { 68 | aiSignal.Class336_1 = Class336.Read(reader); 69 | } 70 | 71 | return aiSignal; 72 | } 73 | } 74 | 75 | public class Class336 76 | { 77 | public int Int0 { get; set; } 78 | public int Int1 { get; set; } 79 | public static Class336 Read(BinaryReader reader) 80 | { 81 | Class336 @class = new Class336(); 82 | @class.Int0 = reader.ReadInt32(); 83 | @class.Int1 = reader.ReadInt32(); 84 | 85 | return @class; 86 | } 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /lib/CS/Run8/LibRun8/Formats/AITrackSpeedDatabase.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Low Accuracy 3 | */ 4 | 5 | namespace LibRun8.Formats 6 | { 7 | public class AITrackSpeedDatabase : FileFormat 8 | { 9 | public List TrackSpeeds { get; set; } = new List(); 10 | public static AITrackSpeedDatabase Read(string path) 11 | { 12 | AITrackSpeedDatabase aiTrackSpeedDatabase = new AITrackSpeedDatabase(); 13 | using (FileStream fileStream = new FileStream(path, FileMode.Open)) 14 | { 15 | using (BinaryReader reader = new BinaryReader(fileStream)) 16 | { 17 | reader.ReadInt32(); // reserved 18 | var count = reader.ReadInt32(); 19 | for (int i = 0; i < count; i++) 20 | { 21 | aiTrackSpeedDatabase.TrackSpeeds.Add(TrackSpeed.Read(reader)); 22 | } 23 | } 24 | } 25 | 26 | return aiTrackSpeedDatabase; 27 | } 28 | 29 | public override void Write(string path) 30 | { 31 | throw new NotImplementedException(); 32 | } 33 | 34 | public class TrackSpeedEntry 35 | { 36 | public int Int0 { get; set; } 37 | public int Int1 { get; set; } = 15; 38 | public int Int2 { get; set; } = 15; 39 | public static TrackSpeedEntry Read(BinaryReader reader) 40 | { 41 | TrackSpeedEntry class317 = new TrackSpeedEntry(); 42 | 43 | reader.ReadInt32(); // reserved 44 | class317.Int0 = reader.ReadInt32(); 45 | class317.Int1 = reader.ReadInt32(); 46 | class317.Int2 = reader.ReadInt32(); 47 | 48 | return class317; 49 | } 50 | } 51 | 52 | public class TrackSpeed 53 | { 54 | public List Speeds { get; set; } = new List(); 55 | public int Int0 { get; set; } 56 | public static TrackSpeed Read(BinaryReader reader) 57 | { 58 | TrackSpeed trackSpeed = new TrackSpeed(); 59 | 60 | reader.ReadInt32(); // reserved 61 | trackSpeed.Int0 = reader.ReadInt32(); 62 | var count = reader.ReadInt32(); 63 | for (int i = 0; i < count; i++) 64 | { 65 | trackSpeed.Speeds.Add(TrackSpeedEntry.Read(reader)); 66 | } 67 | 68 | return trackSpeed; 69 | } 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /lib/CS/Run8/LibRun8/Formats/BlockDetectorDatabase.cs: -------------------------------------------------------------------------------- 1 | using LibRun8.Common; 2 | using LibRun8.Util; 3 | 4 | namespace LibRun8.Formats 5 | { 6 | public class BlockDetectorDatabase : FileFormat 7 | { 8 | public List Detectors { get; set; } = new List(); 9 | public static BlockDetectorDatabase Read(string path) 10 | { 11 | BlockDetectorDatabase blockDetectorDatabase = new BlockDetectorDatabase(); 12 | using (FileStream fileStream = new FileStream(path, FileMode.Open)) 13 | { 14 | using (BinaryReader reader = new BinaryReader(fileStream)) 15 | { 16 | reader.ReadInt32(); // reserved 17 | var numOfDetectors = reader.ReadInt32(); 18 | for (int i = 0; i < numOfDetectors; i++) 19 | { 20 | BlockDetector blockDetector = BlockDetector.Read(reader); 21 | blockDetectorDatabase.Detectors.Add(blockDetector); 22 | } 23 | } 24 | } 25 | 26 | return blockDetectorDatabase; 27 | } 28 | 29 | public override void Write(string path) 30 | { 31 | throw new NotImplementedException(); 32 | } 33 | 34 | public class BlockDetector 35 | { 36 | public int Index { get; set; } 37 | public List Tracks { get; set; } = new List(); 38 | public TileIndex TileXZ { get; set; } 39 | public Vector3 PositionXYZ { get; set; } 40 | 41 | public static BlockDetector Read(BinaryReader reader) 42 | { 43 | BlockDetector blockDetector = new BlockDetector(); 44 | 45 | reader.ReadInt32(); // reserved 46 | blockDetector.Index = reader.ReadInt32(); 47 | var numOfTracks = reader.ReadInt32(); 48 | for (int i = 0; i < numOfTracks; i++) 49 | { 50 | blockDetector.Tracks.Add(reader.ReadInt32()); 51 | } 52 | blockDetector.TileXZ = reader.ReadTileIndex(); 53 | blockDetector.PositionXYZ = reader.ReadVector3(); 54 | 55 | return blockDetector; 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /lib/CS/Run8/LibRun8/Formats/CarSpewerDatabase.cs: -------------------------------------------------------------------------------- 1 | using LibRun8.Common; 2 | using LibRun8.Util; 3 | 4 | namespace LibRun8.Formats 5 | { 6 | public class CarSpewerDatabase : FileFormat 7 | { 8 | public List Spewers { get; set; } = new List(); 9 | public static CarSpewerDatabase Read(string path) 10 | { 11 | CarSpewerDatabase carSpewerDatabase = new CarSpewerDatabase(); 12 | using (FileStream fileStream = new FileStream(path, FileMode.Open)) 13 | { 14 | using (BinaryReader reader = new BinaryReader(fileStream)) 15 | { 16 | reader.ReadInt32(); // reserved 17 | var numOfSpewers = reader.ReadInt32(); 18 | for (int i = 0; i < numOfSpewers; i++) 19 | { 20 | carSpewerDatabase.Spewers.Add(CarSpewer.Read(reader)); 21 | } 22 | } 23 | } 24 | 25 | return carSpewerDatabase; 26 | } 27 | 28 | public override void Write(string path) 29 | { 30 | throw new NotImplementedException(); 31 | } 32 | 33 | public class CarSpewer 34 | { 35 | public int Int0 { get; set; } // Doesn't appear to ever be used 36 | public int RoadNodeIndex { get; set; } 37 | public int MaxNumCars { get; set; } 38 | public double MinTimeBetwixtSpew { get; set; } 39 | public double MaxTimeBetwixtSpew { get; set; } 40 | public float MaxSpeed { get; set; } 41 | public List CarSpewStartPoints { get; set; } = new List(); 42 | 43 | public static CarSpewer Read(BinaryReader reader) 44 | { 45 | CarSpewer carSpewer = new CarSpewer(); 46 | 47 | var num = reader.ReadInt32(); 48 | carSpewer.Int0 = reader.ReadInt32(); 49 | carSpewer.RoadNodeIndex = reader.ReadInt32(); 50 | carSpewer.MaxNumCars = reader.ReadInt32(); 51 | carSpewer.MinTimeBetwixtSpew = reader.ReadDouble(); 52 | carSpewer.MaxTimeBetwixtSpew = reader.ReadDouble(); 53 | if (num == 2) 54 | { 55 | carSpewer.MaxSpeed = reader.ReadSingle(); 56 | } 57 | var numOfSpewStartPoints = reader.ReadInt32(); 58 | for (int i = 0; i < numOfSpewStartPoints; i++) 59 | { 60 | carSpewer.CarSpewStartPoints.Add(CarSpewStartPoint.Read(reader)); 61 | } 62 | 63 | return carSpewer; 64 | } 65 | } 66 | 67 | public class CarSpewStartPoint 68 | { 69 | public Vector3 PosXYZ { get; set; } 70 | public TileIndex TileXZ { get; set; } 71 | public float Heading { get; set; } = -999f; 72 | 73 | public static CarSpewStartPoint Read(BinaryReader reader) 74 | { 75 | CarSpewStartPoint carSpewStartPoint = new CarSpewStartPoint(); 76 | 77 | reader.ReadInt32(); 78 | carSpewStartPoint.PosXYZ = reader.ReadVector3(); 79 | carSpewStartPoint.TileXZ = reader.ReadTileIndex(); 80 | carSpewStartPoint.Heading = reader.ReadSingle(); 81 | 82 | return carSpewStartPoint; 83 | } 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /lib/CS/Run8/LibRun8/Formats/DefectDetector.cs: -------------------------------------------------------------------------------- 1 | using LibRun8.Common; 2 | using LibRun8.Util; 3 | 4 | namespace LibRun8.Formats 5 | { 6 | public class DefectDetector 7 | { 8 | public int Version { get; set; } = 2; 9 | public int Milepost { get; set; } 10 | public int MilepostDecimal { get; set; } 11 | public TileIndex TileXZ { get; set; } 12 | public Vector3 PositionXYZ { get; set; } 13 | public bool? IsAEI { get; set; } 14 | public bool SquawkOnDefectOnly { get; set; } 15 | public bool DraggingEquipment { get; set; } 16 | public bool SquawkTemperature { get; set; } 17 | public bool SquawkTrainSpeed { get; set; } 18 | public bool Hotbox { get; set; } 19 | public bool HiWide { get; set; } // legacy, not used 20 | public string WaveBankName { get; set; } 21 | public string SoundBankName { get; set; } 22 | public int TrackNumber { get; set; } 23 | 24 | public static DefectDetector Read(BinaryReader reader) 25 | { 26 | DefectDetector defectDetector = new DefectDetector(); 27 | defectDetector.Version = reader.ReadInt32(); 28 | if (defectDetector.Version == 1) 29 | { 30 | defectDetector.Milepost = reader.ReadInt32(); 31 | defectDetector.MilepostDecimal = reader.ReadInt32(); 32 | defectDetector.TileXZ = reader.ReadTileIndex(); 33 | defectDetector.PositionXYZ = reader.ReadVector3(); 34 | defectDetector.SquawkOnDefectOnly = reader.ReadBoolean(); 35 | defectDetector.DraggingEquipment = reader.ReadBoolean(); 36 | defectDetector.SquawkTemperature = reader.ReadBoolean(); 37 | defectDetector.SquawkTrainSpeed = reader.ReadBoolean(); 38 | defectDetector.Hotbox = reader.ReadBoolean(); 39 | defectDetector.HiWide = reader.ReadBoolean(); 40 | defectDetector.WaveBankName = reader.ReadR8String(); 41 | defectDetector.SoundBankName = reader.ReadR8String(); 42 | defectDetector.TrackNumber = reader.ReadInt32(); 43 | } 44 | 45 | if (defectDetector.Version == 2) 46 | { 47 | defectDetector.Milepost = reader.ReadInt32(); 48 | defectDetector.MilepostDecimal = reader.ReadInt32(); 49 | defectDetector.TileXZ = reader.ReadTileIndex(); 50 | defectDetector.PositionXYZ = reader.ReadVector3(); 51 | defectDetector.IsAEI = reader.ReadBoolean(); 52 | defectDetector.SquawkOnDefectOnly = reader.ReadBoolean(); 53 | defectDetector.DraggingEquipment = reader.ReadBoolean(); 54 | defectDetector.SquawkTemperature = reader.ReadBoolean(); 55 | defectDetector.SquawkTrainSpeed = reader.ReadBoolean(); 56 | defectDetector.Hotbox = reader.ReadBoolean(); 57 | defectDetector.HiWide = reader.ReadBoolean(); 58 | defectDetector.WaveBankName = reader.ReadR8String(); 59 | defectDetector.SoundBankName = reader.ReadR8String(); 60 | defectDetector.TrackNumber = reader.ReadInt32(); 61 | } 62 | 63 | return defectDetector; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /lib/CS/Run8/LibRun8/Formats/DefectDetectorList.cs: -------------------------------------------------------------------------------- 1 | using LibRun8.Util; 2 | 3 | namespace LibRun8.Formats 4 | { 5 | public class DefectDetectorList : FileFormat 6 | { 7 | public List DefectDetectors { get; set; } = new List(); 8 | public static DefectDetectorList Read(string path) 9 | { 10 | DefectDetectorList defectDetectorList = new DefectDetectorList(); 11 | using (FileStream fileStream = new FileStream(path, FileMode.Open)) 12 | { 13 | using (BinaryReader reader = new BinaryReader(fileStream)) 14 | { 15 | reader.ReadInt32(); // reserved 16 | int numOfDetectors = reader.ReadInt32(); 17 | for (int i = 0; i < numOfDetectors; i++) 18 | { 19 | defectDetectorList.DefectDetectors.Add(DefectDetector.Read(reader)); 20 | } 21 | } 22 | } 23 | 24 | return defectDetectorList; 25 | } 26 | 27 | public override void Write(string path) 28 | { 29 | using (FileStream fileStream = new FileStream(path, FileMode.OpenOrCreate)) 30 | using (BinaryWriter writer = new BinaryWriter(fileStream)) 31 | { 32 | 33 | writer.Write(1); // reserved 34 | writer.Write(DefectDetectors.Count); 35 | foreach (DefectDetector defectDetector in DefectDetectors) 36 | { 37 | writer.Write(defectDetector.Version); 38 | writer.Write(defectDetector.Milepost); 39 | writer.Write(defectDetector.MilepostDecimal); 40 | writer.WriteTileIndex(defectDetector.TileXZ); 41 | writer.WriteVector3(defectDetector.PositionXYZ); 42 | if (defectDetector.Version == 2) 43 | { 44 | if(!defectDetector.IsAEI.HasValue) 45 | { 46 | throw new Exception("IsAEI must have a value when version is 2!"); 47 | } 48 | writer.Write(defectDetector.IsAEI.Value); 49 | } 50 | writer.Write(defectDetector.SquawkOnDefectOnly); 51 | writer.Write(defectDetector.DraggingEquipment); 52 | writer.Write(defectDetector.SquawkTemperature); 53 | writer.Write(defectDetector.SquawkTrainSpeed); 54 | writer.Write(defectDetector.Hotbox); 55 | writer.Write(defectDetector.HiWide); 56 | writer.WriteR8String(defectDetector.WaveBankName); 57 | writer.WriteR8String(defectDetector.SoundBankName); 58 | writer.Write(defectDetector.TrackNumber); 59 | } 60 | } 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /lib/CS/Run8/LibRun8/Formats/DispatcherLightBlockDatabase.cs: -------------------------------------------------------------------------------- 1 | using LibRun8.Common; 2 | 3 | namespace LibRun8.Formats 4 | { 5 | public class DispatcherLightBlockDatabase : FileFormat 6 | { 7 | public List DispatchLights { get; set; } = new List(); 8 | public static DispatcherLightBlockDatabase Read(string path) 9 | { 10 | DispatcherLightBlockDatabase dispatcherLightBlockDatabase = new DispatcherLightBlockDatabase(); 11 | using (FileStream fileStream = new FileStream(path, FileMode.Open)) 12 | { 13 | using (BinaryReader reader = new BinaryReader(fileStream)) 14 | { 15 | reader.ReadInt32(); // reserved 16 | int numOfBlocks = reader.ReadInt32(); 17 | for (int i = 0; i < numOfBlocks; i++) 18 | { 19 | dispatcherLightBlockDatabase.DispatchLights.Add(DispatcherLight.Read(reader)); 20 | } 21 | } 22 | } 23 | 24 | return dispatcherLightBlockDatabase; 25 | } 26 | 27 | public override void Write(string path) 28 | { 29 | throw new NotImplementedException(); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/CS/Run8/LibRun8/Formats/DispatcherSignalControllerDatabase.cs: -------------------------------------------------------------------------------- 1 | using LibRun8.Common; 2 | using LibRun8.Util; 3 | 4 | namespace LibRun8.Formats 5 | { 6 | public class DispatcherSignalControllerDatabase : FileFormat 7 | { 8 | public List Controllers { get; private set; } = new List(); 9 | public static DispatcherSignalControllerDatabase Read(string path) 10 | { 11 | DispatcherSignalControllerDatabase item = new DispatcherSignalControllerDatabase(); 12 | using (FileStream fileStream = new FileStream(path, FileMode.Open)) 13 | { 14 | using (BinaryReader reader = new BinaryReader(fileStream)) 15 | { 16 | reader.ReadInt32(); // reserved 17 | int numOfControllers = reader.ReadInt32(); 18 | for (int i = 0; i < numOfControllers; i++) 19 | { 20 | item.Controllers.Add(DispatcherSignalController.Read(reader)); 21 | } 22 | } 23 | } 24 | 25 | return item; 26 | } 27 | 28 | public override void Write(string path) 29 | { 30 | throw new NotImplementedException(); 31 | } 32 | 33 | public class DispatcherSignalController 34 | { 35 | public DispatcherLight Button { get; set; } 36 | public List Signals { get; set; } = new List(); 37 | public string String0 { get; set; } = string.Empty; 38 | public static DispatcherSignalController Read(BinaryReader reader) 39 | { 40 | DispatcherSignalController controller = new DispatcherSignalController(); 41 | 42 | int num = reader.ReadInt32(); 43 | Vector2 screenXY = reader.ReadVector2(); 44 | controller.Button = DispatcherLight.Read(reader); 45 | controller.Button.ScreenXY = screenXY; 46 | 47 | int numOfSignals = reader.ReadInt32(); 48 | for (int i = 0; i < numOfSignals; i++) 49 | { 50 | controller.Signals.Add(reader.ReadInt32()); 51 | } 52 | 53 | if(num == 2) 54 | { 55 | controller.String0 = reader.ReadString(); 56 | } 57 | 58 | return controller; 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /lib/CS/Run8/LibRun8/Formats/DispatcherSwitchIconDatabase.cs: -------------------------------------------------------------------------------- 1 | using LibRun8.Common; 2 | using LibRun8.Util; 3 | 4 | namespace LibRun8.Formats 5 | { 6 | public class DispatcherSwitchIconDatabase : FileFormat 7 | { 8 | public List Buttons { get; set; } = new List(); 9 | public static DispatcherSwitchIconDatabase Read(string path) 10 | { 11 | DispatcherSwitchIconDatabase item = new DispatcherSwitchIconDatabase(); 12 | using (FileStream fileStream = new FileStream(path, FileMode.Open)) 13 | { 14 | using (BinaryReader reader = new BinaryReader(fileStream)) 15 | { 16 | reader.ReadInt32(); // reserved 17 | int numOfIcons = reader.ReadInt32(); 18 | for (int i = 0; i < numOfIcons; i++) 19 | { 20 | item.Buttons.Add(DispatcherButton.Read(reader)); 21 | } 22 | } 23 | } 24 | 25 | return item; 26 | } 27 | 28 | public override void Write(string path) 29 | { 30 | throw new NotImplementedException(); 31 | } 32 | 33 | public class DispatcherButton 34 | { 35 | public Rectangle Button { get; set; } 36 | public Vector2 ScreenXY { get; set; } 37 | public int RoutePrefix { get; set; } 38 | public int Index { get; set; } 39 | public List SwitchControllers { get; set; } = new List(); 40 | public string String0 { get; set; } = string.Empty; 41 | 42 | public static DispatcherButton Read(BinaryReader reader) 43 | { 44 | DispatcherButton dispatcherButton = new DispatcherButton(); 45 | 46 | int num = reader.ReadInt32(); 47 | dispatcherButton.Button = reader.ReadRectangle(); 48 | dispatcherButton.ScreenXY = reader.ReadVector2(); 49 | dispatcherButton.RoutePrefix = reader.ReadInt32(); 50 | dispatcherButton.Index = reader.ReadInt32(); 51 | int numOfSwitchControllers = reader.ReadInt32(); 52 | 53 | for (int i = 0; i < numOfSwitchControllers; i++) 54 | { 55 | dispatcherButton.SwitchControllers.Add(reader.ReadInt32()); 56 | } 57 | 58 | if (num == 2) 59 | { 60 | dispatcherButton.String0 = reader.ReadString(); 61 | } 62 | 63 | return dispatcherButton; 64 | } 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /lib/CS/Run8/LibRun8/Formats/FileFormat.cs: -------------------------------------------------------------------------------- 1 | namespace LibRun8.Formats 2 | { 3 | public abstract class FileFormat 4 | { 5 | public abstract void Write(string path); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /lib/CS/Run8/LibRun8/Formats/Signal.cs: -------------------------------------------------------------------------------- 1 | using LibRun8.Common; 2 | 3 | namespace LibRun8.Formats 4 | { 5 | public class Signal : FileFormat 6 | { 7 | public string ModelName { get; set; } 8 | public int LeastRestrictiveSignalState { get; set; } 9 | public bool B0 { get; set; } 10 | public bool IsDwarf { get; set; } 11 | public SignalLight[] SignalLights { get; set; } 12 | 13 | public static Signal Read(string path) 14 | { 15 | Signal signal = new Signal(); 16 | using (FileStream fileStream = new FileStream(path, FileMode.Open)) 17 | { 18 | using (BinaryReader reader = new BinaryReader(fileStream)) 19 | { 20 | signal.ModelName = reader.ReadString(); 21 | signal.LeastRestrictiveSignalState = reader.ReadInt32(); 22 | signal.B0 = reader.ReadBoolean(); 23 | signal.IsDwarf = reader.ReadBoolean(); 24 | 25 | int signalCount = reader.ReadInt32(); 26 | signal.SignalLights = new SignalLight[signalCount]; 27 | 28 | for(int i = 0; i < signalCount; i++) 29 | { 30 | SignalLight light = new SignalLight(); 31 | light.LightOffset = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); 32 | light.Color = new Vector4(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), 1f); 33 | light.LightGlareRadiusMeters = reader.ReadSingle(); 34 | light.LightRange = reader.ReadSingle(); 35 | 36 | int VectorCount = reader.ReadInt32(); 37 | light.GlareList = new Vector3[VectorCount]; 38 | 39 | for(int j = 0; j < VectorCount; j++) 40 | { 41 | light.GlareList[j] = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); 42 | } 43 | 44 | signal.SignalLights[i] = light; 45 | } 46 | } 47 | } 48 | 49 | return signal; 50 | } 51 | 52 | public override void Write(string path) 53 | { 54 | throw new NotImplementedException(); 55 | } 56 | 57 | public class SignalLight 58 | { 59 | public Vector3 LightOffset { get; set; } 60 | public Vector3 lightDirectionDeg { get; set; } 61 | public Vector3[] GlareList { get; set; } 62 | public Vector4 Color { get; set; } 63 | public float LightGlareRadiusMeters { get; set; } = 0.35f; 64 | public float LightRange { get; set; } 65 | public float LightIntensity { get; set; } 66 | public bool IsLimitedYardLight { get; set; } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /lib/CS/Run8/LibRun8/Formats/Stars4.cs: -------------------------------------------------------------------------------- 1 | using LibRun8.Util; 2 | 3 | namespace LibRun8.Formats 4 | { 5 | public class Stars4 : FileFormat 6 | { 7 | public string[] Entries { get; set; } 8 | 9 | public static Stars4 Read(string path) 10 | { 11 | Stars4 stars4 = new Stars4(); 12 | using (FileStream fileStream = new FileStream(path, FileMode.Open)) 13 | { 14 | using (BinaryReader reader = new BinaryReader(fileStream)) 15 | { 16 | reader.ReadInt32(); 17 | int entryCount = reader.ReadInt32(); 18 | stars4.Entries = new string[entryCount]; 19 | 20 | for(int i = 0; i < stars4.Entries.Length; i++) 21 | { 22 | stars4.Entries[i] = reader.ReadR8String(); 23 | } 24 | } 25 | } 26 | 27 | return stars4; 28 | } 29 | 30 | public override void Write(string path) 31 | { 32 | throw new NotImplementedException(); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lib/CS/Run8/LibRun8/Formats/Terrain/Chunk.cs: -------------------------------------------------------------------------------- 1 | using LibRun8.Common; 2 | namespace LibRun8.Formats.Terrain 3 | { 4 | public class Chunk 5 | { 6 | public static readonly int CHUNK_SIZE = 25; 7 | 8 | public float[,] HeightMap; 9 | public float[][] JaggedHeightMap { get { return Util.Utils.ConvertToJaggedArray(HeightMap); } } 10 | public short Hixels { get; set; } 11 | public int CX { get; set; } 12 | public int CZ { get; set; } 13 | public VertexStruct[] Vertices { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/CS/Run8/LibRun8/Formats/Terrain/ETileType.cs: -------------------------------------------------------------------------------- 1 | namespace LibRun8.Formats.Terrain 2 | { 3 | public enum ETileType 4 | { 5 | None, 6 | Ter, 7 | Tr2, 8 | Tr3, 9 | Tr4 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /lib/CS/Run8/LibRun8/Formats/Terrain/TerrainTile.cs: -------------------------------------------------------------------------------- 1 | using LibRun8.Common; 2 | 3 | namespace LibRun8.Formats.Terrain 4 | { 5 | public class TerrainTile 6 | { 7 | public string Texture0Name { get; set; } 8 | public string Texture1Name { get; set; } 9 | public string Texture2Name { get; set; } 10 | public string Texture3Name { get; set; } 11 | public int DetailLevel { get; set; } 12 | public Chunk[,] ChunkData { get; set; } 13 | public float LonWest { get; set; } 14 | public float LonEast { get; set; } 15 | public float LatNorth { get; set; } 16 | public float LatSouth { get; set; } 17 | public string ProcVeg { get; set; } 18 | public VertexStruct[] AllVerticesTemp { get; set; } 19 | public int[] IndexBuffer { get; set; } 20 | public TileIndex TileXZ { get; set; } 21 | public List LoadList { get; set; } = new List(); 22 | public ProceduralVegetation Plants { get; set; } 23 | public byte[] WeightMap { get; set; } 24 | public Vector2 CenterXZ { get; set; } 25 | public float CenterY { get; set; } 26 | 27 | public void CopyToVertexBuffers() 28 | { 29 | for (int i = 0; i < this.AllVerticesTemp.Length; i++) 30 | { 31 | Vector2 textureCoordinate = default; 32 | textureCoordinate.X = this.AllVerticesTemp[i].Position.X / 844.3211f; 33 | textureCoordinate.Y = -this.AllVerticesTemp[i].Position.Z / 1026.0822f; 34 | this.AllVerticesTemp[i].TextureCoordinate = textureCoordinate; 35 | } 36 | 37 | //this.indexBuffer = null; 38 | //this.allVerticesTemp = null; 39 | } 40 | 41 | public void WriteOBJ(string path) 42 | { 43 | 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /lib/CS/Run8/LibRun8/Formats/Terrain/TerrainTileLoadData.cs: -------------------------------------------------------------------------------- 1 | namespace LibRun8.Formats.Terrain 2 | { 3 | public class TerrainTileLoadData 4 | { 5 | public string FilePath { get; set; } 6 | public string FileNameOnly { get; set; } 7 | public ETileType Type { get; set; } 8 | public TerrainTile Tile { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /lib/CS/Run8/LibRun8/Formats/Terrain/Tr2Loader.cs: -------------------------------------------------------------------------------- 1 | using LibRun8.Util; 2 | 3 | namespace LibRun8.Formats.Terrain 4 | { 5 | public class Tr2Loader 6 | { 7 | public static void LoadTile(TerrainTileLoadData terrainTileLoadData) 8 | { 9 | LoadTile(terrainTileLoadData, false); 10 | } 11 | 12 | public static void LoadTile(TerrainTileLoadData terrainTileLoadData, bool bool0) 13 | { 14 | using (FileStream fileStream = new FileStream(terrainTileLoadData.FilePath, FileMode.Open, FileAccess.Read)) 15 | { 16 | using (BinaryReader binaryReader = new BinaryReader(fileStream)) 17 | { 18 | TileUtil.LoadTextures(binaryReader, terrainTileLoadData, bool0); 19 | LoadChunks(binaryReader, terrainTileLoadData); 20 | } 21 | } 22 | } 23 | 24 | public static void LoadChunks(BinaryReader reader, TerrainTileLoadData terrainTileLoadData) 25 | { 26 | terrainTileLoadData.Tile.DetailLevel = 99; 27 | terrainTileLoadData.Tile.ChunkData = new Chunk[25, 25]; 28 | //int num = 0; 29 | for (byte x = 0; x < 25; x++) 30 | { 31 | for (byte z = 0; z < 25; z++) 32 | { 33 | Chunk chunk = new Chunk(); 34 | chunk.Hixels = (short)reader.ReadInt32(); 35 | chunk.HeightMap = new float[chunk.Hixels, chunk.Hixels]; 36 | chunk.CX = x; 37 | chunk.CZ = z; 38 | 39 | for (int i = 0; i < chunk.Hixels; i++) 40 | { 41 | for (int j = 0; j < chunk.Hixels; j++) 42 | { 43 | float elevation = reader.ReadSingle(); 44 | chunk.HeightMap[i, j] = elevation; 45 | //if(elevation <= heightOffset + 0.2f) 46 | //{ 47 | // num++; 48 | //} 49 | } 50 | } 51 | 52 | terrainTileLoadData.Tile.ChunkData[x, z] = chunk; 53 | } 54 | } 55 | 56 | //unknown0 = region == "SouthernCA" && num > 100; 57 | 58 | try 59 | { 60 | terrainTileLoadData.Tile.LonEast = reader.ReadSingle(); 61 | terrainTileLoadData.Tile.LonWest = reader.ReadSingle(); 62 | terrainTileLoadData.Tile.LatNorth = reader.ReadSingle(); 63 | terrainTileLoadData.Tile.LatSouth = reader.ReadSingle(); 64 | terrainTileLoadData.Tile.ProcVeg = reader.ReadString(); 65 | } 66 | catch { } 67 | 68 | // this calculates vertex and index buffer 69 | TileUtil.smethod_13(terrainTileLoadData.Tile); 70 | } 71 | 72 | public void Write(string path) 73 | { 74 | throw new NotImplementedException(); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /lib/CS/Run8/LibRun8/Formats/TileScenery.cs: -------------------------------------------------------------------------------- 1 | using LibRun8.Common; 2 | 3 | namespace LibRun8.Formats 4 | { 5 | public class TileScenery : FileFormat 6 | { 7 | public List LoadList = new List(); 8 | 9 | public static TileScenery Read(string path) 10 | { 11 | TileScenery item = new TileScenery(); 12 | using (FileStream fileStream = new FileStream(path, FileMode.Open)) 13 | { 14 | using (BinaryReader reader = new BinaryReader(fileStream)) 15 | { 16 | // this is a copy of the LoadSceneryItems method from Tr4Loader.cs 17 | int count = reader.ReadInt32(); 18 | 19 | for (int i = 0; i < count; i++) 20 | { 21 | SceneryAssetLoader sceneryAssetLoader = new SceneryAssetLoader 22 | { 23 | DecalLoadList = new List() 24 | }; 25 | 26 | int decalCount = reader.ReadInt32(); 27 | 28 | for (int j = 0; j < decalCount; j++) 29 | { 30 | DecalLoader decalLoader = new DecalLoader 31 | { 32 | ColorRGB = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()), 33 | }; 34 | 35 | int digitCount = reader.ReadInt32(); 36 | for (int k = 0; k < digitCount; k++) 37 | { 38 | decalLoader.Digits.Add(reader.ReadInt32()); 39 | } 40 | 41 | decalLoader.OffsetXYZ = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); 42 | decalLoader.RotationDegXYZ = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); 43 | decalLoader.Size = reader.ReadSingle(); 44 | decalLoader.TextureName = reader.ReadString(); 45 | sceneryAssetLoader.DecalLoadList.Add(decalLoader); 46 | } 47 | 48 | sceneryAssetLoader.DisregardBoundingTest = reader.ReadBoolean(); 49 | sceneryAssetLoader.ModelName = reader.ReadString(); 50 | sceneryAssetLoader.PositionXYZ = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); 51 | sceneryAssetLoader.RotationXYZ = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); 52 | sceneryAssetLoader.Scale = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); 53 | sceneryAssetLoader.TileXZ = new TileIndex(reader.ReadInt32(), reader.ReadInt32()); 54 | item.LoadList.Add(sceneryAssetLoader); 55 | } 56 | } 57 | } 58 | 59 | return item; 60 | } 61 | 62 | public override void Write(string path) 63 | { 64 | throw new NotImplementedException(); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /lib/CS/Run8/LibRun8/LibRun8.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | enable 7 | true 8 | AnyCPU;x64 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /lib/CS/Run8/LibRun8/Utils/BinaryWriterExtensions.cs: -------------------------------------------------------------------------------- 1 | using LibRun8.Common; 2 | 3 | namespace LibRun8.Util 4 | { 5 | /// 6 | /// Provides some conspicuously absent string and Type functionality to 7 | /// 8 | /// 9 | static class BinaryWriterExtensions 10 | { 11 | 12 | public static void WriteVector3(this BinaryWriter writer, Vector3 vector) 13 | { 14 | writer.Write(vector.X); 15 | writer.Write(vector.Y); 16 | writer.Write(vector.Z); 17 | } 18 | 19 | public static void WriteTileIndex(this BinaryWriter writer, TileIndex TileXZ) 20 | { 21 | writer.Write(TileXZ.X); 22 | writer.Write(TileXZ.Z); 23 | } 24 | 25 | public static void WriteR8String(this BinaryWriter writer, string val) 26 | { 27 | if (val == null) 28 | { 29 | val = string.Empty; 30 | } 31 | byte[] array = R8String.EncodeBytes(val); 32 | writer.Write(array.Length); 33 | writer.Write(array); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lib/CS/Run8/LibRun8/Utils/R8String.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | 3 | namespace LibRun8.Util 4 | { 5 | public class R8String 6 | { 7 | public static string DecodeBytes(byte[] bytes) 8 | { 9 | byte[] array = new byte[bytes.Length / 2]; 10 | int num = 0; 11 | for (int i = 0; i < array.Length; i++) 12 | { 13 | byte[] array2 = array; 14 | int num2 = i; 15 | array2[num2] |= (byte)(bytes[num++] << 4); 16 | byte[] array3 = array; 17 | int num3 = i; 18 | array3[num3] |= (byte)(bytes[num++] >> 4); 19 | } 20 | return Encoding.UTF8.GetString(array); 21 | } 22 | 23 | public static byte[] EncodeBytes(string val) 24 | { 25 | byte[] bytes = Encoding.UTF8.GetBytes(val); 26 | byte[] array = new byte[bytes.Length * 2]; 27 | int num = 0; 28 | for (int i = 0; i < bytes.Length; i++) 29 | { 30 | array[num++] = (byte)(bytes[i] >> 4); 31 | array[num++] = (byte)(bytes[i] << 4); 32 | } 33 | return array; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lib/CS/Run8/MappingTest/ClassInfo.cs: -------------------------------------------------------------------------------- 1 | namespace MappingTest 2 | { 3 | public class ClassInfo 4 | { 5 | public string ClassName { get; set; } 6 | public List Methods { get; set; } 7 | public List Fields { get; set; } 8 | public List Properties { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /lib/CS/Run8/MappingTest/ClassPair.cs: -------------------------------------------------------------------------------- 1 | namespace MappingTest 2 | { 3 | public class ClassPair 4 | { 5 | public ClassInfo OldClass { get; set; } 6 | public ClassInfo NewClass { get; set; } 7 | public bool IsSameClass { get; set; } // Label: true if they are the same class, false otherwise 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /lib/CS/Run8/MappingTest/Extractor.cs: -------------------------------------------------------------------------------- 1 | namespace MappingTest 2 | { 3 | public class Extractor 4 | { 5 | public static Dictionary GetClassesFromAssembly(string assemblyPath) 6 | { 7 | var classes = new Dictionary(); 8 | var assembly = Mono.Cecil.AssemblyDefinition.ReadAssembly(assemblyPath); 9 | 10 | foreach (var module in assembly.Modules) 11 | { 12 | foreach (var type in module.Types) 13 | { 14 | if (type.IsClass && type.FullName.StartsWith("ns0")) 15 | { 16 | var classInfo = new ClassInfo 17 | { 18 | ClassName = type.FullName, 19 | Methods = type.Methods.Select(m => new MethodInfo 20 | { 21 | Name = m.Name, 22 | Parameters = m.Parameters.Select(p => p.ParameterType.FullName).ToList(), 23 | ReturnType = m.ReturnType.FullName, 24 | Body = m.HasBody ? string.Join(" ", m.Body.Instructions.Select(i => i.OpCode.Code.ToString())) : string.Empty 25 | }).ToList(), 26 | Fields = type.Fields.Select(f => f.Name).ToList(), 27 | Properties = type.Properties.Select(p => p.Name).ToList() 28 | }; 29 | classes[classInfo.ClassName] = classInfo; 30 | } 31 | } 32 | } 33 | 34 | return classes; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lib/CS/Run8/MappingTest/Labeling.cs: -------------------------------------------------------------------------------- 1 | namespace MappingTest 2 | { 3 | public class Labeling 4 | { 5 | public static void ManualLabeling(List pairs) 6 | { 7 | // Implement a manual labeling interface or tool 8 | // For simplicity, this is a placeholder for manual labeling 9 | foreach (var pair in pairs) 10 | { 11 | Console.WriteLine($"Old Class: {pair.OldClass.ClassName}, New Class: {pair.NewClass.ClassName}"); 12 | Console.WriteLine("Are these the same class? (y/n)"); 13 | var input = Console.ReadLine(); 14 | pair.IsSameClass = input.ToLower() == "y"; 15 | } 16 | } 17 | 18 | public static void AutoLabeling(List pairs) 19 | { 20 | // Implement heuristic rules for automatic labeling 21 | foreach (var pair in pairs) 22 | { 23 | pair.IsSameClass = pair.OldClass.ClassName == pair.NewClass.ClassName; 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/CS/Run8/MappingTest/MappingTest.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /lib/CS/Run8/MappingTest/MethodInfo.cs: -------------------------------------------------------------------------------- 1 | namespace MappingTest 2 | { 3 | public class MethodInfo 4 | { 5 | public string Name { get; set; } 6 | public List Parameters { get; set; } 7 | public string ReturnType { get; set; } 8 | public string Body { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /lib/CS/Run8/MappingTest/PairGenerator.cs: -------------------------------------------------------------------------------- 1 | namespace MappingTest 2 | { 3 | public class PairGenerator 4 | { 5 | public static List GeneratePairs(Dictionary oldClasses, Dictionary newClasses) 6 | { 7 | var pairs = new List(); 8 | 9 | foreach (var oldClass in oldClasses.Values) 10 | { 11 | foreach (var newClass in newClasses.Values) 12 | { 13 | pairs.Add(new ClassPair { OldClass = oldClass, NewClass = newClass }); 14 | } 15 | } 16 | 17 | return pairs; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/CS/Run8/MappingTest/Program.cs: -------------------------------------------------------------------------------- 1 | namespace MappingTest 2 | { 3 | class Program 4 | { 5 | static void Main(string[] args) 6 | { 7 | if (args.Length != 2) 8 | { 9 | Console.WriteLine("Usage: CompareExeVersions "); 10 | return; 11 | } 12 | 13 | string oldExePath = args[0]; 14 | string newExePath = args[1]; 15 | 16 | var oldClasses = Extractor.GetClassesFromAssembly(oldExePath); 17 | var newClasses = Extractor.GetClassesFromAssembly(newExePath); 18 | 19 | var pairs = PairGenerator.GeneratePairs(oldClasses, newClasses); 20 | 21 | Labeling.AutoLabeling(pairs); 22 | 23 | foreach (var pair in pairs) 24 | { 25 | Console.WriteLine($"Old Class: {pair.OldClass.ClassName}, New Class: {pair.NewClass.ClassName}, IsSameClass: {pair.IsSameClass}"); 26 | } 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /lib/CS/Run8/MappingTest/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "MappingTest": { 4 | "commandName": "Project", 5 | "commandLineArgs": "\"D:\\Programs\\Run8Studios\\Run8 Train Simulator V3\\old\\Run-8 Train Simulator V3_update_11_renamed.exe\" \"D:\\Programs\\Run8Studios\\Run8 Train Simulator V3\\old\\Run-8 Train Simulator V3_update_12_cleaned.exe\"" 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /lib/CS/Run8/ModelLoaderTest/Class141.cs: -------------------------------------------------------------------------------- 1 | namespace ModelLoaderTest 2 | { 3 | public sealed class Class141 4 | { 5 | //public Texture2D texture2D_0; 6 | public string texture2D_0; 7 | 8 | //public Texture2D texture2D_1; 9 | public string texture2D_1; 10 | 11 | //public Texture2D texture2D_2; 12 | public string texture2D_2; 13 | 14 | public int BaseVertexLocation; 15 | 16 | public int StartIndexLocation; 17 | 18 | public int IndexCountPerInstance; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/CS/Run8/ModelLoaderTest/Class251.cs: -------------------------------------------------------------------------------- 1 | using LibRun8.Common; 2 | using LibRun8.Util; 3 | 4 | namespace ModelLoaderTest 5 | { 6 | public class Class251 7 | { 8 | public void method_0(float float_0) 9 | { 10 | if (this.quaternion_0.Length < 2) 11 | { 12 | this.quaternion_1 = Quaternion.Identity; 13 | this.vector3_1 = Vector3.Zero; 14 | return; 15 | } 16 | int num = Utils.Clamp((int)(float_0 * (float)this.quaternion_0.Length - 2f), 0, this.quaternion_0.Length - 2); 17 | int num2 = Utils.Clamp(num + 1, 0, this.quaternion_0.Length - 1); 18 | Quaternion quaternion = this.quaternion_0[num]; 19 | Quaternion quaternion2 = this.quaternion_0[num2]; 20 | Vector3 vector = this.vector3_0[num]; 21 | Vector3 vector2 = this.vector3_0[num2]; 22 | float num3 = 1f / (float)(this.quaternion_0.Length - 1); 23 | float num4 = Utils.Lerp(0f, 1f, float_0 - num3 * (float)num / num3); 24 | if (quaternion != quaternion2) 25 | { 26 | this.quaternion_1 = Quaternion.Lerp(quaternion, quaternion2, num4); 27 | } 28 | else 29 | { 30 | this.quaternion_1 = quaternion; 31 | } 32 | this.vector3_1 = Vector3.Lerp(vector, vector2, num4); 33 | } 34 | 35 | internal Quaternion[] quaternion_0; 36 | 37 | internal Vector3[] vector3_0; 38 | 39 | internal Quaternion quaternion_1; 40 | 41 | internal Vector3 vector3_1; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /lib/CS/Run8/ModelLoaderTest/Class252.cs: -------------------------------------------------------------------------------- 1 | using LibRun8.Common; 2 | 3 | namespace ModelLoaderTest 4 | { 5 | public class Class252 6 | { 7 | // Token: 0x06001379 RID: 4985 RVA: 0x0000CC48 File Offset: 0x0000AE48 8 | public void Dispose() 9 | { 10 | //this.buffer_0.Dispose(); 11 | //this.buffer_1.Dispose(); 12 | } 13 | 14 | // Token: 0x0600137A RID: 4986 RVA: 0x0007DDC4 File Offset: 0x0007BFC4 15 | public void method_1(float float_0) 16 | { 17 | Vector3 vector = Vector3.Transform(Vector3.ForwardRH, this.class252_0.quaternion_0); 18 | Vector3 vector2 = Vector3.Transform(Vector3.Up, this.class252_0.quaternion_0); 19 | Vector3 vector3 = Vector3.Transform(Vector3.Right, this.class252_0.quaternion_0); 20 | //this.vector3_2 != Vector3.Zero; 21 | if (this.class251_0 != null) 22 | { 23 | this.class251_0.method_0(float_0); 24 | this.quaternion_0 = this.class252_0.quaternion_0 * this.class251_0.quaternion_1 * this.quaternion_2 * this.RotationMatrix; 25 | this.vector3_0 = this.class252_0.vector3_0; 26 | this.vector3_0 += vector3 * this.class251_0.vector3_1.X; 27 | this.vector3_0 += vector2 * this.class251_0.vector3_1.Y; 28 | this.vector3_0 += vector * this.class251_0.vector3_1.Z; 29 | } 30 | else 31 | { 32 | this.quaternion_0 = this.class252_0.quaternion_0; 33 | this.vector3_0 = this.class252_0.vector3_0; 34 | this.vector3_0 += vector3 * this.PositionOffset.X; 35 | this.vector3_0 += vector2 * this.PositionOffset.Y; 36 | this.vector3_0 += vector * this.PositionOffset.Z; 37 | } 38 | Vector3 vector4 = this.vector3_3 - this.class252_0.vector3_3 + this.vector3_1; 39 | this.vector3_0 += vector3 * vector4.X; 40 | this.vector3_0 += vector2 * vector4.Y; 41 | this.vector3_0 += vector * -vector4.Z; 42 | } 43 | 44 | //public Enum41 enum41_0; 45 | public bool isUshortIndexBuffer = false; 46 | 47 | public string string_0 { get; set; } 48 | 49 | public string string_1 { get; set; } 50 | 51 | //public SharpDX.Toolkit.Graphics.Buffer buffer_0; 52 | public Struct7[] VertexBuffer; 53 | 54 | //public SharpDX.Toolkit.Graphics.Buffer buffer_1; 55 | 56 | public ushort[] IndexBuffer1; 57 | public int[] IndexBuffer2; 58 | 59 | public List list_0 = new List(); 60 | 61 | public Quaternion quaternion_0 { get; set; } = Quaternion.Identity; 62 | 63 | public Vector3 vector3_0 { get; set; } = Vector3.Zero; 64 | 65 | public Vector3 vector3_1 { get; set; } = Vector3.Zero; 66 | 67 | public Quaternion RotationMatrix { get; set; } = Quaternion.Identity; 68 | 69 | public Quaternion quaternion_2 { get; set; } = Quaternion.Identity; 70 | 71 | public Vector3 PositionOffset { get; set; } = Vector3.Zero; 72 | 73 | public Vector3 vector3_3 { get; set; } = Vector3.Zero; 74 | 75 | public Class251 class251_0 { get; set; } 76 | 77 | public Class252 class252_0 { get; set; } 78 | 79 | public bool bool_0 { get; set; } = true; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /lib/CS/Run8/ModelLoaderTest/ModelLoaderTest.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | enable 8 | AnyCPU;x64 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /lib/CS/Run8/ModelLoaderTest/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "ModelLoaderTest": { 4 | "commandName": "Project", 5 | "commandLineArgs": "\"D:\\Programs\\Run8Studios\\Run8 Train Simulator V3\\Content\\V3RailVehicles\\Body\\R8_SD40T-2_SP01.rn8\"" 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /lib/CS/Run8/ModelLoaderTest/Struct7.cs: -------------------------------------------------------------------------------- 1 | using LibRun8.Common; 2 | 3 | namespace ModelLoaderTest 4 | { 5 | public struct Struct7 6 | { 7 | //[VertexElement("SV_Position")] 8 | public Vector3 Position; 9 | 10 | //[VertexElement("NORMAL")] 11 | public Vector3 Normal; 12 | 13 | //[VertexElement("TEXCOORD0")] 14 | public Vector2 TexCoord0; 15 | 16 | //[VertexElement("TANGENT")] 17 | public Vector3 Tangent; 18 | 19 | //[VertexElement("BINORMAL")] 20 | public Vector3 BiNormal; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/CS/Run8/ModelLoaderTest/VertexPositionNormalTexture.cs: -------------------------------------------------------------------------------- 1 | using LibRun8.Common; 2 | 3 | namespace ModelLoaderTest 4 | { 5 | public struct VertexPositionNormalTexture : IEquatable 6 | { 7 | /// 8 | /// Initializes a new instance. 9 | /// 10 | /// The position of this vertex. 11 | /// The vertex normal. 12 | /// UV texture coordinates. 13 | public VertexPositionNormalTexture(Vector3 position, Vector3 normal, Vector2 textureCoordinate) 14 | { 15 | this = default(VertexPositionNormalTexture); 16 | this.Position = position; 17 | this.Normal = normal; 18 | this.TextureCoordinate = textureCoordinate; 19 | } 20 | 21 | public bool Equals(VertexPositionNormalTexture other) 22 | { 23 | return this.Position.Equals(other.Position) && this.Normal.Equals(other.Normal) && this.TextureCoordinate.Equals(other.TextureCoordinate); 24 | } 25 | 26 | public override bool Equals(object obj) 27 | { 28 | return !object.ReferenceEquals(null, obj) && obj is VertexPositionNormalTexture && this.Equals((VertexPositionNormalTexture)obj); 29 | } 30 | 31 | public override int GetHashCode() 32 | { 33 | int num = this.Position.GetHashCode(); 34 | num = (num * 397) ^ this.Normal.GetHashCode(); 35 | return (num * 397) ^ this.TextureCoordinate.GetHashCode(); 36 | } 37 | 38 | public static bool operator ==(VertexPositionNormalTexture left, VertexPositionNormalTexture right) 39 | { 40 | return left.Equals(right); 41 | } 42 | 43 | public static bool operator !=(VertexPositionNormalTexture left, VertexPositionNormalTexture right) 44 | { 45 | return !left.Equals(right); 46 | } 47 | 48 | public override string ToString() 49 | { 50 | return string.Format("Position: {0}, Normal: {1}, Texcoord: {2}", this.Position, this.Normal, this.TextureCoordinate); 51 | } 52 | 53 | /// 54 | /// XYZ position. 55 | /// 56 | //[VertexElement("SV_Position")] 57 | public Vector3 Position; 58 | 59 | /// 60 | /// The vertex normal. 61 | /// 62 | //[VertexElement("NORMAL")] 63 | public Vector3 Normal; 64 | 65 | /// 66 | /// UV texture coordinates. 67 | /// 68 | //[VertexElement("TEXCOORD0")] 69 | public Vector2 TextureCoordinate; 70 | 71 | /// 72 | /// Defines structure byte size. 73 | /// 74 | public static readonly int Size = 32; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /lib/CS/Run8/R8Explorer/MainForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace R8Explorer 2 | { 3 | partial class MainForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | menuStrip1 = new MenuStrip(); 32 | fileToolStripMenuItem = new ToolStripMenuItem(); 33 | openToolStripMenuItem = new ToolStripMenuItem(); 34 | menuStrip1.SuspendLayout(); 35 | SuspendLayout(); 36 | // 37 | // menuStrip1 38 | // 39 | menuStrip1.Items.AddRange(new ToolStripItem[] { fileToolStripMenuItem }); 40 | menuStrip1.Location = new Point(0, 0); 41 | menuStrip1.Name = "menuStrip1"; 42 | menuStrip1.Size = new Size(800, 24); 43 | menuStrip1.TabIndex = 0; 44 | menuStrip1.Text = "menuStrip1"; 45 | // 46 | // fileToolStripMenuItem 47 | // 48 | fileToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { openToolStripMenuItem }); 49 | fileToolStripMenuItem.Name = "fileToolStripMenuItem"; 50 | fileToolStripMenuItem.Size = new Size(37, 20); 51 | fileToolStripMenuItem.Text = "File"; 52 | // 53 | // openToolStripMenuItem 54 | // 55 | openToolStripMenuItem.Name = "openToolStripMenuItem"; 56 | openToolStripMenuItem.Size = new Size(180, 20); 57 | openToolStripMenuItem.Text = "Open"; 58 | openToolStripMenuItem.Click += openToolStripMenuItem_Click; 59 | // 60 | // MainForm 61 | // 62 | AutoScaleDimensions = new SizeF(7F, 15F); 63 | AutoScaleMode = AutoScaleMode.Font; 64 | BackColor = Color.FromArgb(18, 18, 18); 65 | ClientSize = new Size(800, 450); 66 | Controls.Add(menuStrip1); 67 | MainMenuStrip = menuStrip1; 68 | Name = "MainForm"; 69 | Text = "Run8 Explorer"; 70 | menuStrip1.ResumeLayout(false); 71 | menuStrip1.PerformLayout(); 72 | ResumeLayout(false); 73 | PerformLayout(); 74 | } 75 | 76 | #endregion 77 | 78 | private MenuStrip menuStrip1; 79 | private ToolStripMenuItem fileToolStripMenuItem; 80 | private ToolStripMenuItem openToolStripMenuItem; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /lib/CS/Run8/R8Explorer/MainForm.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | namespace R8Explorer 4 | { 5 | public partial class MainForm : Form 6 | { 7 | public MainForm() 8 | { 9 | InitializeComponent(); 10 | } 11 | 12 | private void openToolStripMenuItem_Click(object sender, EventArgs e) 13 | { 14 | // open file picker 15 | OpenFileDialog openFileDialog = new OpenFileDialog(); 16 | openFileDialog.Filter = FileFilterManager.GetOpenFileDialogFilter(); 17 | openFileDialog.Title = "Open Run8 Train Simulator File"; 18 | var res = openFileDialog.ShowDialog(); 19 | 20 | if (res == DialogResult.OK) 21 | { 22 | // open file 23 | // Process.Start(openFileDialog.FileName); 24 | MessageBox.Show("Opening file: " + openFileDialog.FileName); 25 | } 26 | 27 | openFileDialog.Dispose(); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/CS/Run8/R8Explorer/Program.cs: -------------------------------------------------------------------------------- 1 | namespace R8Explorer 2 | { 3 | internal static class Program 4 | { 5 | /// 6 | /// The main entry point for the application. 7 | /// 8 | [STAThread] 9 | static void Main() 10 | { 11 | // To customize application configuration such as set high DPI settings or default font, 12 | // see https://aka.ms/applicationconfiguration. 13 | ApplicationConfiguration.Initialize(); 14 | Application.Run(new MainForm()); 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /lib/CS/Run8/R8Explorer/R8Explorer.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | WinExe 5 | net6.0-windows 6 | enable 7 | true 8 | enable 9 | AnyCPU;x64 10 | 11 | 12 | -------------------------------------------------------------------------------- /lib/CS/Run8/R8Explorer/Run8Version.cs: -------------------------------------------------------------------------------- 1 | namespace R8Explorer 2 | { 3 | public enum Run8Version 4 | { 5 | V3, 6 | V2, 7 | Any 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /lib/CS/Run8/RN8ToObj/ColladaConverter.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | enable 8 | AnyCPU;x64 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /lib/CS/Run8/RN8ToObj/Program.cs: -------------------------------------------------------------------------------- 1 | using LibRun8.Formats; 2 | 3 | namespace RN8ToDae 4 | { 5 | internal class Program 6 | { 7 | static int Main(string[] args) 8 | { 9 | if (args.Length == 0) 10 | { 11 | Console.WriteLine("No file specified"); 12 | return 1; 13 | } 14 | 15 | string inputFilePath = args[0]; 16 | string inputFileName, inputFileExt, inputFileWithoutExt; 17 | 18 | if (!File.Exists(inputFilePath)) 19 | { 20 | Console.WriteLine("File does not exist: " + inputFilePath); 21 | return 1; 22 | } 23 | 24 | inputFileName = Path.GetFileName(inputFilePath); 25 | inputFileExt = Path.GetExtension(inputFilePath); 26 | inputFileWithoutExt = Path.GetFileNameWithoutExtension(inputFilePath); 27 | 28 | if (inputFileExt.ToLower() != ".rn8") 29 | { 30 | Console.WriteLine("File is not a .rn8 file: " + inputFilePath); 31 | return 1; 32 | } 33 | 34 | try 35 | { 36 | Model model = Model.Read(inputFilePath); 37 | model.WriteCollada(inputFileWithoutExt + ".dae"); 38 | Console.WriteLine("Conversion of " + inputFileName + ": OK"); 39 | return 0; 40 | } 41 | catch (Exception ex) 42 | { 43 | Console.WriteLine("Conversion of " + inputFileName + ": FAILED"); 44 | Console.WriteLine(ex.Message); 45 | return 1; 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /lib/CS/Run8/RN8ToObj/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "RN8ToObj": { 4 | "commandName": "Project", 5 | "commandLineArgs": "\"E:\\Program Files\\Run8Studios\\Run8 Train Simulator V3\\Content\\V3RailVehicles\\Body\\R8_C449W_BNSF04.rn8\"" 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /lib/CS/Run8/Test/Test.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | enable 8 | AnyCPU;x64 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /lib/CS/Run8/TextureTools/Program.cs: -------------------------------------------------------------------------------- 1 | using LibRun8.Util; 2 | using System.CommandLine; 3 | 4 | namespace TextureTool 5 | { 6 | internal class Program 7 | { 8 | static async Task Main(string[] args) 9 | { 10 | var rootCommand = new RootCommand("Run8 Texture Tool"); 11 | var decryptCommand = new Command("decrypt", "Convert tx8 to dds"); 12 | var encryptCommand = new Command("encrypt", "Convert dds to tx8"); 13 | 14 | var fileArgument = new Argument("file", "File to convert"); 15 | decryptCommand.Add(fileArgument); 16 | encryptCommand.Add(fileArgument); 17 | 18 | rootCommand.Add(decryptCommand); 19 | rootCommand.Add(encryptCommand); 20 | 21 | decryptCommand.SetHandler((file) => 22 | { 23 | try 24 | { 25 | Decrypt(file); 26 | } catch(Exception e) 27 | { 28 | Console.WriteLine("Decryption of file '" + file.Name + "' failed: " + e.Message); 29 | } 30 | }, 31 | fileArgument); 32 | 33 | encryptCommand.SetHandler((file) => 34 | { 35 | try 36 | { 37 | Encrypt(file); 38 | } 39 | catch (Exception e) 40 | { 41 | Console.WriteLine("Encryption of file '" + file.Name + "' failed: " + e.Message); 42 | } 43 | }, 44 | fileArgument); 45 | 46 | return await rootCommand.InvokeAsync(args); 47 | } 48 | 49 | private static void Decrypt(FileInfo file) 50 | { 51 | Texture.Decrypt(file); 52 | } 53 | 54 | private static void Encrypt(FileInfo file) 55 | { 56 | Texture.Encrypt(file); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /lib/CS/Run8/TextureTools/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "TextureTool": { 4 | "commandName": "Project", 5 | "commandLineArgs": "decrypt \"E:\\Run8Studios\\Run8 Train Simulator V3\\Content\\V3RailVehicles\\Body\\R8_BethgonII_BNSF01_0.tx8\"" 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /lib/CS/Run8/TextureTools/TextureTool.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | enable 8 | AnyCPU;x64 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /misc/README.md: -------------------------------------------------------------------------------- 1 | other random bs -------------------------------------------------------------------------------- /misc/ksy/README.md: -------------------------------------------------------------------------------- 1 | kaitai structs 2 | -------------------------------------------------------------------------------- /misc/ksy/compile.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | kaitai-struct-compiler -t python -d lib_run8\kaitai --python-package lib_run8.kaitai ksy\*.ksy -------------------------------------------------------------------------------- /misc/ksy/gen_docs.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | for %%f in (ksy\*.ksy) do ( 4 | python generate_docs.py "%%f" "..\..\docs" 5 | ) -------------------------------------------------------------------------------- /misc/ksy/ksy/ai_signal_database.ksy: -------------------------------------------------------------------------------- 1 | doc: Contains a list of AI Signals 2 | meta: 3 | id: ai_signal_database 4 | title: AISignalDatabase (AISignalDatabase.r8) 5 | application: Run8 Train Simulator 6 | file-extension: r8 7 | endian: le 8 | imports: 9 | - common 10 | seq: 11 | - id: reserved 12 | type: s4 13 | - id: num_entries 14 | type: s4 15 | - id: entries 16 | type: ai_signal 17 | repeat: expr 18 | repeat-expr: num_entries 19 | 20 | types: 21 | ai_signal: 22 | seq: 23 | - id: reserved 24 | type: s4 25 | - id: num_entries 26 | type: s4 27 | - id: entries 28 | type: s4 29 | repeat: expr 30 | repeat-expr: num_entries 31 | - id: bool1 32 | type: common::boolean 33 | - id: int1 34 | type: s4 35 | - id: int2 36 | type: s4 37 | - id: bool2 38 | type: common::boolean 39 | - id: class_341_1 40 | type: class_341 41 | if: bool2.is_true 42 | doc: c:Only if bool2 is true 43 | - id: bool3 44 | type: common::boolean 45 | - id: class_341_2 46 | type: class_341 47 | if: bool3.is_true 48 | doc: c:Only if bool3 is true 49 | class_341: 50 | seq: 51 | - id: int1 52 | type: s4 53 | - id: int2 54 | type: s4 55 | -------------------------------------------------------------------------------- /misc/ksy/ksy/ai_special_locations.ksy: -------------------------------------------------------------------------------- 1 | doc: Contains a list of AI Special Locations 2 | meta: 3 | id: ai_special_locations 4 | title: AISpecialLocations (AISpecialLocations.r8) 5 | application: Run8 Train Simulator 6 | file-extension: r8 7 | endian: le 8 | imports: 9 | - common 10 | seq: 11 | - id: reserved 12 | type: s4 13 | - id: num_entries 14 | type: s4 15 | - id: entries 16 | type: ai_special_location 17 | repeat: expr 18 | repeat-expr: num_entries 19 | 20 | types: 21 | ai_special_location: 22 | seq: 23 | - id: reserved 24 | type: s4 25 | - id: name 26 | type: common::r8string 27 | - id: type 28 | type: u1 29 | enum: ai_special_location_type 30 | - id: int1 31 | type: s4 32 | - id: int2 33 | type: s4 34 | - id: int3 35 | type: s4 36 | - id: float1 37 | type: f4 38 | - id: int4 39 | type: s4 40 | - id: bool1 41 | type: common::boolean 42 | 43 | enums: 44 | ai_special_location_type: 45 | 0: spawn_point 46 | 1: crew_change 47 | 2: crew_change_and_hold 48 | 3: passenger 49 | 4: passenger_crew_change 50 | 5: passenger_crew_change_and_hold 51 | 6: reliquish 52 | 7: passenger_reliquish 53 | -------------------------------------------------------------------------------- /misc/ksy/ksy/ai_track_speed_database.ksy: -------------------------------------------------------------------------------- 1 | doc: Contains a list of AI Track Speeds 2 | meta: 3 | id: ai_track_speed_database 4 | title: AITrackSpeedDatabase (AITrackSpeedDatabase.r8) 5 | application: Run8 Train Simulator 6 | file-extension: r8 7 | endian: le 8 | imports: 9 | - common 10 | seq: 11 | - id: reserved 12 | type: s4 13 | - id: num_entries 14 | type: s4 15 | - id: entries 16 | type: ai_track_speed 17 | repeat: expr 18 | repeat-expr: num_entries 19 | 20 | types: 21 | ai_track_speed: 22 | seq: 23 | - id: reserved 24 | type: s4 25 | - id: int1 26 | type: s4 27 | - id: num_entries 28 | type: s4 29 | - id: entries 30 | type: class_322 31 | repeat: expr 32 | repeat-expr: num_entries 33 | class_322: 34 | seq: 35 | - id: reserved 36 | type: s4 37 | - id: int1 38 | type: s4 39 | - id: int2 40 | type: s4 41 | - id: int3 42 | type: s4 43 | -------------------------------------------------------------------------------- /misc/ksy/ksy/common.ksy: -------------------------------------------------------------------------------- 1 | doc: "Common Types\n\n 2 | ## Encoding Strings\n 3 | ```c#\n 4 | string s = \"1ST COAST RECYCLING\";\n 5 | byte[] bytes = Encoding.UTF8.GetBytes(s);\n 6 | byte[] encoded = new byte[bytes.Length * 2];\n 7 | int num = 0;\n 8 | for (int i = 0; i < bytes.Length; i++)\n 9 | {\n 10 | \tencoded[num++] = (byte)(bytes[i] >> 4);\n 11 | \tencoded[num++] = (byte)(bytes[i] << 4);\n 12 | }\n 13 | ```\n\n 14 | ## Decoding Strings\n 15 | ```c#\n 16 | byte[] encoded = ;\n 17 | byte[] decodedBytes = new byte[encoded.Length / 2];\n 18 | int num = 0;\n 19 | for (int i = 0; i < decodedBytes.Length; i++)\n 20 | {\n 21 | \tdecodedBytes[i] |= (byte)(encoded[num++] << 4);\n 22 | \tdecodedBytes[i] |= (byte)(encoded[num++] >> 4);\n 23 | }\n\n 24 | string decodedString = Encoding.UTF8.GetString(decodedBytes);\n 25 | ```" 26 | meta: 27 | id: common 28 | title: Common 29 | application: Run8 Train Simulator V3 30 | endian: le 31 | ks-opaque-types: true 32 | types: 33 | r8string: 34 | doc: Run8 specific string format 35 | seq: 36 | - id: len_value 37 | type: s4 38 | doc: d:Length of the encoded string, x2 len of decoded string 39 | - id: value 40 | size: len_value 41 | process: lib_run8.string_utils.decode_run8_string(len_value) 42 | doc: d:Decoded string 43 | cs_string: 44 | doc: C# style string 45 | seq: 46 | - id: len 47 | type: u1 48 | doc: d:Length of the string as a 7 bit encoded int 49 | - id: value 50 | type: str 51 | encoding: UTF-8 52 | size: len 53 | vector2: 54 | seq: 55 | - id: x 56 | type: f4 57 | - id: y 58 | type: f4 59 | vector3: 60 | seq: 61 | - id: x 62 | type: f4 63 | - id: y 64 | type: f4 65 | - id: z 66 | type: f4 67 | tilexz: 68 | seq: 69 | - id: x 70 | type: s4 71 | - id: z 72 | type: s4 73 | matrix4: 74 | seq: 75 | - id: m11 76 | type: f4 77 | - id: m12 78 | type: f4 79 | - id: m13 80 | type: f4 81 | - id: m14 82 | type: f4 83 | - id: m21 84 | type: f4 85 | - id: m22 86 | type: f4 87 | - id: m23 88 | type: f4 89 | - id: m24 90 | type: f4 91 | - id: m31 92 | type: f4 93 | - id: m32 94 | type: f4 95 | - id: m33 96 | type: f4 97 | - id: m34 98 | type: f4 99 | - id: m41 100 | type: f4 101 | - id: m42 102 | type: f4 103 | - id: m43 104 | type: f4 105 | - id: m44 106 | type: f4 107 | color: 108 | seq: 109 | - id: a 110 | type: u1 111 | - id: r 112 | type: u1 113 | - id: g 114 | type: u1 115 | - id: b 116 | type: u1 117 | boolean: 118 | doc: This is just a bullshit stub 119 | seq: 120 | - id: value 121 | type: u1 122 | instances: 123 | is_true: 124 | value: value != 0 125 | is_false: 126 | value: value == 0 127 | -------------------------------------------------------------------------------- /misc/ksy/ksy/key_settings.ksy: -------------------------------------------------------------------------------- 1 | doc: Stores game keybind settings 2 | meta: 3 | id: key_settings 4 | title: Key Settings (Run8KeySettings.r8) 5 | application: Run8 Train Simulator 6 | file-extension: r8 7 | endian: le 8 | imports: 9 | - common 10 | seq: 11 | - id: reserved 12 | type: s4 13 | - id: num_settings 14 | type: s4 15 | - id: settings 16 | type: key_setting 17 | repeat: expr 18 | repeat-expr: num_settings 19 | 20 | types: 21 | key_setting: 22 | seq: 23 | - id: reserved 24 | type: s4 25 | - id: name 26 | type: common::r8string 27 | - id: enum70 28 | type: s1 29 | - id: num_keys 30 | type: s4 31 | - id: keys 32 | type: s4 33 | repeat: expr 34 | repeat-expr: num_keys 35 | -------------------------------------------------------------------------------- /misc/ksy/ksy/service_area_database.ksy: -------------------------------------------------------------------------------- 1 | meta: 2 | id: service_area_database 3 | title: ServiceAreaDatabase (ServiceAreaDatabase.r8) 4 | application: Run8 Train Simulator 5 | file-extension: r8 6 | endian: le 7 | imports: 8 | - common 9 | seq: 10 | - id: reserved 11 | type: s4 12 | - id: num_service_areas 13 | type: s4 14 | - id: service_areas 15 | type: service_area 16 | repeat: expr 17 | repeat-expr: num_service_areas 18 | 19 | types: 20 | service_area: 21 | seq: 22 | - id: num 23 | type: s4 24 | - id: path1 25 | type: path1 26 | if: num == 1 27 | doc: c:Only if num == 1 28 | - id: path2 29 | type: path2 30 | if: num == 2 31 | doc: c:Only if num == 2 32 | path1: 33 | seq: 34 | - id: tile_xz 35 | type: common::tilexz 36 | - id: position 37 | type: common::vector3 38 | - id: float0 39 | type: f4 40 | - id: bool0 41 | type: common::boolean 42 | - id: bool1 43 | type: common::boolean 44 | - id: bool2 45 | type: common::boolean 46 | - id: bool3 47 | type: common::boolean 48 | path2: 49 | seq: 50 | - id: tile_xz 51 | type: common::tilexz 52 | - id: position 53 | type: common::vector3 54 | - id: float0 55 | type: f4 56 | - id: class646 57 | type: class646 58 | class646: 59 | seq: 60 | - id: enum50_0 61 | type: s1 62 | - id: enum60_0 63 | type: s1 64 | - id: double1 65 | type: f8 66 | - id: double2 67 | type: f8 68 | -------------------------------------------------------------------------------- /misc/ksy/ksy/stars4.ksy: -------------------------------------------------------------------------------- 1 | doc: Contains a list of strings, including file paths. Strings are referenced by their index. 2 | meta: 3 | id: stars4 4 | title: Stars4 (stars4.r8) 5 | application: Run8 Train Simulator 6 | file-extension: rn8 7 | endian: le 8 | imports: 9 | - common 10 | seq: 11 | - id: reserved 12 | type: s4 13 | - id: num_entries 14 | type: s4 15 | - id: entries 16 | type: common::r8string 17 | repeat: expr 18 | repeat-expr: num_entries 19 | -------------------------------------------------------------------------------- /misc/ksy/ksy/tilescenery.ksy: -------------------------------------------------------------------------------- 1 | meta: 2 | id: tile_scenery 3 | title: Tile Scenery File 4 | application: Run8 Train Simulator 5 | file-extension: rn8 6 | endian: le 7 | imports: 8 | - common 9 | seq: 10 | - id: num_assets 11 | type: s4 12 | - id: assets 13 | type: asset 14 | repeat: expr 15 | repeat-expr: num_assets 16 | types: 17 | asset: 18 | seq: 19 | - id: num_decals 20 | type: s4 21 | - id: decals 22 | type: decal 23 | repeat: expr 24 | repeat-expr: num_decals 25 | - id: disregard_bounding_test 26 | type: s1 27 | - id: model_name 28 | type: common::cs_string 29 | - id: position 30 | type: common::vector3 31 | - id: rotation 32 | type: common::vector3 33 | - id: scale 34 | type: common::vector3 35 | - id: tile_xz 36 | type: common::tilexz 37 | decal: 38 | seq: 39 | - id: color_r 40 | type: f4 41 | - id: color_g 42 | type: f4 43 | - id: color_b 44 | type: f4 45 | - id: num_digits 46 | type: s4 47 | - id: digits 48 | type: digit 49 | repeat: expr 50 | repeat-expr: num_digits 51 | - id: offset 52 | type: common::vector3 53 | - id: rotation_deg 54 | type: common::vector3 55 | - id: size 56 | type: f4 57 | - id: texture_name 58 | type: common::cs_string 59 | digit: 60 | seq: 61 | - id: digit 62 | type: s4 63 | -------------------------------------------------------------------------------- /misc/ksy/ksy/tr2.ksy: -------------------------------------------------------------------------------- 1 | meta: 2 | id: terrain_tr2 3 | title: TR2 Terrain Tile 4 | application: Run8 Train Simulator 5 | file-extension: tr2 6 | endian: le 7 | imports: 8 | - common 9 | seq: 10 | - id: texture_1 11 | type: common::cs_string 12 | - id: texture_2 13 | type: common::cs_string 14 | - id: texture_3 15 | type: common::cs_string 16 | - id: texture_4 17 | type: common::cs_string 18 | - id: chunks 19 | type: chunk_row 20 | repeat: expr 21 | repeat-expr: 25 22 | doc: d:Tile X; Tiles are 25x25 chunks 23 | - id: lon_east 24 | type: f4 25 | - id: lon_west 26 | type: f4 27 | - id: lat_north 28 | type: f4 29 | - id: lat_south 30 | type: f4 31 | types: 32 | chunk_row: 33 | seq: 34 | - id: chunks 35 | type: chunk 36 | repeat: expr 37 | repeat-expr: 25 38 | doc: d:Tile Y; Tiles are 25x25 chunks 39 | chunk: 40 | seq: 41 | - id: chunk_size 42 | type: u4 43 | doc: d:Number of elevation points in this chunk 44 | - id: elevations_row 45 | type: elevation_col 46 | repeat: expr 47 | repeat-expr: chunk_size 48 | doc: d:Chunk X 49 | elevation_col: 50 | seq: 51 | - id: elevation 52 | type: f4 53 | repeat: expr 54 | repeat-expr: _parent.chunk_size 55 | doc: d:Chunk Y 56 | -------------------------------------------------------------------------------- /misc/ksy/lib_run8/kaitai/ai_signal_database.py: -------------------------------------------------------------------------------- 1 | # This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild 2 | # type: ignore 3 | 4 | import kaitaistruct 5 | from kaitaistruct import KaitaiStruct, KaitaiStream, BytesIO 6 | from lib_run8.kaitai import common 7 | 8 | 9 | if getattr(kaitaistruct, 'API_VERSION', (0, 9)) < (0, 11): 10 | raise Exception("Incompatible Kaitai Struct Python API: 0.11 or later is required, but you have %s" % (kaitaistruct.__version__)) 11 | 12 | class AiSignalDatabase(KaitaiStruct): 13 | """Contains a list of AI Signals.""" 14 | def __init__(self, _io, _parent=None, _root=None): 15 | self._io = _io 16 | self._parent = _parent 17 | self._root = _root if _root else self 18 | self._read() 19 | 20 | def _read(self): 21 | self.reserved = self._io.read_s4le() 22 | self.num_entries = self._io.read_s4le() 23 | self.entries = [] 24 | for i in range(self.num_entries): 25 | self.entries.append(AiSignalDatabase.AiSignal(self._io, self, self._root)) 26 | 27 | 28 | class AiSignal(KaitaiStruct): 29 | def __init__(self, _io, _parent=None, _root=None): 30 | self._io = _io 31 | self._parent = _parent 32 | self._root = _root 33 | self._read() 34 | 35 | def _read(self): 36 | self.reserved = self._io.read_s4le() 37 | self.num_entries = self._io.read_s4le() 38 | self.entries = [] 39 | for i in range(self.num_entries): 40 | self.entries.append(self._io.read_s4le()) 41 | 42 | self.bool1 = common.Common.Boolean(self._io) 43 | self.int1 = self._io.read_s4le() 44 | self.int2 = self._io.read_s4le() 45 | self.bool2 = common.Common.Boolean(self._io) 46 | if self.bool2.is_true: 47 | self.class_341_1 = AiSignalDatabase.Class341(self._io, self, self._root) 48 | 49 | self.bool3 = common.Common.Boolean(self._io) 50 | if self.bool3.is_true: 51 | self.class_341_2 = AiSignalDatabase.Class341(self._io, self, self._root) 52 | 53 | 54 | 55 | class Class341(KaitaiStruct): 56 | def __init__(self, _io, _parent=None, _root=None): 57 | self._io = _io 58 | self._parent = _parent 59 | self._root = _root 60 | self._read() 61 | 62 | def _read(self): 63 | self.int1 = self._io.read_s4le() 64 | self.int2 = self._io.read_s4le() 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /misc/ksy/lib_run8/kaitai/ai_special_locations.py: -------------------------------------------------------------------------------- 1 | # This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild 2 | # type: ignore 3 | 4 | import kaitaistruct 5 | from kaitaistruct import KaitaiStruct, KaitaiStream, BytesIO 6 | from lib_run8.kaitai import common 7 | from enum import IntEnum 8 | 9 | 10 | if getattr(kaitaistruct, 'API_VERSION', (0, 9)) < (0, 11): 11 | raise Exception("Incompatible Kaitai Struct Python API: 0.11 or later is required, but you have %s" % (kaitaistruct.__version__)) 12 | 13 | class AiSpecialLocations(KaitaiStruct): 14 | """Contains a list of AI Special Locations.""" 15 | 16 | class AiSpecialLocationType(IntEnum): 17 | spawn_point = 0 18 | crew_change = 1 19 | crew_change_and_hold = 2 20 | passenger = 3 21 | passenger_crew_change = 4 22 | passenger_crew_change_and_hold = 5 23 | reliquish = 6 24 | passenger_reliquish = 7 25 | def __init__(self, _io, _parent=None, _root=None): 26 | self._io = _io 27 | self._parent = _parent 28 | self._root = _root if _root else self 29 | self._read() 30 | 31 | def _read(self): 32 | self.reserved = self._io.read_s4le() 33 | self.num_entries = self._io.read_s4le() 34 | self.entries = [] 35 | for i in range(self.num_entries): 36 | self.entries.append(AiSpecialLocations.AiSpecialLocation(self._io, self, self._root)) 37 | 38 | 39 | class AiSpecialLocation(KaitaiStruct): 40 | def __init__(self, _io, _parent=None, _root=None): 41 | self._io = _io 42 | self._parent = _parent 43 | self._root = _root 44 | self._read() 45 | 46 | def _read(self): 47 | self.reserved = self._io.read_s4le() 48 | self.name = common.Common.R8string(self._io) 49 | self.type = KaitaiStream.resolve_enum(AiSpecialLocations.AiSpecialLocationType, self._io.read_u1()) 50 | self.int1 = self._io.read_s4le() 51 | self.int2 = self._io.read_s4le() 52 | self.int3 = self._io.read_s4le() 53 | self.float1 = self._io.read_f4le() 54 | self.int4 = self._io.read_s4le() 55 | self.bool1 = common.Common.Boolean(self._io) 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /misc/ksy/lib_run8/kaitai/ai_track_speed_database.py: -------------------------------------------------------------------------------- 1 | # This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild 2 | # type: ignore 3 | 4 | import kaitaistruct 5 | from kaitaistruct import KaitaiStruct, KaitaiStream, BytesIO 6 | 7 | 8 | if getattr(kaitaistruct, 'API_VERSION', (0, 9)) < (0, 11): 9 | raise Exception("Incompatible Kaitai Struct Python API: 0.11 or later is required, but you have %s" % (kaitaistruct.__version__)) 10 | 11 | class AiTrackSpeedDatabase(KaitaiStruct): 12 | """Contains a list of AI Track Speeds.""" 13 | def __init__(self, _io, _parent=None, _root=None): 14 | self._io = _io 15 | self._parent = _parent 16 | self._root = _root if _root else self 17 | self._read() 18 | 19 | def _read(self): 20 | self.reserved = self._io.read_s4le() 21 | self.num_entries = self._io.read_s4le() 22 | self.entries = [] 23 | for i in range(self.num_entries): 24 | self.entries.append(AiTrackSpeedDatabase.AiTrackSpeed(self._io, self, self._root)) 25 | 26 | 27 | class AiTrackSpeed(KaitaiStruct): 28 | def __init__(self, _io, _parent=None, _root=None): 29 | self._io = _io 30 | self._parent = _parent 31 | self._root = _root 32 | self._read() 33 | 34 | def _read(self): 35 | self.reserved = self._io.read_s4le() 36 | self.int1 = self._io.read_s4le() 37 | self.num_entries = self._io.read_s4le() 38 | self.entries = [] 39 | for i in range(self.num_entries): 40 | self.entries.append(AiTrackSpeedDatabase.Class322(self._io, self, self._root)) 41 | 42 | 43 | 44 | class Class322(KaitaiStruct): 45 | def __init__(self, _io, _parent=None, _root=None): 46 | self._io = _io 47 | self._parent = _parent 48 | self._root = _root 49 | self._read() 50 | 51 | def _read(self): 52 | self.reserved = self._io.read_s4le() 53 | self.int1 = self._io.read_s4le() 54 | self.int2 = self._io.read_s4le() 55 | self.int3 = self._io.read_s4le() 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /misc/ksy/lib_run8/kaitai/key_settings.py: -------------------------------------------------------------------------------- 1 | # This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild 2 | # type: ignore 3 | 4 | import kaitaistruct 5 | from kaitaistruct import KaitaiStruct, KaitaiStream, BytesIO 6 | from lib_run8.kaitai import common 7 | 8 | 9 | if getattr(kaitaistruct, 'API_VERSION', (0, 9)) < (0, 11): 10 | raise Exception("Incompatible Kaitai Struct Python API: 0.11 or later is required, but you have %s" % (kaitaistruct.__version__)) 11 | 12 | class KeySettings(KaitaiStruct): 13 | """Stores game keybind settings.""" 14 | def __init__(self, _io, _parent=None, _root=None): 15 | self._io = _io 16 | self._parent = _parent 17 | self._root = _root if _root else self 18 | self._read() 19 | 20 | def _read(self): 21 | self.reserved = self._io.read_s4le() 22 | self.num_settings = self._io.read_s4le() 23 | self.settings = [] 24 | for i in range(self.num_settings): 25 | self.settings.append(KeySettings.KeySetting(self._io, self, self._root)) 26 | 27 | 28 | class KeySetting(KaitaiStruct): 29 | def __init__(self, _io, _parent=None, _root=None): 30 | self._io = _io 31 | self._parent = _parent 32 | self._root = _root 33 | self._read() 34 | 35 | def _read(self): 36 | self.reserved = self._io.read_s4le() 37 | self.name = common.Common.R8string(self._io) 38 | self.enum70 = self._io.read_s1() 39 | self.num_keys = self._io.read_s4le() 40 | self.keys = [] 41 | for i in range(self.num_keys): 42 | self.keys.append(self._io.read_s4le()) 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /misc/ksy/lib_run8/kaitai/service_area_database.py: -------------------------------------------------------------------------------- 1 | # This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild 2 | # type: ignore 3 | 4 | import kaitaistruct 5 | from kaitaistruct import KaitaiStruct, KaitaiStream, BytesIO 6 | from lib_run8.kaitai import common 7 | 8 | 9 | if getattr(kaitaistruct, 'API_VERSION', (0, 9)) < (0, 11): 10 | raise Exception("Incompatible Kaitai Struct Python API: 0.11 or later is required, but you have %s" % (kaitaistruct.__version__)) 11 | 12 | class ServiceAreaDatabase(KaitaiStruct): 13 | def __init__(self, _io, _parent=None, _root=None): 14 | self._io = _io 15 | self._parent = _parent 16 | self._root = _root if _root else self 17 | self._read() 18 | 19 | def _read(self): 20 | self.reserved = self._io.read_s4le() 21 | self.num_service_areas = self._io.read_s4le() 22 | self.service_areas = [] 23 | for i in range(self.num_service_areas): 24 | self.service_areas.append(ServiceAreaDatabase.ServiceArea(self._io, self, self._root)) 25 | 26 | 27 | class Class646(KaitaiStruct): 28 | def __init__(self, _io, _parent=None, _root=None): 29 | self._io = _io 30 | self._parent = _parent 31 | self._root = _root 32 | self._read() 33 | 34 | def _read(self): 35 | self.enum50_0 = self._io.read_s1() 36 | self.enum60_0 = self._io.read_s1() 37 | self.double1 = self._io.read_f8le() 38 | self.double2 = self._io.read_f8le() 39 | 40 | 41 | class Path1(KaitaiStruct): 42 | def __init__(self, _io, _parent=None, _root=None): 43 | self._io = _io 44 | self._parent = _parent 45 | self._root = _root 46 | self._read() 47 | 48 | def _read(self): 49 | self.tile_xz = common.Common.Tilexz(self._io) 50 | self.position = common.Common.Vector3(self._io) 51 | self.float0 = self._io.read_f4le() 52 | self.bool0 = common.Common.Boolean(self._io) 53 | self.bool1 = common.Common.Boolean(self._io) 54 | self.bool2 = common.Common.Boolean(self._io) 55 | self.bool3 = common.Common.Boolean(self._io) 56 | 57 | 58 | class Path2(KaitaiStruct): 59 | def __init__(self, _io, _parent=None, _root=None): 60 | self._io = _io 61 | self._parent = _parent 62 | self._root = _root 63 | self._read() 64 | 65 | def _read(self): 66 | self.tile_xz = common.Common.Tilexz(self._io) 67 | self.position = common.Common.Vector3(self._io) 68 | self.float0 = self._io.read_f4le() 69 | self.class646 = ServiceAreaDatabase.Class646(self._io, self, self._root) 70 | 71 | 72 | class ServiceArea(KaitaiStruct): 73 | def __init__(self, _io, _parent=None, _root=None): 74 | self._io = _io 75 | self._parent = _parent 76 | self._root = _root 77 | self._read() 78 | 79 | def _read(self): 80 | self.num = self._io.read_s4le() 81 | if self.num == 1: 82 | self.path1 = ServiceAreaDatabase.Path1(self._io, self, self._root) 83 | 84 | if self.num == 2: 85 | self.path2 = ServiceAreaDatabase.Path2(self._io, self, self._root) 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /misc/ksy/lib_run8/kaitai/stars4.py: -------------------------------------------------------------------------------- 1 | # This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild 2 | # type: ignore 3 | 4 | import kaitaistruct 5 | from kaitaistruct import KaitaiStruct, KaitaiStream, BytesIO 6 | from lib_run8.kaitai import common 7 | 8 | 9 | if getattr(kaitaistruct, 'API_VERSION', (0, 9)) < (0, 11): 10 | raise Exception("Incompatible Kaitai Struct Python API: 0.11 or later is required, but you have %s" % (kaitaistruct.__version__)) 11 | 12 | class Stars4(KaitaiStruct): 13 | """Contains a list of strings, including file paths. Strings are referenced by their index.""" 14 | def __init__(self, _io, _parent=None, _root=None): 15 | self._io = _io 16 | self._parent = _parent 17 | self._root = _root if _root else self 18 | self._read() 19 | 20 | def _read(self): 21 | self.reserved = self._io.read_s4le() 22 | self.num_entries = self._io.read_s4le() 23 | self.entries = [] 24 | for i in range(self.num_entries): 25 | self.entries.append(common.Common.R8string(self._io)) 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /misc/ksy/lib_run8/kaitai/terrain_tr2.py: -------------------------------------------------------------------------------- 1 | # This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild 2 | # type: ignore 3 | 4 | import kaitaistruct 5 | from kaitaistruct import KaitaiStruct, KaitaiStream, BytesIO 6 | from lib_run8.kaitai import common 7 | 8 | 9 | if getattr(kaitaistruct, 'API_VERSION', (0, 9)) < (0, 11): 10 | raise Exception("Incompatible Kaitai Struct Python API: 0.11 or later is required, but you have %s" % (kaitaistruct.__version__)) 11 | 12 | class TerrainTr2(KaitaiStruct): 13 | def __init__(self, _io, _parent=None, _root=None): 14 | self._io = _io 15 | self._parent = _parent 16 | self._root = _root if _root else self 17 | self._read() 18 | 19 | def _read(self): 20 | self.texture_1 = common.Common.CsString(self._io) 21 | self.texture_2 = common.Common.CsString(self._io) 22 | self.texture_3 = common.Common.CsString(self._io) 23 | self.texture_4 = common.Common.CsString(self._io) 24 | self.chunks = [] 25 | for i in range(25): 26 | self.chunks.append(TerrainTr2.ChunkRow(self._io, self, self._root)) 27 | 28 | self.lon_east = self._io.read_f4le() 29 | self.lon_west = self._io.read_f4le() 30 | self.lat_north = self._io.read_f4le() 31 | self.lat_south = self._io.read_f4le() 32 | 33 | class Chunk(KaitaiStruct): 34 | def __init__(self, _io, _parent=None, _root=None): 35 | self._io = _io 36 | self._parent = _parent 37 | self._root = _root 38 | self._read() 39 | 40 | def _read(self): 41 | self.chunk_size = self._io.read_u4le() 42 | self.elevations_row = [] 43 | for i in range(self.chunk_size): 44 | self.elevations_row.append(TerrainTr2.ElevationCol(self._io, self, self._root)) 45 | 46 | 47 | 48 | class ChunkRow(KaitaiStruct): 49 | def __init__(self, _io, _parent=None, _root=None): 50 | self._io = _io 51 | self._parent = _parent 52 | self._root = _root 53 | self._read() 54 | 55 | def _read(self): 56 | self.chunks = [] 57 | for i in range(25): 58 | self.chunks.append(TerrainTr2.Chunk(self._io, self, self._root)) 59 | 60 | 61 | 62 | class ElevationCol(KaitaiStruct): 63 | def __init__(self, _io, _parent=None, _root=None): 64 | self._io = _io 65 | self._parent = _parent 66 | self._root = _root 67 | self._read() 68 | 69 | def _read(self): 70 | self.elevation = [] 71 | for i in range(self._parent.chunk_size): 72 | self.elevation.append(self._io.read_f4le()) 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /misc/ksy/lib_run8/kaitai/tile_scenery.py: -------------------------------------------------------------------------------- 1 | # This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild 2 | # type: ignore 3 | 4 | import kaitaistruct 5 | from kaitaistruct import KaitaiStruct, KaitaiStream, BytesIO 6 | from lib_run8.kaitai import common 7 | 8 | 9 | if getattr(kaitaistruct, 'API_VERSION', (0, 9)) < (0, 11): 10 | raise Exception("Incompatible Kaitai Struct Python API: 0.11 or later is required, but you have %s" % (kaitaistruct.__version__)) 11 | 12 | class TileScenery(KaitaiStruct): 13 | def __init__(self, _io, _parent=None, _root=None): 14 | self._io = _io 15 | self._parent = _parent 16 | self._root = _root if _root else self 17 | self._read() 18 | 19 | def _read(self): 20 | self.num_assets = self._io.read_s4le() 21 | self.assets = [] 22 | for i in range(self.num_assets): 23 | self.assets.append(TileScenery.Asset(self._io, self, self._root)) 24 | 25 | 26 | class Asset(KaitaiStruct): 27 | def __init__(self, _io, _parent=None, _root=None): 28 | self._io = _io 29 | self._parent = _parent 30 | self._root = _root 31 | self._read() 32 | 33 | def _read(self): 34 | self.num_decals = self._io.read_s4le() 35 | self.decals = [] 36 | for i in range(self.num_decals): 37 | self.decals.append(TileScenery.Decal(self._io, self, self._root)) 38 | 39 | self.disregard_bounding_test = self._io.read_s1() 40 | self.model_name = common.Common.CsString(self._io) 41 | self.position = common.Common.Vector3(self._io) 42 | self.rotation = common.Common.Vector3(self._io) 43 | self.scale = common.Common.Vector3(self._io) 44 | self.tile_xz = common.Common.Tilexz(self._io) 45 | 46 | 47 | class Decal(KaitaiStruct): 48 | def __init__(self, _io, _parent=None, _root=None): 49 | self._io = _io 50 | self._parent = _parent 51 | self._root = _root 52 | self._read() 53 | 54 | def _read(self): 55 | self.color_r = self._io.read_f4le() 56 | self.color_g = self._io.read_f4le() 57 | self.color_b = self._io.read_f4le() 58 | self.num_digits = self._io.read_s4le() 59 | self.digits = [] 60 | for i in range(self.num_digits): 61 | self.digits.append(TileScenery.Digit(self._io, self, self._root)) 62 | 63 | self.offset = common.Common.Vector3(self._io) 64 | self.rotation_deg = common.Common.Vector3(self._io) 65 | self.size = self._io.read_f4le() 66 | self.texture_name = common.Common.CsString(self._io) 67 | 68 | 69 | class Digit(KaitaiStruct): 70 | def __init__(self, _io, _parent=None, _root=None): 71 | self._io = _io 72 | self._parent = _parent 73 | self._root = _root 74 | self._read() 75 | 76 | def _read(self): 77 | self.digit = self._io.read_s4le() 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /misc/ksy/lib_run8/kaitai/tr2.py: -------------------------------------------------------------------------------- 1 | # This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild 2 | # type: ignore 3 | 4 | import kaitaistruct 5 | from kaitaistruct import KaitaiStruct, KaitaiStream, BytesIO 6 | from lib_run8.kaitai import common 7 | 8 | 9 | if getattr(kaitaistruct, 'API_VERSION', (0, 9)) < (0, 11): 10 | raise Exception("Incompatible Kaitai Struct Python API: 0.11 or later is required, but you have %s" % (kaitaistruct.__version__)) 11 | 12 | class Tr2(KaitaiStruct): 13 | def __init__(self, _io, _parent=None, _root=None): 14 | self._io = _io 15 | self._parent = _parent 16 | self._root = _root if _root else self 17 | self._read() 18 | 19 | def _read(self): 20 | self.texture_1 = common.Common.CsString(self._io) 21 | self.texture_2 = common.Common.CsString(self._io) 22 | self.texture_3 = common.Common.CsString(self._io) 23 | self.texture_4 = common.Common.CsString(self._io) 24 | self.chunks = [] 25 | for i in range(25): 26 | self.chunks.append(Tr2.ChunkRow(self._io, self, self._root)) 27 | 28 | self.lon_east = self._io.read_f4le() 29 | self.lon_west = self._io.read_f4le() 30 | self.lat_north = self._io.read_f4le() 31 | self.lat_south = self._io.read_f4le() 32 | 33 | class Chunk(KaitaiStruct): 34 | def __init__(self, _io, _parent=None, _root=None): 35 | self._io = _io 36 | self._parent = _parent 37 | self._root = _root 38 | self._read() 39 | 40 | def _read(self): 41 | self.chunk_size = self._io.read_u4le() 42 | self.elevations_row = [] 43 | for i in range(self.chunk_size): 44 | self.elevations_row.append(Tr2.ElevationCol(self._io, self, self._root)) 45 | 46 | 47 | 48 | class ChunkRow(KaitaiStruct): 49 | def __init__(self, _io, _parent=None, _root=None): 50 | self._io = _io 51 | self._parent = _parent 52 | self._root = _root 53 | self._read() 54 | 55 | def _read(self): 56 | self.chunks = [] 57 | for i in range(25): 58 | self.chunks.append(Tr2.Chunk(self._io, self, self._root)) 59 | 60 | 61 | 62 | class ElevationCol(KaitaiStruct): 63 | def __init__(self, _io, _parent=None, _root=None): 64 | self._io = _io 65 | self._parent = _parent 66 | self._root = _root 67 | self._read() 68 | 69 | def _read(self): 70 | self.elevation = [] 71 | for i in range(self._parent.chunk_size): 72 | self.elevation.append(self._io.read_f4le()) 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /misc/ksy/lib_run8/string_utils.py: -------------------------------------------------------------------------------- 1 | from kaitaistruct import KaitaiStruct 2 | 3 | 4 | class DecodeRun8String(KaitaiStruct): 5 | def __init__(self, len_buf): 6 | super().__init__(len_buf) 7 | self.len = len_buf 8 | 9 | def decode(self, data: bytes) -> str: 10 | size = self.len // 2 11 | array = bytearray(size) 12 | num = 0 13 | for i in range(size): 14 | array[i] |= data[num] << 4 15 | num += 1 16 | array[i] |= data[num] >> 4 17 | num += 1 18 | return array.decode("utf8") 19 | -------------------------------------------------------------------------------- /misc/ksy/lib_run8/visualizer.py: -------------------------------------------------------------------------------- 1 | # converted to python from ruby by chatgpt 2 | # Original source: https://github.com/kaitai-io/kaitai_struct_visualizer/blob/master/lib/kaitai/struct/visualizer/obj_to_h.rb 3 | 4 | from kaitaistruct import KaitaiStruct 5 | 6 | 7 | class KaitaiStructVisualizer: 8 | @staticmethod 9 | def obj_to_h(obj): 10 | if isinstance(obj, (bool, int, float, type(None))): 11 | return obj 12 | elif isinstance(obj, str): 13 | try: 14 | obj.encode("ascii") 15 | return obj 16 | except UnicodeEncodeError: 17 | return " ".join(f"{ord(c):02X}" for c in obj) 18 | elif isinstance(obj, list): 19 | return [KaitaiStructVisualizer.obj_to_h(x) for x in obj] 20 | elif isinstance(obj, KaitaiStruct): 21 | root = {} 22 | for attr in dir(obj): 23 | if not attr.startswith("_") and not callable(getattr(obj, attr)): 24 | value = getattr(obj, attr) 25 | v = KaitaiStructVisualizer.obj_to_h(value) 26 | if v is not None: 27 | root[attr] = v 28 | return root 29 | else: 30 | print(type(obj).__name__) 31 | return f"OPAQUE ({type(obj).__name__})" 32 | -------------------------------------------------------------------------------- /misc/terrain_exporter/rename.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | dir_path = Path("heightmaps") 4 | 5 | for file in dir_path.glob("*.bin"): 6 | name = file.name 7 | split, y = name.split(".")[0].split("Y") 8 | x = split.split("X")[1] 9 | 10 | # new name should be x_y + ext 11 | new_name = f"{x}_{y}.bin" 12 | file.rename(dir_path / new_name) 13 | -------------------------------------------------------------------------------- /misc/terrain_exporter/view.py: -------------------------------------------------------------------------------- 1 | import struct 2 | import tkinter as tk 3 | from tkinter import filedialog, messagebox 4 | 5 | import matplotlib.pyplot as plt 6 | import numpy as np 7 | from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg 8 | from matplotlib.figure import Figure 9 | 10 | 11 | class ImageViewer: 12 | def __init__(self, root): 13 | self.root = root 14 | root.title("F32 Image Viewer") 15 | root.geometry("800x600") 16 | 17 | # Create matplotlib figure 18 | self.figure = Figure(figsize=(8, 6)) 19 | self.ax = self.figure.add_subplot(111) 20 | self.canvas = FigureCanvasTkAgg(self.figure, master=root) 21 | self.canvas.draw() 22 | self.canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True) 23 | 24 | # Add open button 25 | open_button = tk.Button(root, text="Open File", command=self.open_file) 26 | open_button.pack(pady=5) 27 | 28 | def read_f32_image(self, file_path): 29 | with open(file_path, "rb") as f: 30 | # Read width and height from header (2 int32s) 31 | width, height = struct.unpack("ii", f.read(8)) 32 | 33 | # read bounds (4 float 32s) 34 | bounds = struct.unpack("ffff", f.read(16)) 35 | 36 | # Read the rest as float32 data 37 | data = np.fromfile(f, dtype=np.float32) 38 | 39 | if width * height != len(data): 40 | raise ValueError(f"File data length {len(data)} doesn't match dimensions {width}x{height}") 41 | 42 | return data.reshape(height, width) 43 | 44 | def open_file(self): 45 | file_path = filedialog.askopenfilename(title="Open F32 Image", filetypes=[("Binary Files", "*.bin")]) 46 | 47 | if file_path: 48 | try: 49 | image_data = self.read_f32_image(file_path) 50 | self.display_image(image_data) 51 | except Exception as e: 52 | messagebox.showerror("Error", str(e)) 53 | 54 | def display_image(self, image_data): 55 | self.ax.clear() 56 | vmin, vmax = np.percentile(image_data, [2, 98]) 57 | im = self.ax.imshow(image_data, cmap="viridis", vmin=vmin, vmax=vmax) 58 | self.figure.colorbar(im, ax=self.ax, label="Intensity") 59 | self.ax.set_title(f"Image: {image_data.shape[1]}x{image_data.shape[0]}") 60 | self.canvas.draw() 61 | 62 | 63 | def main(): 64 | root = tk.Tk() 65 | viewer = ImageViewer(root) 66 | root.mainloop() 67 | 68 | 69 | if __name__ == "__main__": 70 | main() 71 | -------------------------------------------------------------------------------- /misc_scripts/binwriter.py: -------------------------------------------------------------------------------- 1 | import struct 2 | from io import SEEK_CUR 3 | from typing import BinaryIO 4 | 5 | ENDIAN_PREFIXES = ("@", "<", ">", "=", "!") 6 | 7 | 8 | class BinaryWriter: 9 | def __init__(self, buf: BinaryIO, endian: str = "<") -> None: 10 | self.buf = buf 11 | self.endian = endian 12 | 13 | def align(self) -> None: 14 | old = self.tell() 15 | new = (old + 3) & -4 16 | if new > old: 17 | self.seek(new - old, SEEK_CUR) 18 | 19 | def write(self, *args) -> int: 20 | return self.buf.write(*args) 21 | 22 | def seek(self, *args) -> int: 23 | return self.buf.seek(*args) 24 | 25 | def tell(self) -> int: 26 | return self.buf.tell() 27 | 28 | def write_string(self, value: str, encoding: str = "utf-8") -> int: 29 | """ 30 | Writes a 7 bit prefixed string to the buffer. 31 | """ 32 | encoded_string = value.encode(encoding) 33 | size = self.write_7bit_encoded_int(len(encoded_string)) 34 | size += self.write(encoded_string) 35 | 36 | return size 37 | 38 | def write_cstring(self, value: str) -> int: 39 | return self.write_string(value + "\0") 40 | 41 | def write_7bit_encoded_int(self, value: int) -> int: 42 | while value >= 128: 43 | self.write(bytes([((value & 0x7F) | 0x80)])) 44 | value >>= 7 45 | return self.write(bytes([value])) 46 | 47 | def write_bool(self, value: bool) -> int: 48 | return self.write(struct.pack(self.endian + "b", int(value))) 49 | 50 | def write_byte(self, value: int) -> int: 51 | return self.write(struct.pack(self.endian + "b", value)) 52 | 53 | def write_ubyte(self, value: int) -> int: 54 | return self.write(struct.pack(self.endian + "B", value)) 55 | 56 | def write_int16(self, value: int) -> int: 57 | return self.write(struct.pack(self.endian + "h", value)) 58 | 59 | def write_uint16(self, value: int) -> int: 60 | return self.write(struct.pack(self.endian + "H", value)) 61 | 62 | def write_int32(self, value: int) -> int: 63 | return self.write(struct.pack(self.endian + "i", value)) 64 | 65 | def write_uint32(self, value: int) -> int: 66 | return self.write(struct.pack(self.endian + "I", value)) 67 | 68 | def write_int64(self, value: int) -> int: 69 | return self.write(struct.pack(self.endian + "q", value)) 70 | 71 | def write_uint64(self, value: int) -> int: 72 | return self.write(struct.pack(self.endian + "Q", value)) 73 | 74 | def write_float(self, value: float) -> int: 75 | return self.write(struct.pack(self.endian + "f", value)) 76 | 77 | def write_double(self, value: float) -> int: 78 | return self.write(struct.pack(self.endian + "d", value)) 79 | 80 | def write_struct(self, format: str, *values) -> int: 81 | if not format.startswith(ENDIAN_PREFIXES): 82 | format = self.endian + format 83 | data = struct.pack(format, *values) 84 | return self.write(data) 85 | 86 | # Aliases 87 | def write_int(self, value: int) -> int: 88 | return self.write_int32(value) 89 | 90 | def write_uint(self, value: int) -> int: 91 | return self.write_uint32(value) 92 | -------------------------------------------------------------------------------- /misc_scripts/gen_terrain_tr2.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import math 3 | 4 | import numpy as np 5 | import rasterio 6 | 7 | from binwriter import BinaryWriter 8 | 9 | CHUNKS_X = 25 10 | CHUNKS_Z = 25 11 | TILE_X = 1026.0822 # meters 12 | TILE_Z = 844.3211 # meters 13 | CHUNK_SIZE_X = TILE_X / CHUNKS_X 14 | CHUNK_SIZE_Z = TILE_Z / CHUNKS_Z 15 | 16 | 17 | def main(file: str): 18 | with rasterio.open("./tiles/0_1.tif") as heightmap: 19 | height_values = heightmap.read(1) 20 | 21 | HIXELS = height_values.shape[1] // CHUNKS_Z 22 | print(f"Hixels per chunk per side: {HIXELS}") 23 | 24 | x_points_required = CHUNKS_X * HIXELS 25 | z_points_required = CHUNKS_Z * HIXELS 26 | 27 | x_points_available = height_values.shape[0] 28 | z_points_available = height_values.shape[1] 29 | 30 | if x_points_available < x_points_required: 31 | print(f"Not enough x points available: {x_points_available} < {x_points_required}") 32 | else: 33 | print(f"X points available: {x_points_available} >= {x_points_required}") 34 | 35 | if z_points_available < z_points_required: 36 | print(f"Not enough z points available: {z_points_available} < {z_points_required}") 37 | else: 38 | print(f"Z points available: {z_points_available} >= {z_points_required}") 39 | 40 | min_x_value = np.amin(height_values, axis=0) 41 | min_z_value = np.amin(height_values, axis=1) 42 | 43 | min_x_value = np.min(min_x_value) 44 | min_z_value = np.min(min_z_value) 45 | 46 | with open(file, "wb") as f: 47 | writer = BinaryWriter(f) 48 | 49 | # writer texture names 50 | writer.write_cstring("sandy") 51 | writer.write_cstring("jwg_greenGrass") 52 | writer.write_cstring("jwg_cameron02") 53 | writer.write_cstring("jwg_goldenGrass") 54 | 55 | for x in range(CHUNKS_X): 56 | for z in range(CHUNKS_Z): 57 | writer.write_int32(HIXELS) 58 | for cx in range(HIXELS): 59 | for cz in range(HIXELS): 60 | x_idx = x * HIXELS + cx 61 | z_idx = z * HIXELS + cz 62 | 63 | if x_idx >= x_points_available or z_idx >= z_points_available: 64 | value = min_x_value 65 | else: 66 | value = height_values[x_idx, z_idx] 67 | if value < 0: 68 | print("oops") 69 | value = math.fabs(value) 70 | writer.write_float(value) 71 | 72 | 73 | if __name__ == "__main__": 74 | parser = argparse.ArgumentParser(description="Generate TR2 terrain") 75 | parser.add_argument("file", help="Output file") 76 | 77 | args = parser.parse_args() 78 | 79 | main(args.file) 80 | -------------------------------------------------------------------------------- /misc_scripts/get_latlon_center.py: -------------------------------------------------------------------------------- 1 | def calculate_bounds_center(north, south, east, west): 2 | center_lat = (north + south) / 2 3 | center_lng = (east + west) / 2 4 | return center_lat, center_lng 5 | 6 | 7 | def calculate_size_bounds(north, south, east, west): 8 | lat_size = north - south 9 | lng_size = east - west 10 | return lat_size, lng_size 11 | 12 | 13 | north = 40.46984100341797 14 | east = -78.58444213867188 15 | south = 40.460601806640625 16 | west = -78.59439849853516 17 | 18 | print(calculate_bounds_center(north, south, east, west)) 19 | print(calculate_size_bounds(north, south, east, west)) 20 | -------------------------------------------------------------------------------- /misc_scripts/obj_to_rn8.py: -------------------------------------------------------------------------------- 1 | from io import BytesIO 2 | 3 | from binwriter import BinaryWriter 4 | 5 | positions = [] 6 | normals = [] 7 | uvs = [] 8 | vertices = [] 9 | 10 | # First pass: read data 11 | with open("./test.obj", "r") as f: 12 | for line in f.readlines(): 13 | line = line.strip() 14 | if not line or line.startswith("#"): 15 | continue 16 | 17 | parts = line.split() 18 | typ = parts[0] 19 | 20 | if typ == "v": 21 | # Read positions - note these are larger values than your working model 22 | x, y, z = map(float, parts[1:]) 23 | # Scale down the positions to match working model scale 24 | positions.append((x, y, z)) 25 | elif typ == "vt": 26 | u, v = map(float, parts[1:]) 27 | uvs.append((u, v)) 28 | elif typ == "vn": 29 | x, y, z = map(float, parts[1:]) 30 | normals.append((x, y, z)) 31 | elif typ == "f": 32 | # Process face indices 33 | for vert in parts[1:]: 34 | v_idx, t_idx, n_idx = map(lambda x: int(x) - 1, vert.split("/")) 35 | vertex = {"position": positions[v_idx], "normal": normals[n_idx], "uv": uvs[t_idx]} 36 | vertices.append(vertex) 37 | 38 | # Now write the file 39 | buf = BytesIO() 40 | writer = BinaryWriter(buf) 41 | 42 | # Write vertex count 43 | writer.write_int32(len(vertices) * 7) 44 | 45 | # Write each vertex 46 | for i, vertex in enumerate(vertices): 47 | pos = vertex["position"] 48 | norm = vertex["normal"] 49 | uv = vertex["uv"] 50 | 51 | writer.write_float(0.0) # unused 52 | writer.write_float(pos[0]) # pos x - already at correct scale 53 | writer.write_float(norm[1]) # normal y 54 | writer.write_float(pos[2]) # pos z 55 | writer.write_float(uv[0] * 4.8) # uv x 56 | writer.write_float(norm[0]) # normal x 57 | writer.write_float(0.0) # unused 58 | writer.write_float(norm[2]) # normal z 59 | writer.write_float(uv[1] * 9.6) # uv y 60 | writer.write_float(pos[1]) # pos y 61 | 62 | # Write texture count (-6 for testing) 63 | writer.write_int32(-6) 64 | 65 | # Write index buffer format (32-bit) 66 | writer.write_bool(False) 67 | 68 | # Write indices - just sequential since we expanded vertices 69 | index_count = len(vertices) 70 | writer.write_int32(index_count) 71 | for i in range(index_count): 72 | writer.write_int32(i) 73 | 74 | # Write definition count 75 | writer.write_int32(9) 76 | 77 | with open("./R8_Caboose_c509_SP01.rn8", "wb") as f: 78 | f.write(buf.getvalue()) 79 | -------------------------------------------------------------------------------- /misc_scripts/parse_tr2.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | 3 | from binreader import BinaryReader 4 | 5 | 6 | def main(file): 7 | with open(file, "rb") as f: 8 | reader = BinaryReader(f) 9 | 10 | all_points = [] 11 | 12 | print(reader.read_cs_string()) 13 | print(reader.read_cs_string()) 14 | print(reader.read_cs_string()) 15 | print(reader.read_cs_string()) 16 | 17 | # read chunks 18 | for x in range(25): 19 | for y in range(25): 20 | # read chunk hixels 21 | hixels = reader.read_int32() 22 | print(f"{x},{y} = {hixels}") 23 | for cx in range(hixels): 24 | for cy in range(hixels): 25 | value = reader.read_float() 26 | # print(f"{x},{y},{cx},{cy} = {value}") 27 | all_points.append(value) 28 | print(f"Total Points: {len(all_points)}") 29 | 30 | 31 | if __name__ == "__main__": 32 | parser = argparse.ArgumentParser(description="Parse TR2 terrain") 33 | parser.add_argument("file", help="Input file") 34 | 35 | args = parser.parse_args() 36 | 37 | main(args.file) 38 | -------------------------------------------------------------------------------- /misc_scripts/skydome_test.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import hashlib 3 | from pathlib import Path 4 | 5 | from binreader import BinaryReader 6 | 7 | 8 | def compute_file_hash(filepath: str) -> str: 9 | md5 = hashlib.md5() 10 | with open(filepath, "rb") as f: 11 | for chunk in iter(lambda: f.read(4096), b""): 12 | md5.update(chunk) 13 | 14 | return md5.hexdigest() 15 | 16 | 17 | def main(folder_path: str): 18 | exe_path = Path(folder_path, "Run-8 Train Simulator V3.exe") 19 | skydome_path = Path(folder_path, "Content", "Misc", "SkyDomeData.rn8") 20 | 21 | if not exe_path.exists(): 22 | raise FileNotFoundError(f"Could not find Run-8 Train Simulator V3.exe at {exe_path}") 23 | 24 | if not skydome_path.exists(): 25 | raise FileNotFoundError(f"Could not find SkyDomeData.rn8 at {skydome_path}") 26 | 27 | file_hash = compute_file_hash(exe_path).encode("utf-8") 28 | 29 | with open(skydome_path, "rb") as f: 30 | size = f.seek(0, 2) 31 | assert size == 38888, f"Expected 38888 bytes, got {size} bytes" 32 | f.seek(0) 33 | 34 | reader = BinaryReader(f) 35 | data = [] 36 | hash_data = bytearray(len(file_hash)) 37 | 38 | i = 0 39 | while i < 9722: 40 | data.append(reader.read_int32()) 41 | i += 1 42 | 43 | num = data[17] # 17 is the index of the file hash length 44 | assert num == len(file_hash), "Expected index 17 to be the length of the file hash" 45 | 46 | i = 0 47 | while i < num: 48 | num2 = data[i + 18] 49 | hash_data[i] = data[num2] 50 | i += 1 51 | 52 | hash_data = bytes(hash_data) 53 | assert file_hash.decode("utf-8").upper() == hash_data.decode("utf-8").upper(), "File hash does not match" 54 | 55 | print("Hashes match") 56 | 57 | 58 | if __name__ == "__main__": 59 | parser = argparse.ArgumentParser(description="SkyDomeData test parser") 60 | parser.add_argument("path", help="Path to run8v3 folder") 61 | 62 | args = parser.parse_args() 63 | main(args.path) 64 | -------------------------------------------------------------------------------- /misc_scripts/split_geotif.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | from math import ceil 3 | from pathlib import Path 4 | 5 | import numpy as np 6 | from osgeo import gdal 7 | 8 | 9 | def split_geotiff_into_tiles(input_tiff, tile_width_meters=844.3211, tile_height_meters=1026.0822): 10 | ds = gdal.Open(input_tiff) 11 | gt = ds.GetGeoTransform() 12 | pixel_width = abs(gt[1]) 13 | pixel_height = abs(gt[5]) 14 | 15 | tile_width_pixels = int(ceil(tile_width_meters / pixel_width)) 16 | tile_height_pixels = int(ceil(tile_height_meters / pixel_height)) 17 | 18 | width = ds.RasterXSize 19 | height = ds.RasterYSize 20 | 21 | num_tiles_x = width // tile_width_pixels 22 | num_tiles_y = height // tile_height_pixels 23 | 24 | for i in range(num_tiles_y): 25 | for j in range(num_tiles_x): 26 | print(f"Processing tile {i}, {j}") 27 | x_start = j * tile_width_pixels 28 | y_start = i * tile_height_pixels 29 | 30 | output_file = Path("tiles", f"{i}_{j}.tif") 31 | output_file.parent.mkdir(exist_ok=True, parents=True) 32 | gdal.Translate( 33 | str(output_file), ds, srcWin=[x_start, y_start, tile_width_pixels, tile_height_pixels], format="GTiff" 34 | ) 35 | 36 | 37 | if __name__ == "__main__": 38 | parser = argparse.ArgumentParser(description="Split a geotiff into tiles") 39 | parser.add_argument("input_tiff", help="Input geotiff file") 40 | parser.add_argument("--tile_width", type=float, default=844.3211, help="Width of each tile in meters") 41 | parser.add_argument("--tile_height", type=float, default=1026.0822, help="Height of each tile in meters") 42 | 43 | args = parser.parse_args() 44 | 45 | split_geotiff_into_tiles(args.input_tiff, args.tile_width, args.tile_height) 46 | -------------------------------------------------------------------------------- /misc_scripts/structs.py: -------------------------------------------------------------------------------- 1 | class Vector2: 2 | def __init__(self, x: float, y: float) -> None: 3 | self.x = x 4 | self.y = y 5 | 6 | def __str__(self) -> str: 7 | return f"Vector2({self.x}, {self.y})" 8 | 9 | 10 | class Vector3: 11 | def __init__(self, x: float, y: float, z: float) -> None: 12 | self.x = x 13 | self.y = y 14 | self.z = z 15 | 16 | def __str__(self) -> str: 17 | return f"Vector3({self.x}, {self.y}, {self.z})" 18 | 19 | 20 | class Vector4: 21 | def __init__(self, x: float, y: float, z: float, w: float) -> None: 22 | self.x = x 23 | self.y = y 24 | self.z = z 25 | self.w = w 26 | 27 | def __str__(self) -> str: 28 | return f"Vector4({self.x}, {self.y}, {self.z}, {self.w})" 29 | -------------------------------------------------------------------------------- /misc_scripts/structs2.py: -------------------------------------------------------------------------------- 1 | from construct import Array, Float32l, GreedyBytes, Int8sl, Int8ul, Int32ul, Struct, this 2 | 3 | 4 | def encode_7bit_int(length): 5 | result = bytearray() 6 | while length >= 0x80: 7 | result.append((length & 0x7F) | 0x80) 8 | length >>= 7 9 | result.append(length) 10 | return bytes(result) 11 | 12 | 13 | def build_cs_string(text): 14 | encoded_text = text.encode("utf8") 15 | length_prefix = encode_7bit_int(len(encoded_text)) 16 | return length_prefix + encoded_text 17 | 18 | 19 | Chunk = Struct( 20 | "hixel_count" / Int32ul, 21 | "hixels" / Array(this.hixel_count, Array(this.hixel_count, Float32l)), 22 | ) 23 | 24 | Vector3 = Struct( 25 | "x" / Float32l, 26 | "y" / Float32l, 27 | "z" / Float32l, 28 | ) 29 | 30 | Vector4 = Struct( 31 | "x" / Float32l, 32 | "y" / Float32l, 33 | "z" / Float32l, 34 | "w" / Float32l, 35 | ) 36 | 37 | TileIndex = Struct( 38 | "x" / Int32ul, 39 | "y" / Int32ul, 40 | ) 41 | 42 | Decal = Struct( 43 | "r" / Float32l, 44 | "g" / Float32l, 45 | "b" / Float32l, 46 | "digit_count" / Int32ul, 47 | "digits" / Array(this.digit_count, Int32ul), 48 | "offset" / Vector3, 49 | "rotation" / Vector3, 50 | "size" / Float32l, 51 | "texture_name" / GreedyBytes, 52 | ) 53 | 54 | SceneryAsset = Struct( 55 | "decal_count" / Int32ul, 56 | "decals" / Array(this.decal_count, Decal), 57 | "disregard_bounding_test" / Int8ul, 58 | "model_name" / GreedyBytes, 59 | "position" / Vector3, 60 | "rotation" / Vector3, 61 | "scale" / Vector3, 62 | "tile_index" / TileIndex, 63 | ) 64 | 65 | TR4 = Struct( 66 | "texture_1" / GreedyBytes, 67 | "texture_2" / GreedyBytes, 68 | "texture_3" / GreedyBytes, 69 | "texture_4" / GreedyBytes, 70 | "chunks" / Array(25, Array(25, Chunk)), 71 | "east" / Float32l, 72 | "west" / Float32l, 73 | "north" / Float32l, 74 | "south" / Float32l, 75 | "veg_texture" / GreedyBytes, 76 | "scenery_asset_count" / Int32ul, 77 | "scenery_assets" / Array(this.scenery_asset_count, SceneryAsset), 78 | "plant_count" / Int32ul, 79 | "plants" / Array(this.plant_count, Vector4), 80 | "reserved" / Int32ul, 81 | "weight_map" / Int8sl, 82 | ) 83 | 84 | TR2 = Struct( 85 | "texture_1" / GreedyBytes, 86 | "texture_2" / GreedyBytes, 87 | "texture_3" / GreedyBytes, 88 | "texture_4" / GreedyBytes, 89 | "chunks" / Array(25, Array(25, Chunk)), 90 | "east" / Float32l, 91 | "west" / Float32l, 92 | "north" / Float32l, 93 | "south" / Float32l, 94 | "veg_texture" / GreedyBytes, 95 | ) 96 | -------------------------------------------------------------------------------- /misc_scripts/tr4_to_tr2.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import io 3 | import zlib 4 | 5 | from binreader import BinaryReader 6 | 7 | 8 | def main(file): 9 | with open(file, "rb") as f: 10 | data = f.read() 11 | data = zlib.decompress(data, -15) 12 | 13 | reader = BinaryReader(io.BytesIO(data)) 14 | 15 | print(reader.read_cs_string()) 16 | print(reader.read_cs_string()) 17 | print(reader.read_cs_string()) 18 | print(reader.read_cs_string()) 19 | 20 | chunks = [] 21 | min_value = 9999999 22 | max_value = -9999999 23 | 24 | # heightmap 25 | for x in range(25): 26 | for y in range(25): 27 | # read chunk hixels 28 | hixel_count = reader.read_int32() 29 | print(f"Chunk at {x},{y} has a density of {hixel_count}x{hixel_count} points") 30 | 31 | chunk_points = [] 32 | for cx in range(hixel_count): 33 | for cy in range(hixel_count): 34 | value = reader.read_float() 35 | # print(f"{x},{y},{cx},{cy} = {value}") 36 | chunk_points.append(value) 37 | min_value = min(min_value, value) 38 | max_value = max(max_value, value) 39 | 40 | print(f"Chunk at {x},{y} has {len(chunk_points)} points") 41 | chunks.append(chunk_points) 42 | print(f"Total Points: {sum([len(x) for y in chunk_points for x in chunks])}") 43 | 44 | # find the min and max values 45 | print(f"Min: {min_value}") 46 | print(f"Max: {max_value}") 47 | 48 | try: 49 | print(f"East: {reader.read_float()}") 50 | print(f"West: {reader.read_float()}") 51 | print(f"North: {reader.read_float()}") 52 | print(f"South: {reader.read_float()}") 53 | print(reader.read_cs_string()) 54 | except: 55 | pass 56 | 57 | size = reader.tell() 58 | reader.seek(0) 59 | data = reader.read(size) 60 | with open("output.tr2", "wb") as f: 61 | f.write(data) 62 | 63 | 64 | if __name__ == "__main__": 65 | parser = argparse.ArgumentParser(description="Convert TR4 to TR2") 66 | parser.add_argument("file", help="TR2 File") 67 | 68 | args = parser.parse_args() 69 | 70 | main(args.file) 71 | -------------------------------------------------------------------------------- /misc_scripts/updater.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | import os 3 | 4 | import requests 5 | 6 | URL = "http://www.run8-services.com/v3autoupdater/v3autoupdate.php" 7 | FILE_DOWNLOAD_URL = "http://www.run8-services.com/v3autoupdater/v3autoupdate_dl.php" 8 | BASE_PATH = "D:\\Programs\\Run8Studios\\Run8 Train Simulator V3" 9 | OUTDATED_LIST = [] 10 | FILES: dict[str, str] = {} 11 | 12 | 13 | def smethod_5(dirname: str): 14 | return ( 15 | "V3Routes" in dirname 16 | and not "VegTextures" in dirname 17 | and not "TrackTextures" in dirname 18 | and not "TerrainTextures" in dirname 19 | and not "Splendid Assets" in dirname 20 | and not "Regions" in dirname 21 | ) 22 | 23 | 24 | def compute_file_hash(path: str): 25 | with open(path, "rb") as f: 26 | return hashlib.md5(f.read()).hexdigest().lower() 27 | 28 | 29 | def check_files(): 30 | OUTDATED_LIST.clear() 31 | 32 | for file in FILES.keys(): 33 | rpath = file 34 | hash_ = FILES[file] 35 | 36 | apath = BASE_PATH + rpath 37 | dirname = os.path.dirname(apath) 38 | 39 | if os.path.exists(dirname) and (not smethod_5(dirname) or os.path.exists(dirname + "/TrackDatabase.r8")): 40 | if os.path.exists(apath): 41 | file_hash = compute_file_hash(apath) 42 | if file_hash != hash_.lower(): 43 | OUTDATED_LIST.append(rpath) 44 | else: 45 | OUTDATED_LIST.append(rpath) 46 | 47 | 48 | def download_file(name: str): 49 | try: 50 | r = requests.post(FILE_DOWNLOAD_URL, data={"xyz": "123", "filename": name}) 51 | 52 | if r.ok: 53 | apath = BASE_PATH + name 54 | with open(apath, "wb") as f: 55 | f.write(r.content) 56 | except Exception as e: 57 | print(e) 58 | 59 | 60 | def main(): 61 | print("Fetching manifest...") 62 | data = {"xyz": "123"} 63 | r = requests.post(URL, data=data) 64 | 65 | if r.ok: 66 | for text in list(filter(None, r.text.split("jwg96main"))): 67 | k, v = list(filter(None, text.split(";"))) 68 | FILES[k] = v 69 | 70 | print("Checking local files against manifest...") 71 | check_files() 72 | 73 | print(f"{len(OUTDATED_LIST)} outdated files") 74 | 75 | if len(OUTDATED_LIST) == 0: 76 | print("Already up to date") 77 | exit(0) 78 | 79 | for file in OUTDATED_LIST: 80 | print(f"Downloading file: {file} ({OUTDATED_LIST.index(file) + 1}/{len(OUTDATED_LIST)})") 81 | 82 | download_file(file) 83 | 84 | print("Checking for errors...") 85 | check_files() 86 | 87 | if len(OUTDATED_LIST) > 0: 88 | print(f"Update failure! {len(OUTDATED_LIST)} files failed to verify") 89 | else: 90 | print("Update complete") 91 | else: 92 | print("Failed to get manifest.") 93 | 94 | 95 | if __name__ == "__main__": 96 | main() 97 | --------------------------------------------------------------------------------