public Ets2NavigationRoute(Ets2Item start, Ets2Item end, Ets2Point from, Ets2Point to, Ets2Mapper mapper) { Start = start; End = end; From = from; To = to; Mapper = mapper; if (Start != End) ThreadPool.QueueUserWorkItem(new WaitCallback(FindRoute)); }
public Ets2Item FindItem(ulong uid) { Tuple <string, int> inp; if (uid == 0) { return(null); } /*if (Mapper.ItemCache.TryGetValue(uid, out inp)) * { * var item = new Ets2Item(uid, * Mapper.Sectors.FirstOrDefault(x => Path.GetFileNameWithoutExtension(x.FilePath) == inp.Item1), * inp.Item2); * if (!item.Valid) * { * lock (Mapper.ItemCache) * { * Mapper.ItemCache.Remove(uid); * } * } * else * { * return item; * } * }*/ var pos = SearchUID(BitConverter.GetBytes(uid)); foreach (var off in pos) { var offs = off - 4; var type = BitConverter.ToUInt32(Stream, offs); if (type < 0x40 && type != 0) { var item = new Ets2Item(uid, this, offs); if (item.Valid) { /*lock (Mapper.ItemCache) * { * Mapper.ItemCache.Add(uid, * new Tuple<string, int>(Path.GetFileNameWithoutExtension(FilePath), offs)); * }*/ return(item); } } } return(null); }
public Ets2NavigationRoute(Ets2Item start, Ets2Item end, Ets2Point from, Ets2Point to, Ets2Mapper mapper) { Start = start; End = end; From = from; To = to; Mapper = mapper; if (Start != End) { ThreadPool.QueueUserWorkItem(new WaitCallback(FindRoute)); } }
public Ets2NavigationSegment(Ets2Item prefab) { Type = Ets2NavigationSegmentType.Prefab; Prefab = prefab; }
private float RoadDistance(Ets2Item road, float x, float y) { if (road == null) return float.MaxValue; if (road.StartNode == null || road.EndNode == null) return float.MaxValue; if (Math.Abs(road.StartNode.X - x) > 500) return float.MaxValue; if (Math.Abs(road.StartNode.Z - y) > 500) return float.MaxValue; if (road.RoadPolygons == null) road.GenerateRoadPolygon(64); var minPerPoint = float.MaxValue; foreach (var pt in road.RoadPolygons) { var dx1 = pt.X - x; var dy1 = pt.Y - y; var r1 = (float)Math.Sqrt(dx1 * dx1 + dy1 * dy1); if (minPerPoint >= r1) minPerPoint = r1; } return minPerPoint; }
private bool OutsideRoad(Ets2Item road, float x, float y) { if (road == null) return true; if (road.StartNode == null || road.EndNode == null) return true; var minX = Math.Min(road.StartNode.X, road.EndNode.X); var maxX = Math.Max(road.StartNode.X, road.EndNode.X); var minY = Math.Min(road.StartNode.Z, road.EndNode.Z); var maxY = Math.Max(road.StartNode.Z, road.EndNode.Z); var margin = 10.5f; if (minX - margin >= x && maxX + margin <= x && minY - margin >= y && maxY + margin <= y) { return false; } else { return true; } }
public void Parse() { ThreadPool.SetMaxThreads(2, 2); Loading = true; // First load prefabs PrefabsLookup = PrefabFiles.Select(x => new Ets2Prefab(this, x)).ToList(); // Load all LUTs LoadLUT(); ItemSearchRequests = new List <Ets2ItemSearchRequest>(); Sectors = SectorFiles.Select(x => new Ets2Sector(this, x)).ToList(); // 2-stage process so we can validate node UID's at item stage ThreadPool.SetMaxThreads(1, 1); Parallel.ForEach(Sectors, (sec) => sec.ParseNodes()); Parallel.ForEach(Sectors, (sec) => sec.ParseItems()); Loading = false; // Now find all that were not ofund ItemSearchRequests.Clear(); Console.WriteLine(ItemSearchRequests.Count + " were not found; attempting to search them through all sectors"); foreach (var req in ItemSearchRequests) { Ets2Item item = Sectors.Select(sec => sec.FindItem(req.ItemUID)).FirstOrDefault(tmp => tmp != null); if (item == null) { Console.WriteLine("Still couldn't find node " + req.ItemUID.ToString("X16")); } else { if (req.IsBackward) { item.Apply(req.Node); req.Node.BackwardItem = item; } if (req.IsForward) { item.Apply(req.Node); req.Node.ForwardItem = item; } if (item.StartNode == null && item.StartNodeUID != null) { Ets2Node startNode; if (Nodes.TryGetValue(item.StartNodeUID, out startNode)) { item.Apply(startNode); } } if (item.EndNode == null && item.EndNodeUID != null) { Ets2Node endNode; if (Nodes.TryGetValue(item.EndNodeUID, out endNode)) { item.Apply(endNode); } } Console.Write("."); } } // Navigation cache BuildNavigationCache(); // Lookup all cities Cities = Items.Values.Where(x => x.Type == Ets2ItemType.City).GroupBy(x => x.City).Select(x => x.FirstOrDefault()).ToDictionary(x => x.City, x => x); Console.WriteLine(Items.Values.Count(x => x.Type == Ets2ItemType.Building) + " buildings were found"); Console.WriteLine(Items.Values.Count(x => x.Type == Ets2ItemType.Road) + " roads were found"); Console.WriteLine(Items.Values.Count(x => x.Type == Ets2ItemType.Prefab) + " prefabs were found"); Console.WriteLine(Items.Values.Count(x => x.Type == Ets2ItemType.Prefab && x.Prefab != null && x.Prefab.Curves.Any()) + " road prefabs were found"); Console.WriteLine(Items.Values.Count(x => x.Type == Ets2ItemType.Service) + " service points were found"); Console.WriteLine(Items.Values.Count(x => x.Type == Ets2ItemType.Company) + " companies were found"); Console.WriteLine(Items.Values.Count(x => x.Type == Ets2ItemType.City) + " cities were found"); }
private void FindRoute(object state) { Loading = true; Dictionary <ulong, Tuple <float, Ets2Item> > nodeMap = new Dictionary <ulong, Tuple <float, Ets2Item> >(); List <Ets2Item> nodesToWalk = new List <Ets2Item>(); // Fill node map foreach (var node in Mapper.Items.Values.Where(x => x.Type == Ets2ItemType.Prefab && x.HideUI == false)) { nodesToWalk.Add(node); nodeMap.Add(node.ItemUID, new Tuple <float, Ets2Item>(float.MaxValue, null)); } // Walk first node (START) if (nodeMap.ContainsKey(Start.ItemUID) == false) { // Nope return; } if (nodeMap.ContainsKey(End.ItemUID) == false) { // Nope return; } // <Weight, LastItem> nodeMap[Start.ItemUID] = new Tuple <float, Ets2Item>(0, null); while (nodesToWalk.Any()) { float distanceWalked = float.MaxValue; Ets2Item toWalk = null; foreach (var node in nodesToWalk) { var dTmp = nodeMap[node.ItemUID].Item1; if (dTmp != float.MaxValue && distanceWalked > dTmp) { distanceWalked = dTmp; toWalk = node; } } if (toWalk == null) { break; } nodesToWalk.Remove(toWalk); var currentWeight = nodeMap[toWalk.ItemUID].Item1; // Iterate all destination nodes from this node foreach (var jump in toWalk.Navigation) { var newWeight = jump.Value.Item1 + currentWeight; var newNode = jump.Key; if (nodeMap.ContainsKey(newNode.ItemUID) && nodeMap[newNode.ItemUID].Item1 > newWeight) { nodeMap[newNode.ItemUID] = new Tuple <float, Ets2Item>(newWeight, toWalk); } // add route with weight + previous node } } List <Ets2Item> routeNodes = new List <Ets2Item>(); List <Ets2Item> routeRoads = new List <Ets2Item>(); List <Ets2NavigationSegment> segments = new List <Ets2NavigationSegment>(); var goingViaNode = (ulong)0; var route = End; while (route != null) { // we add this prefab to the route list routeNodes.Add(route); var prefabSeg = new Ets2NavigationSegment(route); segments.Add(prefabSeg); // find the next prefab in the route description var gotoNew = nodeMap[route.ItemUID].Item2; if (gotoNew == null) { break; } // get a path from the current prefab to the new one var path = route.Navigation[gotoNew]; var roadPath = path.Item3; // add the path to road list routeRoads.AddRange(roadPath); segments.Add(new Ets2NavigationSegment(roadPath, prefabSeg)); // Set the new prefab as route route = gotoNew; } routeNodes.Add(Start); segments.Reverse(); // Find entry/exit of start/end segment var foundDst = float.MaxValue; var foundNode = default(Ets2Node); // Find the closest road to startpoint foreach (var node in segments[0].Prefab.NodesList) { var dst = node.Value.Point.DistanceTo(From); if (foundDst > dst) { foundDst = dst; foundNode = node.Value; } } // We found the node; find the road that exists at this point segments[0].Entry = foundNode; foundDst = float.MaxValue; foundNode = default(Ets2Node); // Find the closest road to startpoint foreach (var node in segments[segments.Count - 1].Prefab.NodesList) { var dst = node.Value.Point.DistanceTo(To); if (foundDst > dst) { foundDst = dst; foundNode = node.Value; } } // We found the node; find the road that exists at this point segments[segments.Count - 1].Exit = foundNode; // Iterate all segments for (int seg = 0; seg < segments.Count; seg++) { // Generate prefab routes if (segments[seg].Type == Ets2NavigationSegmentType.Prefab) { var prevRoad = seg > 0 ? segments[seg - 1] : null; var nextRoad = seg + 1 < segments.Count ? segments[seg + 1] : null; // Link segments together if (prevRoad != null) { segments[seg].Entry = prevRoad.Entry; } if (nextRoad != null) { segments[seg].Exit = nextRoad.Exit; } segments[seg].GenerateOptions(prevRoad, nextRoad); } // Generate lane data if (segments[seg].Type == Ets2NavigationSegmentType.Road) { var prefFab = seg > 0 ? segments[seg - 1] : null; var nextFab = seg + 1 < segments.Count ? segments[seg + 1] : null; segments[seg].GenerateOptions(prefFab, nextFab); } } //for (int seg = 1; seg < segments.Count - 1; seg++) for (int seg = 0; seg < segments.Count; seg++) { // Validate routes if (segments[seg].Type == Ets2NavigationSegmentType.Prefab) { var prevRoad = seg > 0 ? segments[seg - 1] : null; var nextRoad = seg + 1 < segments.Count ? segments[seg + 1] : null; foreach (var opt in segments[seg].Options) { if (prevRoad == null) { // start point; validate if it is close to our start node if (opt.Points.FirstOrDefault().DistanceTo(segments[seg].Entry.Point) < 10) { opt.EntryLane = 0; // yep; sure } } else { var entryPoint = opt.Points.FirstOrDefault(); foreach (var roadOpt in prevRoad.Options) { if (roadOpt.Points.Any(x => x.CloseTo(entryPoint))) { // We've got a match ! :D opt.EntryLane = roadOpt.ExitLane; roadOpt.Valid = roadOpt.EntryLane >= 0 && roadOpt.ExitLane >= 0; } } } if (nextRoad == null) { // last point. if (opt.Points.FirstOrDefault().DistanceTo(segments[seg].Exit.Point) < 10) { opt.ExitLane = 0; // yep; sure } } else { var exitPoint = opt.Points.LastOrDefault(); foreach (var roadOpt in nextRoad.Options) { if (roadOpt.Points.Any(x => x.CloseTo(exitPoint))) { // We've got a match ! :D opt.ExitLane = roadOpt.EntryLane; roadOpt.Valid = roadOpt.EntryLane >= 0 && roadOpt.ExitLane >= 0; } } } opt.Valid = opt.EntryLane >= 0 && opt.ExitLane >= 0; } } // Generate prefab routes if (segments[seg].Type == Ets2NavigationSegmentType.Road && false) { var nextPrefab = segments[seg + 1]; var prevPrefab = segments[seg - 1]; if (nextPrefab.Type != Ets2NavigationSegmentType.Prefab || prevPrefab.Type != Ets2NavigationSegmentType.Prefab) { continue; } // Deduct road options by matching entry/exits for (int solI = 0; solI < segments[seg].Options.Count; solI++) { // Find if there is any route in prefab that matches our entry lane var okStart = prevPrefab.Options.Any(x => segments[seg].MatchEntry(solI, prevPrefab)); var okEnd = nextPrefab.Options.Any(x => segments[seg].MatchExit(solI, nextPrefab)); // This road has a valid end & Start if (okStart && okEnd) { segments[seg].Options[solI].Valid = true; } } } } // There is probably only 1 valid solution for entry/exit //if (segments[0].Options.Any()) segments[0].Options[0].Valid = true; //if (segments[segments.Count - 1].Options.Any()) segments[segments.Count - 1].Options[0].Valid = true; Segments = segments; var pts = Segments.SelectMany(x => x.Solutions).SelectMany(x => x.Points).ToList(); Roads = routeRoads; Prefabs = routeNodes.Select(x => new Tuple <Ets2Item, int, int>(x, 0, 0)).ToList(); Loading = false; }
public Ets2Item FindItem(ulong uid) { Tuple<string, int> inp; if (uid == 0) return null; /*if (Mapper.ItemCache.TryGetValue(uid, out inp)) { var item = new Ets2Item(uid, Mapper.Sectors.FirstOrDefault(x => Path.GetFileNameWithoutExtension(x.FilePath) == inp.Item1), inp.Item2); if (!item.Valid) { lock (Mapper.ItemCache) { Mapper.ItemCache.Remove(uid); } } else { return item; } }*/ var pos = SearchUID(BitConverter.GetBytes(uid)); foreach (var off in pos) { var offs = off - 4; var type = BitConverter.ToUInt32(Stream, offs); if (type < 0x40 && type != 0) { var item = new Ets2Item(uid, this, offs); if (item.Valid) { /*lock (Mapper.ItemCache) { Mapper.ItemCache.Add(uid, new Tuple<string, int>(Path.GetFileNameWithoutExtension(FilePath), offs)); }*/ return item; } } } return null; }