public TsPrefabNode GetNearestNode(TsMapper _mapper, TsNode item, int mode) { // Mode: 0 -> Only Input Points ; 1 -> Only Output Points ; whatever else -> All Points TsPrefabNode node = default(TsPrefabNode); node.id = -1; float min = float.MaxValue; var originNode = _mapper.GetNodeByUid(this.Nodes[0]); var mapPointOrigin = this.Prefab.PrefabNodes[this.Origin]; var prefabStartX = originNode.X - mapPointOrigin.X; var prefabStartZ = originNode.Z - mapPointOrigin.Z; var rot = (float)(originNode.Rotation - Math.PI - Math.Atan2(mapPointOrigin.RotZ, mapPointOrigin.RotX) + Math.PI / 2); foreach (var nod in this.Prefab.PrefabNodes) { if (nod.InputPoints.Count <= 0 && mode == 0) { continue; } if (nod.OutputPoints.Count <= 0 && mode == 1) { continue; } var newPoint = TsMapRenderer.RotatePoint(prefabStartX + nod.X, prefabStartZ + nod.Z, rot, originNode.X, originNode.Z); float dist = (float)Math.Sqrt(Math.Pow(item.X - (newPoint.X), 2) + Math.Pow(item.Z - (newPoint.Y), 2)); if (dist < min && dist < 0.2) { node = nod; min = dist; } } return(node); }
public void UpdateEdgeCoords(TsNode node) { if (minX > node.X) { minX = node.X; } if (maxX < node.X) { maxX = node.X; } if (minZ > node.Z) { minZ = node.Z; } if (maxZ < node.Z) { maxZ = node.Z; } }
public Tuple <bool, float> AddPrefabPath(TsPrefabItem prefab, TsNode startNode, TsNode endNode) { //Optional - some prefabs, like gas stastions will be completely selected instead of selecting a sigle road //if (prefab.Prefab.PrefabNodes.Count <= 2) { // RoutePrefabs.Add(prefab); // return true; //} var returnValue = new Tuple <bool, float>(false, 0); var s = prefab.GetNearestNode(this, startNode, 0); var e = prefab.GetNearestNode(this, endNode, 1); if (s.id == -1 || e.id == -1) { return(returnValue); } var key = new Tuple <TsPrefabNode, TsPrefabNode>(s, e); if (prefab.Prefab.NavigationRoutes.ContainsKey(key)) { PrefabNav[prefab] = prefab.Prefab.NavigationRoutes[key].Item1; returnValue = new Tuple <bool, float>(true, prefab.Prefab.NavigationRoutes[key].Item2); } return(returnValue); }
public TsNode GetEndNode() { return(EndNode ?? (EndNode = Sector.Mapper.GetNodeByUid(EndNodeUid))); }
public TsNode GetStartNode() { return(StartNode ?? (StartNode = Sector.Mapper.GetNodeByUid(StartNodeUid))); }
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; } }