private static void AddPoints(TsRoadItem road) { if (!road.HasPoints()) { var startNode = road.GetStartNode(); var endNode = road.GetEndNode(); var newPoints = new List <PointF>(); var sx = startNode.X; var sz = startNode.Z; var ex = endNode.X; var ez = endNode.Z; var radius = Math.Sqrt(Math.Pow(sx - ex, 2) + Math.Pow(sz - ez, 2)); var tanSx = Math.Cos(-(Math.PI * 0.5f - startNode.Rotation)) * radius; var tanEx = Math.Cos(-(Math.PI * 0.5f - endNode.Rotation)) * radius; var tanSz = Math.Sin(-(Math.PI * 0.5f - startNode.Rotation)) * radius; var tanEz = Math.Sin(-(Math.PI * 0.5f - endNode.Rotation)) * radius; for (var i = 0; i < 8; i++) { var s = i / (float)(8 - 1); var x = (float)TsRoadLook.Hermite(s, sx, ex, tanSx, tanEx); var z = (float)TsRoadLook.Hermite(s, sz, ez, tanSz, tanEz); newPoints.Add(new PointF(x, z)); } road.AddPoints(newPoints); } }
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; } }
/// <summary> /// Given two roads it search for a path that are inside prefabs between them using a DFS search /// </summary> private Tuple <bool, float> SetInternalRoutePrefab(TsRoadItem Start, TsRoadItem End) { TsNode startNode = null; Dictionary <TsPrefabItem, bool> visited = new Dictionary <TsPrefabItem, bool>(); Stack <List <Tuple <TsNode, TsPrefabItem> > > prefabsToCheck = new Stack <List <Tuple <TsNode, TsPrefabItem> > >(); List <List <Tuple <TsNode, TsPrefabItem> > > possiblePaths = new List <List <Tuple <TsNode, TsPrefabItem> > >(); if (GetNodeByUid(Start.StartNodeUid).BackwardItem.Type == TsItemType.Prefab || GetNodeByUid(Start.StartNodeUid).ForwardItem.Type == TsItemType.Prefab) { startNode = GetNodeByUid(Start.StartNodeUid); var prefab = startNode.BackwardItem.Type == TsItemType.Prefab ? (TsPrefabItem)startNode.BackwardItem : (TsPrefabItem)startNode.ForwardItem; var temp = new List <Tuple <TsNode, TsPrefabItem> >(); temp.Add(new Tuple <TsNode, TsPrefabItem>(startNode, prefab)); prefabsToCheck.Push(temp); } if (GetNodeByUid(Start.EndNodeUid).BackwardItem.Type == TsItemType.Prefab || GetNodeByUid(Start.EndNodeUid).ForwardItem.Type == TsItemType.Prefab) { startNode = GetNodeByUid(Start.EndNodeUid); var prefab = startNode.BackwardItem.Type == TsItemType.Prefab ? (TsPrefabItem)startNode.BackwardItem : (TsPrefabItem)startNode.ForwardItem; var temp = new List <Tuple <TsNode, TsPrefabItem> >(); temp.Add(new Tuple <TsNode, TsPrefabItem>(startNode, prefab)); prefabsToCheck.Push(temp); } while (prefabsToCheck.Count != 0) { List <Tuple <TsNode, TsPrefabItem> > actualPath = prefabsToCheck.Pop(); Tuple <TsNode, TsPrefabItem> actualPrefab = actualPath.LastOrDefault(); if (visited.ContainsKey(actualPrefab.Item2)) { continue; } visited[actualPrefab.Item2] = true; var lastNode = actualPrefab.Item2.NodeIteminPrefab(this, End); if (lastNode != null) { actualPath.Add(new Tuple <TsNode, TsPrefabItem>(lastNode, null)); possiblePaths.Add(actualPath); continue; } foreach (var prefab in actualPrefab.Item2.NodePrefabinPrefab(this)) { var newPath = new List <Tuple <TsNode, TsPrefabItem> >(actualPath); newPath.Add(prefab); prefabsToCheck.Push(newPath); } } var returnValue = new Tuple <bool, float>(false, 0); foreach (var path in possiblePaths) { bool success = true; float totalLength = 0.0f; for (int i = 0; i < path.Count - 1; i++) { var tempData = AddPrefabPath(path[i].Item2, path[i].Item1, path[i + 1].Item1); if (!tempData.Item1) { success = false; break; } totalLength += tempData.Item2; } if (success && path.Count >= 1) { return(new Tuple <bool, float>(true, totalLength / Start.RoadLook.GetWidth())); } } return(returnValue); }
/// <summary> /// Loads navigation inside TsItem objects /// </summary> private void LoadNavigation() { foreach (var prefab in Prefabs) { foreach (var nodeStr in prefab.Nodes) { var node = GetNodeByUid(nodeStr); TsItem road = null; TsNode precnode = node; TsItem precitem = prefab; TsNode nextnode; TsItem nextitem; List <TsItem> roads = new List <TsItem>(); var totalLength = 0.0f; if (node.ForwardItem != null && node.ForwardItem.Type == TsItemType.Road) { road = node.ForwardItem; } else if (node.BackwardItem != null && node.BackwardItem.Type == TsItemType.Road) { road = node.BackwardItem; } if (road != null) { int direction = 0; if (road.EndNodeUid == node.Uid) { direction = 1; } while (road != null && road.Type != TsItemType.Prefab && !road.Hidden) { var length = (float)Math.Sqrt(Math.Pow(GetNodeByUid(road.StartNodeUid).X - GetNodeByUid(road.EndNodeUid).X, 2) + Math.Pow(GetNodeByUid(road.StartNodeUid).Z - GetNodeByUid(road.EndNodeUid).Z, 2)); TsRoadItem roadObj = (TsRoadItem)road; totalLength += length / roadObj.RoadLook.GetWidth(); /*if (roadObj.RoadLook.IsHighway) totalLength += (length / 2) / roadObj.RoadLook.GetWidth(); * else if (roadObj.RoadLook.IsLocal) totalLength += (length / 1.75f) / roadObj.RoadLook.GetWidth(); * else if (roadObj.RoadLook.IsExpress) totalLength += (length / 1.25f) / roadObj.RoadLook.GetWidth(); * else length += length * 2;*/ roads.Add(road); if (GetNodeByUid(road.StartNodeUid) == precnode) { nextnode = GetNodeByUid(road.EndNodeUid); precnode = GetNodeByUid(road.EndNodeUid); } else { nextnode = GetNodeByUid(road.StartNodeUid); precnode = GetNodeByUid(road.StartNodeUid); } if (nextnode.BackwardItem == road || nextnode.BackwardItem == precitem) { nextitem = nextnode.ForwardItem; precitem = nextnode.ForwardItem; } else { nextitem = nextnode.BackwardItem; precitem = nextnode.BackwardItem; } road = nextitem; } if (road != null && !road.Hidden) { TsPrefabItem prevPrefab = (TsPrefabItem)prefab; TsPrefabItem nextPrefab = (TsPrefabItem)road; TsRoadLook look = ((TsRoadItem)roads.LastOrDefault()).RoadLook; if (prevPrefab.Hidden || nextPrefab.Hidden) { continue; } if (prevPrefab.Navigation.ContainsKey(nextPrefab) == false && (look.IsBidirectional() || direction == 0)) { prevPrefab.Navigation.Add(nextPrefab, new Tuple <float, List <TsItem> >(totalLength, roads)); } if (nextPrefab.Navigation.ContainsKey(prevPrefab) == false && (look.IsBidirectional() || direction == 1)) { var reverse = new List <TsItem>(roads); reverse.Reverse(); nextPrefab.Navigation.Add(prevPrefab, new Tuple <float, List <TsItem> >(totalLength, reverse)); } } } else if (node.ForwardItem != null && node.BackwardItem != null) { TsPrefabItem forwardPrefab = (TsPrefabItem)node.ForwardItem; TsPrefabItem backwardPrefab = (TsPrefabItem)node.BackwardItem; if (forwardPrefab.Hidden || backwardPrefab.Hidden) { continue; } if (forwardPrefab.Navigation.ContainsKey(backwardPrefab) == false) { forwardPrefab.Navigation.Add(backwardPrefab, new Tuple <float, List <TsItem> >(0, null)); } if (backwardPrefab.Navigation.ContainsKey(forwardPrefab) == false) { backwardPrefab.Navigation.Add(forwardPrefab, new Tuple <float, List <TsItem> >(0, null)); } } } } Dictionary <ulong, TsPrefabItem> ferryToPrefab = new Dictionary <ulong, TsPrefabItem>(); foreach (var port in FerryConnections) { float min = float.MaxValue; TsPrefabItem closerPrefab = null; foreach (var prefab in Prefabs) { float distance = (float)Math.Sqrt(Math.Pow(port.X - prefab.X, 2) + Math.Pow(port.Z - prefab.Z, 2)); if (distance < min && prefab.Navigation.Count > 1 && !prefab.Hidden) { min = distance; closerPrefab = prefab; } } ferryToPrefab[port.FerryPortId] = closerPrefab; } foreach (var port in FerryConnections) { foreach (var connection in LookupFerryConnection(port.FerryPortId)) { var ports = new List <TsItem>(); ports.Add(FerryPortbyId[connection.StartPortToken]); ports.Add(FerryPortbyId[connection.EndPortToken]); ferryToPrefab[connection.StartPortToken].Navigation.Add(ferryToPrefab[connection.EndPortToken], new Tuple <float, List <TsItem> >(connection.Distance, ports)); ports.Reverse(); ferryToPrefab[connection.EndPortToken].Navigation.Add(ferryToPrefab[connection.StartPortToken], new Tuple <float, List <TsItem> >(connection.Distance, ports)); } } }
public void Parse() { Version = BitConverter.ToInt32(Stream, 0x0); // 853 = 1.31+ 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)BitConverter.ToUInt32(Stream, lastOffset); 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.FerryPortbyId.Add(item.FerryPortId, item); } 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; 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; break; } default: { Log.Msg($"Unknown Type: {type} in {Path.GetFileName(FilePath)} @ {lastOffset}"); break; } } } var nodeCount = BitConverter.ToInt32(Stream, lastOffset); for (var i = 0; i < nodeCount; i++) { TsNode node = new TsNode(this, lastOffset += 0x04); if (!Mapper.Nodes.ContainsKey(node.Uid)) { Mapper.Nodes.Add(node.Uid, node); } lastOffset += 0x34; } }