Beispiel #1
0
        private void Parse()
        {
            PrefabNodes      = new List <TsPrefabNode>();
            SpawnPoints      = new List <TsSpawnPoint>();
            MapPoints        = new List <TsMapPoint>();
            TriggerPoints    = new List <TsTriggerPoint>();
            PrefabCurves     = new List <TsPrefabCurve>();
            NavigationRoutes = new Dictionary <Tuple <TsPrefabNode, TsPrefabNode>, Tuple <List <TsPrefabCurve>, float> >();

            var fileOffset = 0x0;

            var version = BitConverter.ToInt32(_stream, fileOffset);

            var nodeCount         = BitConverter.ToInt32(_stream, fileOffset += 0x04);
            var curveCount        = BitConverter.ToInt32(_stream, fileOffset += 0x04);
            var spawnPointCount   = BitConverter.ToInt32(_stream, fileOffset += 0x0C);
            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         = BitConverter.ToInt32(_stream, fileOffset += 0x08);
            var curveOffset        = BitConverter.ToInt32(_stream, fileOffset += 0x04);
            var spawnPointOffset   = BitConverter.ToInt32(_stream, fileOffset += 0x0C);
            var mapPointOffset     = BitConverter.ToInt32(_stream, fileOffset += 0x10);
            var triggerPointOffset = BitConverter.ToInt32(_stream, fileOffset += 0x04);

            for (var i = 0; i < nodeCount; i++)
            {
                var nodeBaseOffset = nodeOffset + (i * NodeBlockSize);
                var listInput      = new List <int>();
                var listOutput     = new List <int>();
                for (var j = 0; j < 8; j++)
                {
                    var inVal  = BitConverter.ToInt32(_stream, nodeBaseOffset + 0x28 + j * 4);
                    var outVal = BitConverter.ToInt32(_stream, nodeBaseOffset + 0x48 + j * 4);
                    if (inVal != -1)
                    {
                        listInput.Add(inVal);
                    }
                    if (outVal != -1)
                    {
                        listOutput.Add(outVal);
                    }
                }
                var node = new TsPrefabNode
                {
                    id           = i,
                    X            = BitConverter.ToSingle(_stream, nodeBaseOffset + 0x10),
                    Z            = BitConverter.ToSingle(_stream, nodeBaseOffset + 0x18),
                    RotX         = BitConverter.ToSingle(_stream, nodeBaseOffset + 0x1C),
                    RotZ         = BitConverter.ToSingle(_stream, nodeBaseOffset + 0x24),
                    InputPoints  = listInput,
                    OutputPoints = listOutput
                };
                PrefabNodes.Add(node);
            }

            for (var i = 0; i < curveCount; i++)
            {
                var curveBaseOffset = curveOffset + (i * PrefabCurveSize);
                var countNextLines  = BitConverter.ToInt32(_stream, curveBaseOffset + 0x6C);
                var nextLinesList   = new List <int>();
                for (var j = 0; j < countNextLines; j++)
                {
                    nextLinesList.Add(BitConverter.ToInt32(_stream, curveBaseOffset + 0x4C + j * 4));
                }
                var countPrevLines = BitConverter.ToInt32(_stream, curveBaseOffset + 0x70);
                var prevLinesList  = new List <int>();
                for (var j = 0; j < countPrevLines; j++)
                {
                    prevLinesList.Add(BitConverter.ToInt32(_stream, curveBaseOffset + 0x5C + j * 4));
                }
                var curve = new TsPrefabCurve
                {
                    id        = i,
                    idNode    = BitConverter.ToInt32(_stream, curveBaseOffset + 0x0C),
                    start_X   = BitConverter.ToSingle(_stream, curveBaseOffset + 0x10),
                    start_Z   = BitConverter.ToSingle(_stream, curveBaseOffset + 0x18),
                    end_X     = BitConverter.ToSingle(_stream, curveBaseOffset + 0x1C),
                    end_Z     = BitConverter.ToSingle(_stream, curveBaseOffset + 0x24),
                    lenght    = BitConverter.ToSingle(_stream, curveBaseOffset + 0x44),
                    nextLines = nextLinesList,
                    prevLines = prevLinesList
                };
                PrefabCurves.Add(curve);
            }

            for (var i = 0; i < spawnPointCount; i++)
            {
                var spawnPointBaseOffset = spawnPointOffset + (i * SpawnPointBlockSize);
                var spawnPoint           = new TsSpawnPoint
                {
                    X    = BitConverter.ToSingle(_stream, spawnPointBaseOffset),
                    Z    = BitConverter.ToSingle(_stream, spawnPointBaseOffset + 0x08),
                    Type = (TsSpawnPointType)BitConverter.ToUInt32(_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      = BitConverter.ToChar(_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 = 1; break;
                }
                int laneCount;
                switch (laneTypeFlags) // TODO: Change these (not really used atm)
                {
                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 = 0; break;

                default:
                    laneCount = 0;
                    // Log.Msg($"Unknown LaneType: {laneTypeFlags}");
                    break;
                }

                var prefabColorFlags = (byte)BitConverter.ToChar(_stream, mapPointBaseOffset + 0x02);

                var navFlags = (byte)BitConverter.ToChar(_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              = BitConverter.ToSingle(_stream, mapPointBaseOffset + 0x08),
                    Z              = BitConverter.ToSingle(_stream, mapPointBaseOffset + 0x10),
                    Neighbours     = new List <int>(),
                    NeighbourCount = BitConverter.ToInt32(_stream, mapPointBaseOffset + 0x14 + (0x04 * 6))
                };

                for (var x = 0; x < point.NeighbourCount; x++)
                {
                    point.Neighbours.Add(BitConverter.ToInt32(_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        = BitConverter.ToUInt32(_stream, triggerPointBaseOffset),
                    TriggerActionUid = BitConverter.ToUInt64(_stream, triggerPointBaseOffset + 0x04),
                    X = BitConverter.ToSingle(_stream, triggerPointBaseOffset + 0x1C),
                    Z = BitConverter.ToSingle(_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);
                }
            }

            foreach (var inputNode in PrefabNodes)
            {
                foreach (var outputNode in PrefabNodes)
                {
                    if (inputNode.id == outputNode.id)
                    {
                        continue;
                    }
                    var defaultCurve = default(TsPrefabCurve);
                    defaultCurve.id = -1;
                    Dictionary <TsPrefabCurve, Tuple <int, TsPrefabCurve> > distances = new Dictionary <TsPrefabCurve, Tuple <int, TsPrefabCurve> >();
                    Dictionary <TsPrefabCurve, bool> visited = new Dictionary <TsPrefabCurve, bool>();
                    foreach (var curve in PrefabCurves)
                    {
                        distances[curve] = new Tuple <int, TsPrefabCurve>(Int32.MaxValue, defaultCurve);
                    }
                    foreach (var inputCurves in inputNode.InputPoints)
                    {
                        distances[PrefabCurves[inputCurves]] = new Tuple <int, TsPrefabCurve>(0, defaultCurve);
                    }
                    var actualCurve = defaultCurve;
                    while (!outputNode.OutputPoints.Contains(actualCurve.id))
                    {
                        var minVal   = Int32.MaxValue;
                        var minCurve = defaultCurve;
                        foreach (var distance in distances)
                        {
                            if (!visited.ContainsKey(distance.Key))
                            {
                                if (distance.Value.Item1 < minVal)
                                {
                                    minVal   = distance.Value.Item1;
                                    minCurve = distance.Key;
                                }
                            }
                        }
                        actualCurve = minCurve;
                        if (actualCurve.id == -1)
                        {
                            break;
                        }
                        visited[actualCurve] = true;
                        foreach (var nextCurveId in actualCurve.nextLines)
                        {
                            var nextCurve = PrefabCurves[nextCurveId];
                            if (minVal + 1 < distances[nextCurve].Item1 && !visited.ContainsKey(nextCurve))
                            {
                                distances[nextCurve] = new Tuple <int, TsPrefabCurve>(minVal + 1, actualCurve);
                            }
                        }
                    }
                    if (actualCurve.id != -1)
                    {
                        List <TsPrefabCurve> path = new List <TsPrefabCurve>();
                        float length         = (float)distances[actualCurve].Item1;
                        float distanceLength = 0.0f;
                        while (actualCurve.id != -1)
                        {
                            distanceLength += (float)Math.Sqrt(Math.Pow(actualCurve.start_X - actualCurve.end_X, 2) + Math.Pow(actualCurve.start_Z - actualCurve.end_Z, 2));
                            path.Add(actualCurve);
                            actualCurve = distances[actualCurve].Item2;
                        }
                        NavigationRoutes.Add(new Tuple <TsPrefabNode, TsPrefabNode>(inputNode, outputNode), new Tuple <List <TsPrefabCurve>, float>(path, distanceLength));
                    }
                }
            }

            _stream = null;
        }
Beispiel #2
0
        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 navCurveCount = BitConverter.ToInt32(_stream, fileOffset += 0x04);

            ValidRoad = navCurveCount != 0;
            var spawnPointCount   = BitConverter.ToInt32(_stream, fileOffset += 0x0C);
            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),
                };

                int laneCount      = 0;
                var nodeFileOffset = nodeBaseOffset + 0x24;
                for (var j = 0; j < 8; j++)
                {
                    if (MemoryHelper.ReadInt32(_stream, nodeFileOffset += 0x04) != -1)
                    {
                        laneCount++;
                    }
                }

                for (var j = 0; j < 8; j++)
                {
                    if (MemoryHelper.ReadInt32(_stream, nodeFileOffset += 0x04) != -1)
                    {
                        laneCount++;
                    }
                }
                node.LaneCount = laneCount;

                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)
                };
                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);
                var controlNodeIndexFlags = MemoryHelper.ReadInt8(_stream, mapPointBaseOffset + 0x04);
                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

                default:
                    laneCount = 1;
                    // Log.Msg($"Unknown LaneType: {laneTypeFlags}");
                    break;
                }
                sbyte controlNodeIndex = -1;
                switch (controlNodeIndexFlags)
                {
                case 1: controlNodeIndex = 0; break;

                case 2: controlNodeIndex = 1; break;

                case 4: controlNodeIndex = 2; break;

                case 8: controlNodeIndex = 3; break;

                case 16: controlNodeIndex = 4; break;

                case 32: controlNodeIndex = 5; 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)),
                    ControlNodeIndex = controlNodeIndex
                };

                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),
                    TriggerActionToken = MemoryHelper.ReadUInt64(_stream, triggerPointBaseOffset + 0x04),
                    X = MemoryHelper.ReadSingle(_stream, triggerPointBaseOffset + 0x1C),
                    Z = MemoryHelper.ReadSingle(_stream, triggerPointBaseOffset + 0x24),
                };
                TriggerPoints.Add(triggerPoint);
            }

            _stream = null;
        }
Beispiel #3
0
        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;
        }