private void Parse() { PrefabNodes = new List <TsPrefabNode>(); SpawnPoints = new List <TsSpawnPoint>(); MapPoints = new List <TsMapPoint>(); TriggerPoints = new List <TsTriggerPoint>(); var fileOffset = 0x0; var version = MemoryHelper.ReadInt32(_stream, fileOffset); if (version < 0x15) { Log.Msg($"{_filePath} file version ({version}) too low, min. is {0x15}"); return; } var nodeCount = BitConverter.ToInt32(_stream, fileOffset += 0x04); var spawnPointCount = BitConverter.ToInt32(_stream, fileOffset += 0x10); var mapPointCount = BitConverter.ToInt32(_stream, fileOffset += 0x0C); var triggerPointCount = BitConverter.ToInt32(_stream, fileOffset += 0x04); if (version > 0x15) { fileOffset += 0x04; // http://modding.scssoft.com/wiki/Games/ETS2/Modding_guides/1.30#Prefabs } var nodeOffset = MemoryHelper.ReadInt32(_stream, fileOffset += 0x08); var spawnPointOffset = MemoryHelper.ReadInt32(_stream, fileOffset += 0x10); var mapPointOffset = MemoryHelper.ReadInt32(_stream, fileOffset += 0x10); var triggerPointOffset = MemoryHelper.ReadInt32(_stream, fileOffset += 0x04); for (var i = 0; i < nodeCount; i++) { var nodeBaseOffset = nodeOffset + (i * NodeBlockSize); var node = new TsPrefabNode { X = MemoryHelper.ReadSingle(_stream, nodeBaseOffset + 0x10), Z = MemoryHelper.ReadSingle(_stream, nodeBaseOffset + 0x18), RotX = MemoryHelper.ReadSingle(_stream, nodeBaseOffset + 0x1C), RotZ = MemoryHelper.ReadSingle(_stream, nodeBaseOffset + 0x24), }; PrefabNodes.Add(node); } for (var i = 0; i < spawnPointCount; i++) { var spawnPointBaseOffset = spawnPointOffset + (i * SpawnPointBlockSize); var spawnPoint = new TsSpawnPoint { X = MemoryHelper.ReadSingle(_stream, spawnPointBaseOffset), Z = MemoryHelper.ReadSingle(_stream, spawnPointBaseOffset + 0x08), Type = (TsSpawnPointType)MemoryHelper.ReadUInt32(_stream, spawnPointBaseOffset + 0x1C) }; var pointInVicinity = SpawnPoints.FirstOrDefault(point => // check if any other spawn points with the same type are close point.Type == spawnPoint.Type && ((spawnPoint.X > point.X - 4 && spawnPoint.X < point.X + 4) || (spawnPoint.Z > point.Z - 4 && spawnPoint.Z < point.Z + 4))); if (pointInVicinity == null) { SpawnPoints.Add(spawnPoint); } // Log.Msg($"Spawn point of type: {spawnPoint.Type} in {_filePath}"); } for (var i = 0; i < mapPointCount; i++) { var mapPointBaseOffset = mapPointOffset + (i * MapPointBlockSize); var roadLookFlags = MemoryHelper.ReadUint8(_stream, mapPointBaseOffset + 0x01); var laneTypeFlags = (byte)(roadLookFlags & 0x0F); var laneOffsetFlags = (byte)(roadLookFlags >> 4); int laneOffset; switch (laneOffsetFlags) { case 1: laneOffset = 1; break; case 2: laneOffset = 2; break; case 3: laneOffset = 5; break; case 4: laneOffset = 10; break; case 5: laneOffset = 15; break; case 6: laneOffset = 20; break; case 7: laneOffset = 25; break; default: laneOffset = 0; break; } int laneCount; switch (laneTypeFlags) // TODO: Change these (not really used atm) { case 0: laneCount = 1; break; case 1: laneCount = 2; break; case 2: laneCount = 4; break; case 3: laneCount = 6; break; case 4: laneCount = 8; break; case 5: laneCount = 5; break; case 6: laneCount = 7; break; case 8: laneCount = 3; break; case 13: laneCount = -1; break; case 14: laneCount = 2; break; // auto ; temp set at 2 default: laneCount = 1; // Log.Msg($"Unknown LaneType: {laneTypeFlags}"); break; } var prefabColorFlags = MemoryHelper.ReadUint8(_stream, mapPointBaseOffset + 0x02); var navFlags = MemoryHelper.ReadUint8(_stream, mapPointBaseOffset + 0x05); var hidden = (navFlags & 0x02) != 0; // Map Point is Control Node var point = new TsMapPoint { LaneCount = laneCount, LaneOffset = laneOffset, Hidden = hidden, PrefabColorFlags = prefabColorFlags, X = MemoryHelper.ReadSingle(_stream, mapPointBaseOffset + 0x08), Z = MemoryHelper.ReadSingle(_stream, mapPointBaseOffset + 0x10), Neighbours = new List <int>(), NeighbourCount = MemoryHelper.ReadInt32(_stream, mapPointBaseOffset + 0x14 + (0x04 * 6)) }; for (var x = 0; x < point.NeighbourCount; x++) { point.Neighbours.Add(MemoryHelper.ReadInt32(_stream, mapPointBaseOffset + 0x14 + (x * 0x04))); } MapPoints.Add(point); } for (var i = 0; i < triggerPointCount; i++) { var triggerPointBaseOffset = triggerPointOffset + (i * TriggerPointBlockSize); var triggerPoint = new TsTriggerPoint { TriggerId = MemoryHelper.ReadUInt32(_stream, triggerPointBaseOffset), TriggerActionUid = MemoryHelper.ReadUInt64(_stream, triggerPointBaseOffset + 0x04), X = MemoryHelper.ReadSingle(_stream, triggerPointBaseOffset + 0x1C), Z = MemoryHelper.ReadSingle(_stream, triggerPointBaseOffset + 0x24), }; var pointInVicinity = TriggerPoints.FirstOrDefault(point => // check if any other trigger points with the same id are close point.TriggerActionUid == triggerPoint.TriggerActionUid && ((triggerPoint.X > point.X - 20 && triggerPoint.X < point.X + 20) || (triggerPoint.Z > point.Z - 20 && triggerPoint.Z < point.Z + 20))); if (pointInVicinity == null) { TriggerPoints.Add(triggerPoint); } } _stream = null; }
public void Parse() { Version = BitConverter.ToInt32(Stream, 0x0); if (Version < 825) { Log.Msg($"{FilePath} version ({Version}) is too low, min. is 825"); return; } var itemCount = BitConverter.ToUInt32(Stream, 0x10); if (itemCount == 0) { _empty = true; } if (_empty) { return; } var lastOffset = 0x14; for (var i = 0; i < itemCount; i++) { var type = (TsItemType)MemoryHelper.ReadUInt32(Stream, lastOffset); if (Version <= 825) { type++; // after version 825 all types were pushed up 1 } switch (type) { case TsItemType.Road: { var item = new TsRoadItem(this, lastOffset); lastOffset += item.BlockSize; if (item.Valid) { Mapper.Roads.Add(item); } break; } case TsItemType.Prefab: { var item = new TsPrefabItem(this, lastOffset); lastOffset += item.BlockSize; if (item.Valid) { Mapper.Prefabs.Add(item); } break; } case TsItemType.Company: { var item = new TsCompanyItem(this, lastOffset); lastOffset += item.BlockSize; if (item.Valid) { Mapper.Companies.Add(item); } break; } case TsItemType.Service: { var item = new TsServiceItem(this, lastOffset); lastOffset += item.BlockSize; break; } case TsItemType.CutPlane: { var item = new TsCutPlaneItem(this, lastOffset); lastOffset += item.BlockSize; break; } case TsItemType.City: { var item = new TsCityItem(this, lastOffset); lastOffset += item.BlockSize; if (item.Valid) { Mapper.Cities.Add(item); } break; } case TsItemType.MapOverlay: { var item = new TsMapOverlayItem(this, lastOffset); lastOffset += item.BlockSize; if (item.Valid) { Mapper.MapOverlays.Add(item); } break; } case TsItemType.Ferry: { var item = new TsFerryItem(this, lastOffset); lastOffset += item.BlockSize; if (item.Valid) { Mapper.FerryConnections.Add(item); } break; } case TsItemType.Garage: { var item = new TsGarageItem(this, lastOffset); lastOffset += item.BlockSize; break; } case TsItemType.Trigger: { var item = new TsTriggerItem(this, lastOffset); lastOffset += item.BlockSize; if (item.Valid) { Mapper.Triggers.Add(item); } break; } case TsItemType.FuelPump: { var item = new TsFuelPumpItem(this, lastOffset); lastOffset += item.BlockSize; break; } case TsItemType.RoadSideItem: { var item = new TsRoadSideItem(this, lastOffset); lastOffset += item.BlockSize; break; } case TsItemType.BusStop: { var item = new TsBusStopItem(this, lastOffset); lastOffset += item.BlockSize; break; } case TsItemType.TrafficRule: { var item = new TsTrafficRuleItem(this, lastOffset); lastOffset += item.BlockSize; break; } case TsItemType.TrajectoryItem: { var item = new TsTrajectoryItem(this, lastOffset); lastOffset += item.BlockSize; break; } case TsItemType.MapArea: { var item = new TsMapAreaItem(this, lastOffset); lastOffset += item.BlockSize; if (item.Valid) { Mapper.MapAreas.Add(item); } break; } default: { Log.Msg($"Unknown Type: {type} in {Path.GetFileName(FilePath)} @ {lastOffset}"); break; } } } var nodeCount = MemoryHelper.ReadInt32(Stream, lastOffset); for (var i = 0; i < nodeCount; i++) { TsNode node = new TsNode(this, lastOffset += 0x04); Mapper.UpdateEdgeCoords(node); if (!Mapper.Nodes.ContainsKey(node.Uid)) { Mapper.Nodes.Add(node.Uid, node); } lastOffset += 0x34; } }
private void ParseDxt5() // https://msdn.microsoft.com/en-us/library/windows/desktop/bb694531 { var fileOffset = 0x80; _pixelData = new Color8888[Width * Height]; for (var y = 0; y < Height; y += 4) { for (var x = 0; x < Width; x += 4) { var alphas = new byte[8]; alphas[0] = _stream[fileOffset]; alphas[1] = _stream[fileOffset += 0x01]; if (alphas[0] > alphas[1]) { // 6 interpolated alpha values. alphas[2] = (byte)((double)6 / 7 * alphas[0] + (double)1 / 7 * alphas[1]); // bit code 010 alphas[3] = (byte)((double)5 / 7 * alphas[0] + (double)2 / 7 * alphas[1]); // bit code 011 alphas[4] = (byte)((double)4 / 7 * alphas[0] + (double)3 / 7 * alphas[1]); // bit code 100 alphas[5] = (byte)((double)3 / 7 * alphas[0] + (double)4 / 7 * alphas[1]); // bit code 101 alphas[6] = (byte)((double)2 / 7 * alphas[0] + (double)5 / 7 * alphas[1]); // bit code 110 alphas[7] = (byte)((double)1 / 7 * alphas[0] + (double)6 / 7 * alphas[1]); // bit code 111 } else { // 4 interpolated alpha values. alphas[2] = (byte)((double)4 / 5 * alphas[0] + (double)1 / 5 * alphas[1]); // bit code 010 alphas[3] = (byte)((double)3 / 5 * alphas[0] + (double)2 / 5 * alphas[1]); // bit code 011 alphas[4] = (byte)((double)2 / 5 * alphas[0] + (double)3 / 5 * alphas[1]); // bit code 100 alphas[5] = (byte)((double)1 / 5 * alphas[0] + (double)4 / 5 * alphas[1]); // bit code 101 alphas[6] = 0; // bit code 110 alphas[7] = 255; // bit code 111 } var alphaTexelUlongData = MemoryHelper.ReadUInt64(_stream, fileOffset += 0x01); var alphaTexelData = alphaTexelUlongData & 0xFFFFFFFFFFFF; // remove 2 excess bytes (read 8 bytes only need 6) var alphaTexels = new byte[16]; for (var j = 0; j < 2; j++) { var alphaTexelRowData = (alphaTexelData >> (j * 0x18)) & 0xFFFFFF; for (var i = 0; i < 8; i++) { var index = (alphaTexelRowData >> (i * 0x03)) & 0x07; alphaTexels[i + j * 8] = alphas[index]; } } var color0 = new Color565(MemoryHelper.ReadUInt16(_stream, fileOffset += 0x06)); var color1 = new Color565(MemoryHelper.ReadUInt16(_stream, fileOffset += 0x02)); var color2 = (double)2 / 3 * color0 + (double)1 / 3 * color1; var color3 = (double)1 / 3 * color0 + (double)2 / 3 * color1; var colors = new[] { new Color8888(color0, 0xFF), // bit code 00 new Color8888(color1, 0xFF), // bit code 01 new Color8888(color2, 0xFF), // bit code 10 new Color8888(color3, 0xFF) // bit code 11 }; var colorTexelData = MemoryHelper.ReadUInt32(_stream, fileOffset += 0x02); for (var j = 3; j >= 0; j--) { var colorTexelRowData = (colorTexelData >> (j * 0x08)) & 0xFF; for (var i = 0; i < 4; i++) { var index = (colorTexelRowData >> (i * 0x02)) & 0x03; var pos = (uint)(y * Width + j * Width + x + i); _pixelData[pos] = colors[index]; _pixelData[pos].SetAlpha(alphaTexels[j * 4 + i]); } } fileOffset += 0x04; } } }