### Minimal Map Creation Example Source: https://github.com/sk-zk/trucklib/blob/master/README.md A basic example demonstrating how to create a new map, add a model, and save it. Ensure the output path is correctly formatted for your ETS2 installation. ```csharp using System.Numerics; using TruckLib.ScsMap; var map = new Map("example"); Model.Add(map, new Vector3(10, 0, 10), "dlc_no_471", "brick", "default"); map.Save(@"\mod\user_map\map"); ``` -------------------------------- ### Install TruckLib via NuGet Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/introduction.md Use the .NET CLI to add the TruckLib package to your project. ```bash dotnet add package TruckLib ``` -------------------------------- ### Create Items Along Path (Simple) Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/TruckLib.ScsMap/polyline-items.md Places Model items at equidistant intervals along a path defined by start and end polyline items. The callback function defines how each item is created. ```cs PolylineItem.CreateItemsAlongPath(start, end, 10f, (container, point) => { Model model = Model.Add(container, point.Position, "greece_29000", "var1", "default"); model.Node.Rotation = point.Rotation; return [model]; }); ``` -------------------------------- ### Instantiate a new map Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/Samples/01-simple.md Initializes an empty map object. This is the starting point for all map creation tasks. ```cs using TruckLib.ScsMap; var map = new Map(); ``` -------------------------------- ### Find First and Last Polyline Items Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/TruckLib.ScsMap/polyline-items.md Retrieves the first and last polyline items in a chain starting from a given member item. The returned items may not be of the same type as the starting item. ```cs PolylineItem start = road.FindFirstItem(); PolylineItem end = road.FindLastItem(); ``` -------------------------------- ### Initialize projection parameters Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/Samples/03-realroad.md Sets up the source and destination coordinate systems and calculates a map center point. ```csharp var sourceCrs = KnownCoordinateSystems.Geographic.World.WGS1984; var destCrs = KnownCoordinateSystems.Projected.UtmWgs1984.WGS1984UTMZone32N; var points = Project(coordinatesWithElevation, sourceCrs, destCrs); ``` ```csharp var center = Project(new[] { new GeographicCoordinate(54.744101, 9.799639) }, sourceCrs, destCrs)[0]; ``` -------------------------------- ### Create and Configure Roads in C# Source: https://context7.com/sk-zk/trucklib/llms.txt Use Road.Add to initialize a road with terrain and configure appearance, vegetation, and roadside models. Append additional segments to extend the road path. ```csharp using System.Numerics; using TruckLib.ScsMap; var map = new Map(); // Add a road item with terrain var road = Road.Add(map, new Vector3(19, 0, 19.5f), // backward (red) node position new Vector3(65, 0, 23), // forward (green) node position "ger1", // road type unit name 80, 80 // terrain size left/right in meters ); // Configure road appearance (for single carriageways, set on Right side) road.Right.Look = "ger_1"; road.Right.Variant = "broken_de"; road.Right.LeftEdge = "ger_sh_15"; road.Right.RightEdge = "ger_sh_15"; // Configure terrain and vegetation on both sides foreach (var side in new[] { road.Left, road.Right }) { // Terrain settings side.Terrain.QuadData.BrushMaterials[0] = new Material("34"); // grass_ger_main side.Terrain.Profile = "profile12"; // hills2 side.Terrain.Noise = TerrainNoise.Percent0; side.Terrain.Coefficient = 0.5f; // Vegetation side.Vegetation[0].Name = "v2_1ger"; // ger - mixed forest side.Vegetation[0].Density = 200; side.Vegetation[0].From = 15; side.Vegetation[0].To = 80; // Roadside models (bollards) side.Models[0].Name = "ch_2y07d"; // reflective post de side.Models[0].Distance = 50; side.Models[0].Offset = 6; } // Append more road segments (properties are copied by default) road.Append(new Vector3(98, 0, 43.5f)) .Append(new Vector3(146.5f, 0, 25)) .Append(new Vector3(216, 0, 25)); ``` -------------------------------- ### Open game assets from base.scs Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/Samples/02-prefabs.md Use HashFsReader to access game files required for loading prefab descriptors. ```csharp using TruckLib.HashFs; // (modify this path before running) var gameRoot = @"E:\SteamLibrary\steamapps\common\Euro Truck Simulator 2"; var baseScs = HashFsReader.Open(Path.Combine(gameRoot, "base.scs")); ``` -------------------------------- ### Stage files for HashFS archive Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/TruckLib.HashFs/writer.md Initialize a writer and add files to the staging area using local file paths and their target archive paths. ```cs using TruckLib.HashFs; HashFsV2Writer writer = new(); writer.Add(@"D:\foo\bar\manifest.sii", "/manifest.sii"); writer.Add(@"C:\stuff\my_house.pmd", "/model/building/my_house.pmd"); ``` -------------------------------- ### Create a new Map instance Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/TruckLib.ScsMap/map-class.md Instantiate an empty map object for new projects. ```cs using TruckLib.ScsMap; Map map = new Map(); ``` -------------------------------- ### Create ElevationProvider with Dependency Injection Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/Samples/03-realroad.md Sets up the ElevationProvider using Microsoft.Extensions.DependencyInjection. This method configures the service collection, adds DEM.Net core services, and resolves an instance of ElevationProvider. ```cs using DEM.Net.Core; using Microsoft.Extensions.DependencyInjection; namespace RealRoad { internal class ElevationProvider { private readonly ElevationService elevationService; private readonly DEMDataSet dataset = DEMDataSet.SRTM_GL1; public static ElevationProvider Create() { var serviceCollection = new ServiceCollection(); serviceCollection.AddDemNetCore(); serviceCollection.AddTransient(); var services = serviceCollection.BuildServiceProvider(); return services.GetService(); } public ElevationProvider(ElevationService elevationService) { this.elevationService = elevationService; } ``` -------------------------------- ### Load Prefab Descriptor from File Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/TruckLib.ScsMap/prefabs.md Loads a prefab descriptor from a specified file path. Ensure the path points to the .ppd file. ```cs using TruckLib.Models.Ppd; PrefabDescriptor ppd = PrefabDescriptor.Open("/prefab2/car_dealer/car_dealer_01_fr.ppd"); ``` -------------------------------- ### Open a HashFS archive Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/TruckLib.HashFs/reader.md Use the static Open method to initialize a reader for a specific .scs file. ```cs using TruckLib.HashFs; using IHashFsReader reader = HashFsReader.Open(@"E:\SteamLibrary\steamapps\common\Euro Truck Simulator 2\def.scs"); ``` -------------------------------- ### Instantiate and Use ElevationProvider Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/Samples/03-realroad.md Creates an instance of ElevationProvider and uses it to fetch elevation data for the loaded coordinates. The first execution may take time due to downloading elevation models. ```cs var elevationProvider = ElevationProvider.Create(); var coordinatesWithElevation = elevationProvider.GetElevations(coordinates); ``` -------------------------------- ### Create HashFS Archives Source: https://context7.com/sk-zk/trucklib/llms.txt Use HashFsV1Writer or HashFsV2Writer to package files into .scs archives. HashFS v2 automatically handles .tobj/.dds pairing. ```csharp using TruckLib.HashFs; // Create a new HashFS v2 archive HashFsV2Writer writer = new HashFsV2Writer(); // Add files from disk writer.Add(@"D:\mod\manifest.sii", "/manifest.sii"); writer.Add(@"D:\mod\model\my_house.pmd", "/model/building/my_house.pmd"); // Add from byte array byte[] configData = System.Text.Encoding.UTF8.GetBytes("config data"); writer.Add(configData, "/def/my_config.sii"); // Add from stream using var stream = new MemoryStream(someBytes); writer.Add(stream, "/material/my_material.mat"); // Save the archive writer.Save("my_mod.scs"); // For HashFS v1 (older format) HashFsV1Writer v1Writer = new HashFsV1Writer(); v1Writer.Add(@"D:\mod\file.txt", "/file.txt"); v1Writer.Save("legacy_mod.scs"); // Note: In v2, .tobj files must have matching .dds files // The writer automatically packs them together ``` -------------------------------- ### Create and Import Map Selections in C# Source: https://context7.com/sk-zk/trucklib/llms.txt Use .sbd files to store and reuse map snippets with custom origin points. ```csharp using System.Numerics; using TruckLib.ScsMap; // Create a new selection Selection selection = new Selection(); // Add items (same as adding to a map) Model model = Model.Add(selection, new Vector3(10f, 0f, 10f), "dlc_no_471", "brick", "default"); Road road = Road.Add(selection, new Vector3(0, 0, 0), new Vector3(50, 0, 0), "ger1"); // Center the origin (recommended before saving) selection.CenterOrigin(); // Or set a custom origin selection.Origin = new Vector3(25, 0, 5); // Save the selection selection.Save("my_selection.sbd"); // Load and import into a map var map = new Map(); Selection loadedSelection = Selection.Open("my_selection.sbd"); // Import at specified position (UIDs will be regenerated) map.Import(loadedSelection, new Vector3(100, 0, 200)); ``` -------------------------------- ### Add and Configure 3D Models Source: https://context7.com/sk-zk/trucklib/llms.txt Use Model.Add to place static objects in the map. Properties like rotation, scale, and terrain material can be adjusted after instantiation. ```csharp using System; using System.Numerics; using TruckLib.ScsMap; var map = new Map(); // Add a model item var house = Model.Add(map, new Vector3(103.75f, -0.3f, 31.73f), // position "dlc_no_471", // unit name (house_01_sc) "brick", // variant "default" // look ); // Set rotation using yaw, pitch, roll house.Node.Rotation = Quaternion.CreateFromYawPitchRoll(-2.99f, 0, 0); // Configure additional model properties house.WaterReflection = true; house.Scale = new Vector3(1.2f, 1.0f, 1.2f); // relative scale house.ViewDistance = 500; // visibility distance in meters // Add another model with 90-degree rotation var woodHeap = Model.Add(map, new Vector3(159.64f, -0.1f, 36.91f), "378", // wood_heap1 "default", "default" ); woodHeap.Node.Rotation = Quaternion.CreateFromYawPitchRoll(MathF.PI / 2, 0, 0); // Set terrain under the model house.TerrainMaterial = new Token("grass_main"); house.TerrainRotation = 0.5f; ``` -------------------------------- ### Manage Prefab Structures and Connections Source: https://context7.com/sk-zk/trucklib/llms.txt Prefabs require a loaded descriptor file. Use Attach and AppendRoad to link prefabs and roads, and manage node connections. ```csharp using System.IO; using System.Numerics; using TruckLib.ScsMap; using TruckLib.Models.Ppd; using TruckLib.HashFs; var map = new Map(); var gameRoot = @"E:\SteamLibrary\steamapps\common\Euro Truck Simulator 2"; // Open the game's base.scs archive var baseScs = HashFsReader.Open(Path.Combine(gameRoot, "base.scs")); // Load prefab descriptor and add a company var companyPpd = PrefabDescriptor.Open("/prefab2/car_dealer/car_dealer_01_fr.ppd", baseScs); var company = Prefab.Add(map, new Vector3(55, 0, 70), // position of node 0 "dlc_fr_14", // unit name companyPpd, // prefab descriptor Quaternion.CreateFromYawPitchRoll(1.5708f, 0, 0) // 90° rotation ); company.Variant = "bhv_fr"; company.Look = "green_fr"; // Add a T-junction and attach it to the company var crossingPpd = PrefabDescriptor.Open("/prefab2/cross_temp/fr/fr_r1_x_r1_t_narrow_tmpl.ppd", baseScs); var crossing = Prefab.Add(map, company.Nodes[0].Position, "387", crossingPpd, Quaternion.CreateFromYawPitchRoll(-1.5708f, 0, 0)); crossing.Variant = "shoul_fr_1"; crossing.Look = "gray_fr"; crossing.AdditionalParts.Add("_midlines"); // Change origin to allow connection (both origins can't be connected) crossing.ChangeOrigin(1); // Attach prefabs (auto-finds closest nodes) company.Attach(crossing); // Or attach specific nodes: prefab1.Attach(nodeIndex1, prefab2, nodeIndex2) // company.Attach(0, crossing, 1); // Append a road from prefab node var road = crossing.AppendRoad(1, new Vector3(100, 0, 88), "template22"); road.Right.Variant = "broken"; road.Right.LeftEdge = "fr_sh_15"; road.Right.RightEdge = "fr_sh_15"; // Extend road and attach back to prefab road = road.Append(new Vector3(100, 0, 52)).Append(crossing.Nodes[0].Position); crossing.Attach(road); // Disconnect items from prefab INode detachedNode = crossing.Nodes[1].Split(); ``` -------------------------------- ### Load a prefab descriptor Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/Samples/02-prefabs.md Load the .ppd file for a specific prefab model using the previously opened game assets. ```csharp using TruckLib.Models.Ppd; var companyDescriptor = PrefabDescriptor.Open("/prefab2/car_dealer/car_dealer_01_fr.ppd", baseScs); ``` ```csharp var crossingDescriptor = PrefabDescriptor.Open("/prefab2/cross_temp/fr/fr_r1_x_r1_t_narrow_tmpl.ppd", baseScs); ``` -------------------------------- ### Create a new map Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/Samples/03-realroad.md Initializes an empty map object with default scales. ```csharp using TruckLib.ScsMap; var map = new Map(); map.NormalScale = 1; map.CityScale = 1; ``` -------------------------------- ### Find an entry by path Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/TruckLib.HashFs/reader.md Retrieve metadata for a specific file path using TryGetEntry. ```cs EntryType type = reader.TryGetEntry("/def/world/prefab.sii", out IEntry entry); ``` -------------------------------- ### Create and Save a Selection Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/TruckLib.ScsMap/selection-class.md Use the Selection class to create a new selection, add models to it, and save it to a .sbd file. Ensure a map recalculation if importing into the official editor. ```cs using System.Numerics; using TruckLib.ScsMap; Selection selection = new(); Model model = Model.Add(selection, new Vector3(10f, 0f, 10f), "dlc_no_471", "brick", "default" ); selection.Save("example.sbd"); ``` -------------------------------- ### Load Prefab Descriptors Source: https://context7.com/sk-zk/trucklib/llms.txt Load .ppd files to access node positions and spawn points. Pair with .pmd model files for terrain support. ```csharp using TruckLib.Models.Ppd; using TruckLib.HashFs; // Load from extracted file PrefabDescriptor ppd = PrefabDescriptor.Open(@"D:\extracted\prefab2\cross\cross_temp.ppd"); // Load directly from .scs archive HashFsReader baseScs = HashFsReader.Open(@"E:\Games\ETS2\base.scs"); PrefabDescriptor ppdFromArchive = PrefabDescriptor.Open( "/prefab2/car_dealer/car_dealer_01_fr.ppd", baseScs ); // Access prefab information Console.WriteLine($"Node count: {ppdFromArchive.Nodes.Count}"); Console.WriteLine($"Spawn points: {ppdFromArchive.SpawnPoints.Count}"); // Node positions are used by Prefab.Add to place control nodes foreach (var node in ppdFromArchive.Nodes) { Console.WriteLine($"Node position: {node.Position}"); Console.WriteLine($"Node direction: {node.Direction}"); } // For terrain support, also load the .pmd model file TruckLib.Models.Model model = TruckLib.Models.Model.Open( "/prefab2/cross_temp/fr/fr_r1_x_r1_t_narrow_tmpl.pmd", baseScs ); // Add prefab with terrain support var map = new Map(); Prefab prefab = Prefab.Add(map, new Vector3(0, 0, 0), "387", ppdFromArchive, model // Pass model for automatic terrain point handling ); prefab.Variant = "shoul_fr_1"; prefab.Look = "gray_fr"; ``` -------------------------------- ### Load Prefab Descriptor from SCS Archive Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/TruckLib.ScsMap/prefabs.md Loads a prefab descriptor directly from an .scs archive using HashFsReader. This avoids the need to extract files. ```cs using TruckLib.Models.Ppd; using TruckLib.HashFs; HashFsReader baseScs = HashFsReader.Open("/base.scs"); PrefabDescriptor ppd = PrefabDescriptor.Open("/prefab2/car_dealer/car_dealer_01_fr.ppd", baseScs); ``` -------------------------------- ### Serialize SiiFile to String Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/TruckLib.Sii/sii.md Create a new SiiFile object, add units and attributes, then serialize it to a string using the Serialize method. Supports custom indentation. ```cs SiiFile sii = new(); Unit unit = new("prefab_model", "prefab.dlc_blke_232"); unit.Attributes.Add("model_desc", "/prefab2/fork_temp/blke/blke_road2_no_offset_tram_to_road2_tram.pmd"); unit.Attributes.Add("prefab_desc", "/prefab2/fork_temp/blke/blke_road2_no_offset_tram_to_road2_tram.pmd"); unit.Attributes.Add("category", "dlc_blke"); unit.Attributes.Add("corner0", new List{"blke383", "blke385"}); unit.Attributes.Add("corner1", new List{"blke384", "blke386"}); sii.Units.Add(unit); string siiStr = sii.Serialize(); ``` -------------------------------- ### Load an existing map Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/TruckLib.ScsMap/map-class.md Load map data from disk or an SCS archive. ```cs using TruckLib.ScsMap; Map map = Map.Open(@"E:\SteamLibrary\steamapps\common\Euro Truck Simulator 2\extracted\map\europe.mbd"); ``` ```cs using TruckLib.HashFs; using TruckLib.ScsMap; IHashFsReader reader = HashFsReader.Open("base_map.scs"); Map map = Map.Open("/map/europe.mbd", reader); ``` -------------------------------- ### Create an Empty Compound Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/TruckLib.ScsMap/compounds.md Use the static `Add` method to create a new, empty compound item at a specified location. ```cs Compound compound = Compound.Add(map, new Vector3(42, 0, 84)); ``` -------------------------------- ### Connect prefabs Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/Samples/02-prefabs.md Adjust the origin of a prefab and attach it to another prefab by merging nodes. ```csharp crossing.ChangeOrigin(1); ``` ```csharp company.Attach(crossing); ``` -------------------------------- ### Parse and Create SII Files Source: https://context7.com/sk-zk/trucklib/llms.txt Read, modify, and write .sii game definition files. Supports plain text, encrypted, and 3nK-encoded formats. ```csharp using TruckLib.Sii; using TruckLib.HashFs; // Parse a SII file from disk SiiFile sii = SiiFile.Open("/path/to/file.sii"); // Parse from string (with include directory for @include directives) string siiContent = File.ReadAllText("config.sii"); SiiFile siiFromString = SiiFile.Load(siiContent, "/path/to/includes"); // Parse directly from .scs archive IHashFsReader reader = HashFsReader.Open("def.scs"); SiiFile siiFromArchive = SiiFile.Open("/def/country.sii", reader); // Access units and their attributes foreach (Unit unit in sii.Units) { Console.WriteLine($"Class: {unit.ClassName}, Name: {unit.Name}"); foreach (var attr in unit.Attributes) { Console.WriteLine($" {attr.Key} = {attr.Value}"); } } // Create a new SII file SiiFile newSii = new SiiFile(); Unit prefabUnit = new Unit("prefab_model", "prefab.dlc_blke_232"); prefabUnit.Attributes.Add("model_desc", "/prefab2/fork_temp/blke/blke_road.pmd"); prefabUnit.Attributes.Add("prefab_desc", "/prefab2/fork_temp/blke/blke_road.ppd"); prefabUnit.Attributes.Add("category", "dlc_blke"); prefabUnit.Attributes.Add("corner0", new List { "blke383", "blke385" }); prefabUnit.Attributes.Add("corner1", new List { "blke384", "blke386" }); newSii.Units.Add(prefabUnit); // Serialize to string string serialized = newSii.Serialize(); // Save to file newSii.Save("output.sii"); ``` -------------------------------- ### Manipulate Polyline Items in C# Source: https://context7.com/sk-zk/trucklib/llms.txt Connect, split, and interpolate along polyline chains. Use CreateItemsAlongPath to automate the placement of objects at regular intervals. ```csharp using System; using System.Numerics; using TruckLib.ScsMap; var map = new Map(); // Create two separate roads Road road1 = Road.Add(map, new Vector3(10, 0, 10), new Vector3(30, 0, 10), "ger1"); Road road2 = Road.Add(map, new Vector3(32, 0, 12), new Vector3(50, 0, 30), "ger1"); // Connect roads by merging nodes (keeps the first node's position) road1.ForwardNode.Merge(road2.Node); // Disconnect roads by splitting the connection INode newNode = road1.ForwardNode.Split(); // Find first and last items in a polyline chain PolylineItem start = road1.FindFirstItem(); PolylineItem end = road1.FindLastItem(); // Interpolate a point on the curve (t between 0 and 1) Vector3 midpoint = road1.InterpolateCurve(0.5f).Position; // Get point at specific distance in meters from backward node Vector3 point10m = road1.InterpolateCurveDist(10f).Position; // Place items at regular intervals along a road chain PolylineItem.CreateItemsAlongPath(start, end, 50f, (container, point) => { // Calculate positions on both sides of the road Vector3 normal = Vector3.Normalize(Vector3.Transform(Vector3.UnitX, point.Rotation)); float distFromRoad = 6; Vector3 leftPos = point.Position + normal * -distFromRoad; Vector3 rightPos = point.Position + normal * distFromRoad; // Place signs on both sides Sign leftPost = Sign.Add(container, leftPos, "ch_2y07d"); leftPost.Node.Rotation = point.Rotation * Quaternion.CreateFromYawPitchRoll((float)Math.PI, 0, 0); Sign rightPost = Sign.Add(container, rightPos, "ch_2y07d"); rightPost.Node.Rotation = point.Rotation; return new MapItem[] { leftPost, rightPost }; }); ``` -------------------------------- ### Manage Map Compounds in C# Source: https://context7.com/sk-zk/trucklib/llms.txt Create, modify, and dissolve compound containers to group map items for easier manipulation. ```csharp using System.Numerics; using TruckLib.ScsMap; var map = new Map(); // Create an empty compound at a center point Compound compound = Compound.Add(map, new Vector3(42, 0, 84)); // Add items directly to the compound (same interface as map) Model model1 = Model.Add(compound, new Vector3(40, 0, 80), "dlc_no_654", "default", "default"); Model model2 = Model.Add(compound, new Vector3(44, 0, 88), "dlc_no_654", "default", "default"); // Remove an item from compound (item is deleted) compound.Delete(model2); // Alternatively, compound existing items var existingModel1 = Model.Add(map, new Vector3(10, 0, 10), "378", "default", "default"); var existingModel2 = Model.Add(map, new Vector3(15, 0, 15), "378", "default", "default"); Compound newCompound = map.CompoundItems(new[] { existingModel1, existingModel2 }); // Dissolve compound (items return to map, compound deleted) map.UncompoundItems(newCompound); // Moving a compound moves all contained items compound.Move(new Vector3(100, 0, 100)); ``` -------------------------------- ### Create Items Along Path (Dual Sided) Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/TruckLib.ScsMap/polyline-items.md Places Sign items (reflector posts) along both sides of a road path at specified intervals, ensuring correct orientation. The callback function handles item creation and positioning. ```cs PolylineItem.CreateItemsAlongPath(start, end, 50f, (container, point) => { Vector3 normal = Vector3.Normalize(Vector3.Transform(Vector3.UnitX, point.Rotation)); float distFromRoad = 6; Vector3 leftPos = point.Position + normal * -distFromRoad; Vector3 rightPos = point.Position + normal * distFromRoad; Sign leftPost = Sign.Add(container, leftPos, "ch_2y07d"); leftPost.Node.Rotation = point.Rotation * Quaternion.CreateFromYawPitchRoll((float)Math.PI, 0, 0); Sign rightPost = Sign.Add(container, rightPos, "ch_2y07d"); rightPost.Node.Rotation = point.Rotation; return [leftPost, rightPost]; }); ``` -------------------------------- ### Append and attach roads Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/Samples/02-prefabs.md Extend a road from a prefab node and attach it back to another node. ```csharp var road = crossing.AppendRoad(1, new Vector3(100, 0, 88), "template22"); road.Right.Variant = "broken"; road.Right.LeftEdge = "fr_sh_15"; road.Right.RightEdge = "fr_sh_15"; road = road.Append(new Vector3(100, 0, 52)).Append(crossing.Nodes[0].Position); ``` ```csharp crossing.Attach(road); ``` -------------------------------- ### Save SiiFile to Disk Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/TruckLib.Sii/sii.md Serialize an SiiFile object and save it directly to a file path using the Save method. An optional indentation parameter can be provided. ```cs sii.Save("foo.sii"); ``` -------------------------------- ### Create and Open Maps with TruckLib Source: https://context7.com/sk-zk/trucklib/llms.txt The Map class serves as the primary interface for initializing, loading, and querying map data. It supports loading from disk, .scs archives, or partial sector loading. ```csharp using System.Numerics; using TruckLib.ScsMap; using TruckLib.HashFs; // Create a new empty map var map = new Map(); // Set map scale (1 for 1:1 mapping) map.NormalScale = 1; map.CityScale = 1; // Open an existing map from disk Map existingMap = Map.Open(@"E:\SteamLibrary\steamapps\common\Euro Truck Simulator 2\extracted\map\europe.mbd"); // Open a map directly from a .scs archive IHashFsReader reader = HashFsReader.Open("base_map.scs"); Map mapFromArchive = Map.Open("/map/europe.mbd", reader); // Load specific sectors only var sectors = new[] { new SectorCoordinate(-1, 0), new SectorCoordinate(0, 0) }; Map partialMap = Map.Open(@"path/to/map.mbd", sectors); // Access map items by UID bool exists = map.MapItems.TryGetValue(0x521CD80FA4000001, out MapItem item); var allMovers = map.MapItems.Where(x => x.Value is Mover); // Find nodes within a bounding box var nodesInArea = map.Nodes.Within(0, 0, 4000, 4000); ``` -------------------------------- ### Import Selection into Map Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/TruckLib.ScsMap/selection-class.md Import a selection into an existing map at a specified offset. This creates a copy of the items with new UIDs. ```cs map.Import(selection, new Vector3(72.7f, 0f, 27.2f)); ``` -------------------------------- ### Deserialize SII from File Path Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/TruckLib.Sii/sii.md Use SiiFile.Open to deserialize an SII file directly from a file path. This method automatically handles include directives. ```cs using TruckLib.Sii; SiiFile sii = SiiFile.Open("/foo/bar.sii"); ``` -------------------------------- ### Retrieve directory contents Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/TruckLib.HashFs/reader.md Access the contents of a directory within the archive using GetDirectoryListing. ```cs // Get the top level of the archive var directory = reader.GetDirectoryListing("/"); ``` -------------------------------- ### Save HashFS archive Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/TruckLib.HashFs/writer.md Finalize the archive creation by writing the staged files to the specified output path. ```cs writer.Save("example.scs"); ``` -------------------------------- ### Save the map to a directory Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/Samples/01-simple.md Saves the created map to a specified path, typically within the game's mod directory. Requires recomputing the map afterwards to update bounding boxes. ```cs var documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); var userMap = Path.Combine(documents, "Euro Truck Simulator 2/mod/user_map/map/"); map.Save(userMap, "example", true); ``` -------------------------------- ### Deserialize SII from String Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/TruckLib.Sii/sii.md Use SiiFile.Load to parse an SII file from a string. Provide the directory for included files if @include directives are present. ```cs SiiFile sii = SiiFile.Load(siiStr, "/path/where/included/files/are/located"); ``` -------------------------------- ### Save a map to disk Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/TruckLib.ScsMap/map-class.md Persist map changes to a specified directory. ```cs string documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); string userMap = Path.Combine(documents, "Euro Truck Simulator 2/mod/user_map/map/"); map.Save(userMap, "map_name", true); ``` -------------------------------- ### Add road items to map Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/Samples/03-realroad.md Constructs a road by adding the initial segment and appending subsequent points. ```csharp var road = Road.Add(map, PointToNodePosition(points[0], center), PointToNodePosition(points[1], center), "ger1"); for (int i = 2; i < points.Count; i++) { road = road.Append(PointToNodePosition(points[i], center)); } ``` -------------------------------- ### Add a Model to the map Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/TruckLib.ScsMap/add-delete-items.md Constructs a model object, configures map nodes, and adds it to the specified container. ```cs Model model = Model.Add( map, // container new Vector3(10f, 0f, 10f), // position "dlc_no_471", // unit name of "house_01_sc" "brick", // model variant "default" // model look ); ``` -------------------------------- ### Add a prefab to the map Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/Samples/02-prefabs.md Place a prefab into the map at specific coordinates with defined rotation and variants. ```csharp var company = Prefab.Add(map, // position of node 0 new Vector3(55, 0, 70), // Unit name "dlc_fr_14", // .ppd companyDescriptor, // rotation (90° in this case) Quaternion.CreateFromYawPitchRoll(1.5708f, 0, 0)); company.Variant = "bhv_fr"; company.Look = "green_fr"; ``` ```csharp var crossing = Prefab.Add(map, company.Nodes[0].Position, "387", crossingDescriptor, Quaternion.CreateFromYawPitchRoll(-1.5708f, 0, 0)); crossing.Variant = "shoul_fr_1"; crossing.Look = "gray_fr"; crossing.AdditionalParts.Add("_midlines"); ``` -------------------------------- ### Add a model to the map Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/Samples/01-simple.md Places a model (e.g., a house or wood heap) onto the map at a specified position with given unit name, variant, and look. Rotation can be set using Quaternion. ```cs var model1 = Model.Add(map, new Vector3(103.75f, -0.3f, 31.73f), // position "dlc_no_471", // unit name of "house_01_sc" "brick", // variant "default" // look ); model1.Node.Rotation = Quaternion.CreateFromYawPitchRoll(-2.99f, 0, 0); var model2 = Model.Add(map, new Vector3(159.64f, -0.1f, 36.91f), "378", // "wood_heap1" "default", "default"); model2.Node.Rotation = Quaternion.CreateFromYawPitchRoll(MathF.PI / 2, 0, 0); ``` -------------------------------- ### Append New Road to Prefab Node Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/TruckLib.ScsMap/prefabs.md Appends a new road item to a prefab node. The provided Vector3 will be the position of the road's forward node, unless appending to the origin node, in which case it becomes the backward node (effectively prepending the road). ```csharp Road road = prefab.AppendRoad(1, new Vector3(42, 0, 21), "ger1"); ``` -------------------------------- ### Attach Prefabs Automatically Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/TruckLib.ScsMap/prefabs.md Attaches two prefabs by automatically finding the closest nodes for connection. One of the connected prefab nodes will be deleted after attachment. ```cs prefab1.Attach(prefab2); ``` -------------------------------- ### Attach Prefabs by Node Index Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/TruckLib.ScsMap/prefabs.md Attaches two prefabs together by specifying the node indices on each prefab. The prefabs will be moved so the specified nodes align. Throws InvalidOperationException if nodes are already attached or are both origin nodes. ```cs prefab1.Attach(3, prefab2, 0); ``` -------------------------------- ### Add Prefab with Terrain Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/TruckLib.ScsMap/prefabs.md Adds a prefab to the map, including its terrain data from a .pmd file. This allows the library to automatically handle terrain points. Ensure a valid variant is set. ```cs HashFsReader baseScs = HashFsReader.Open("/base.scs"); PrefabDescriptor ppd = PrefabDescriptor.Open("/prefab2/cross_temp/fr/fr_r1_x_r1_t_narrow_tmpl.ppd", baseScs); TruckLib.Models.Model model = TruckLib.Models.Model.Open("/prefab2/cross_temp/fr/fr_r1_x_r1_t_narrow_tmpl.pmd", baseScs); Prefab crossing = Prefab.Add(map, new Vector3(12.3f, 0, 23.4f), "387", ppd, model); crossing.Variant = "shoul_fr_1"; // Note that a valid variant must be set crossing.Look = "gray_fr"; crossing.PrefabNodes[2].Terrain.Size = 30; ``` -------------------------------- ### Read HashFS Archives in C# Source: https://context7.com/sk-zk/trucklib/llms.txt Access and extract files from .scs archives, supporting both HashFS v1 and v2 formats. ```csharp using TruckLib.HashFs; // Open a HashFS archive using IHashFsReader reader = HashFsReader.Open(@"E:\Games\ETS2\def.scs"); // Check if an entry exists EntryType type = reader.TryGetEntry("/def/world/prefab.sii", out IEntry entry); // EntryType: File, Directory, or NotFound // List directory contents var contents = reader.GetDirectoryListing("/"); foreach (var item in contents.Subdirectories) Console.WriteLine($"Dir: {item}"); foreach (var item in contents.Files) Console.WriteLine($"File: {item}"); // Extract file to memory byte[][] data = reader.Extract("/def/world/prefab.sii"); string content = System.Text.Encoding.UTF8.GetString(data[0]); // Extract file to disk reader.ExtractToFile("/def/world/prefab.sii", "./prefab.sii"); // Note: HashFS v2 packs .tobj/.dds pairs together // Extracting a .tobj returns both files: [tobj_bytes, dds_bytes] byte[][] textureData = reader.Extract("/material/road/road_01.tobj"); // textureData[0] = reconstructed .tobj // textureData[1] = .dds file ``` -------------------------------- ### Attach Road or Polyline to Prefab Node Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/TruckLib.ScsMap/prefabs.md Use this overload of Attach to connect a road or another polyline item to a specific node of a prefab. The first parameter is the prefab node index, and the second is the item node. Attaching a backward node to an origin node will cause an InvalidOperationException. ```csharp prefab.Attach(1, road.ForwardNode); ``` -------------------------------- ### Configure road terrain and vegetation Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/Samples/01-simple.md Sets the terrain material, profile, noise, and vegetation density for both sides of a road. This loop iterates over the left and right sides of the road item. ```cs foreach (var side in new[]{r.Left, r.Right}) { side.Terrain.QuadData.BrushMaterials[0] = new Material("34"); // "grass_ger_main" side.Terrain.Profile = "profile12"; // "hills2" side.Terrain.Noise = TerrainNoise.Percent0; side.Terrain.Coefficient = 0.5f; side.Vegetation[0].Name = "v2_1ger"; // "ger - mixed forest" side.Vegetation[0].Density = 200; side.Vegetation[0].From = 15; side.Vegetation[0].To = 80; side.Models[0].Name = "219"; // "reflective post" side.Models[0].Distance = 50; side.Models[0].Offset = 6; } ``` -------------------------------- ### Access map items Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/TruckLib.ScsMap/map-class.md Retrieve items from the map using UIDs or LINQ queries. ```cs bool exists = map.MapItems.TryGetValue(0x521CD80FA4000001, out MapItem item); var allMovers = map.MapItems.Where(x => x.Value is Mover); ``` -------------------------------- ### Compound Existing Items Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/TruckLib.ScsMap/compounds.md Combine a list of existing map items into a new compound item using the `CompoundItems` method. ```cs Compound compound = map.CompoundItems(new[] {model1, model2}); ``` -------------------------------- ### Query map nodes Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/TruckLib.ScsMap/map-class.md Retrieve nodes by UID or perform spatial queries using bounding boxes. ```cs bool exists = map.Nodes.TryGetValue(0x521CD80C53000000, out INode node); ``` ```cs var nodes = map.Nodes.Within(0, 0, 4000, 4000); ``` -------------------------------- ### Extract entries Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/TruckLib.HashFs/reader.md Extract file data into memory or directly to the disk. ```cs byte[][] data = reader.Extract("/def/world/prefab.sii"); ``` ```cs reader.ExtractToFile("/def/world/prefab.sii", "./prefab.sii"); ``` -------------------------------- ### Translate and Move Map Items Source: https://context7.com/sk-zk/trucklib/llms.txt Apply absolute positioning with Move or relative offsets with Translate. Polyline items like roads allow individual node manipulation. ```csharp using System.Numerics; using TruckLib.ScsMap; var map = new Map(); // Move a model to absolute position var model = Model.Add(map, new Vector3(10, 0, 10), "dlc_no_654", "default", "default"); model.Move(new Vector3(50, 0, 50)); // Now at (50, 0, 50) // Translate (relative movement) model.Translate(new Vector3(10, 0, -5)); // Now at (60, 0, 45) // For polyline items, Move/Translate affects both nodes var road = Road.Add(map, new Vector3(0, 0, 0), new Vector3(20, 0, 0), "ger1"); road.Translate(new Vector3(100, 0, 100)); // Both nodes shifted // Move only one node of a polyline road.Node.Move(new Vector3(110, 0, 100)); // Move backward node only road.ForwardNode.Move(new Vector3(130, 0, 100)); // Move forward node only // Path/polygon items move relative to anchor node (default: node 0) // Use Move(position, anchorIndex) to specify different anchor ``` -------------------------------- ### Add Prefab to Map Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/TruckLib.ScsMap/prefabs.md Adds a prefab to the map at a specified position and orientation, using a loaded prefab descriptor. The position corresponds to the 0th control node. ```cs Prefab prefab = Prefab.Add(map, new Vector3(12.3f, 0, 23.4f), "dlc_fr_14", ppd, Quaternion.Identity); ``` -------------------------------- ### Connect Two Polyline Items (Keep First Node) Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/TruckLib.ScsMap/polyline-items.md Connects two polyline items by merging the forward node of the first item with the node of the second item. This operation keeps the node from the first item. ```cs Road road1 = Road.Add(map, new Vector3(10, 0, 10), new Vector3(30, 0, 10), "ger1"); Road road2 = Road.Add(map, new Vector3(32, 0, 12), new Vector3(50, 0, 30), "ger1"); road1.ForwardNode.Merge(road2.Node); ``` -------------------------------- ### Disconnect Prefabs or Polyline Items Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/TruckLib.ScsMap/prefabs.md Call the Split method on the connecting node to disconnect two prefabs or a prefab and a polyline item. This method also returns the newly created node after the split. ```csharp INode newNode = prefab.Nodes[1].Split(); ``` -------------------------------- ### Connect Two Polyline Items (Keep Second Node) Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/TruckLib.ScsMap/polyline-items.md Connects two polyline items by merging the node of the second item with the forward node of the first item. This operation keeps the node from the second item. ```cs Road road1 = Road.Add(map, new Vector3(10, 0, 10), new Vector3(30, 0, 10), "ger1"); Road road2 = Road.Add(map, new Vector3(32, 0, 12), new Vector3(50, 0, 30), "ger1"); road2.Node.Merge(road1.ForwardNode); ``` -------------------------------- ### Deserialize SII with Custom I/O Reader Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/TruckLib.Sii/sii.md Deserialize an SII file from an IHashFsReader, useful for loading from SCS archives. This overload allows specifying the file path within the archive and the reader. ```cs using TruckLib.HashFs; using TruckLib.Sii; IHashFsReader reader = HashFsReader.Open("def.scs"); SiiFile sii = SiiFile.Open("/def/country.sii", reader); ``` -------------------------------- ### Fetch Elevation for Geographic Points Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/Samples/03-realroad.md Fetches elevation data for a list of geographic points using the DEM.Net library. It handles downloading missing elevation model files and retrieves elevation for the specified line geometry. ```cs public List GetElevations(List points) { elevationService.DownloadMissingFiles(dataset, GetBoundingBoxContainingPoints(points)); var geoPoints = elevationService.GetLineGeometryElevation( points.Select(p => new GeoPoint(p.Latitude, p.Longitude)), dataset).ToList(); return geoPoints.Select( x => new GeographicCoordinate(x.Latitude, x.Longitude, x.Elevation ?? 0)) .ToList(); } ``` -------------------------------- ### Attach Road or Polyline Using Closest Nodes Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/TruckLib.ScsMap/prefabs.md This method attaches the closest nodes of a road or polyline item to a prefab. The leftover node of the polyline item will be deleted after the operation. ```csharp prefab.Attach(road); ``` -------------------------------- ### Move Map Item with TruckLib Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/TruckLib.ScsMap/move-items.md Use the Move method to reposition a map item to a new absolute coordinate. Ensure the item is properly added to the map before moving. ```cs var model = Model.Add(map, new Vector3(10, 0, 10), "dlc_no_654", "default", "default"); model.Move(new Vector3(50, 0, 50)); // The model is now at (50, 0, 50). ``` -------------------------------- ### Uncompound Items Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/TruckLib.ScsMap/compounds.md Dissolve a compound, moving its items back to the map and deleting the compound item itself, using the `UncompoundItems` method. ```cs map.UncompoundItems(compound); ``` -------------------------------- ### Save Maps to Mod Directory Source: https://context7.com/sk-zk/trucklib/llms.txt Save map data to a specified directory. Note that bounding boxes must be recomputed within the game editor after saving. ```csharp using System; using System.IO; using TruckLib.ScsMap; var map = new Map(); // Add items to map... // Save to the user_map mod directory string documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); string userMapPath = Path.Combine(documents, "Euro Truck Simulator 2/mod/user_map/map/"); // Save with automatic cleanup of existing sector files map.Save(userMapPath, "my_map", cleanSectorDirectory: true); // Result: my_map.mbd and my_map/ directory created // Remember to run Map > Recompute map in the editor after first load ``` -------------------------------- ### Load Coordinates from CSV Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/Samples/03-realroad.md Loads geographic coordinates from a CSV file. This is a placeholder for the actual data loading logic. ```cs var coordinates = LoadCoordinates(); ``` -------------------------------- ### Project geographic coordinates to UTM Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/Samples/03-realroad.md Converts a list of geographic coordinates into projected coordinates using the DotSpatial library. ```csharp using DotSpatial.Projections; static List Project(IList coordinates, ProjectionInfo source, ProjectionInfo dest) { // Convert our list into the flat array expected by the library var xy = new double[coordinates.Count * 2]; for (int i = 0; i < coordinates.Count; i++) { xy[i * 2] = coordinates[i].Longitude; xy[(i * 2) + 1] = coordinates[i].Latitude; } // Project the points in-place Reproject.ReprojectPoints(xy, null, source, dest, 0, coordinates.Count); // And convert it back into a list of ProjectedCoordinates var points = new List(coordinates.Count); for (int i = 0; i < coordinates.Count; i++) { var easting = xy[i * 2]; var northing = xy[(i * 2) + 1]; points.Add(new ProjectedCoordinate(easting, northing, coordinates[i].Height)); } return points; } ``` -------------------------------- ### Add Item to a Compound Source: https://github.com/sk-zk/trucklib/blob/master/docfx/docs/TruckLib.ScsMap/compounds.md Add new map items to an existing compound by using the compound as the parent. ```cs Model model = Model.Add(compound, new Vector3(40, 0, 80), "dlc_no_654", "default", "default"); ```