Exemple #1
0
        private static void FindNearbyStructuresRecursive(double[] pt, HashSet <ArkStructure> points, KDTree <ArkStructure> tree, Area area, MinMaxCoords minmax, ref int pointsRemoved, Action <Area, ArkStructure, MinMaxCoords> addStructureToArea)
        {
            var near = tree.Nearest(pt, _coordRadius).Where(y => points.Contains(y.Node.Value)).ToArray();

            foreach (var item in near)
            {
                addStructureToArea(area, item.Node.Value, minmax);
                points.Remove(item.Node.Value);
            }
            pointsRemoved += near.Length;

            if (points.Count == 0)
            {
                return;
            }
            if (pointsRemoved >= 50)
            {
                tree          = KDTree.FromData(points.Select(y => new double[] { y.Location.Latitude.Value, y.Location.Longitude.Value }).ToArray(), points.ToArray());
                pointsRemoved = 0;
            }

            foreach (var item in near)
            {
                FindNearbyStructuresRecursive(item.Node.Position, points, tree, area, minmax, ref pointsRemoved, addStructureToArea);
            }
        }
Exemple #2
0
        public StructuresViewModel Get(string id)
        {
            var context = _contextManager.GetServer(id);

            if (context == null)
            {
                return(null);
            }

            var demoMode = IsDemoMode() ? new DemoMode() : null;
            var result   = new StructuresViewModel
            {
                MapName = context.SaveState?.MapName
            };

            var ids    = new ConcurrentDictionary <string, int>();
            var types  = new ConcurrentDictionary <string, StructureTypeViewModel>(StringComparer.OrdinalIgnoreCase);
            var owners = new ConcurrentDictionary <int, StructureOwnerViewModel>();

            var addStructureToArea = new Action <Area, ArkStructure, MinMaxCoords>((area, x, minmax) =>
            {
                //todo: this method may call the update callback even when the key ends up already being in the dict
                var type = types.GetOrAdd(x.ClassName, (key) =>
                {
                    return(new StructureTypeViewModel(new Lazy <int>(() => ids.AddOrUpdate("typeId", 0, (key2, value) => value + 1)))
                    {
                        ClassName = x.ClassName,
                        Name = x.ClassName //todo: we do not have names for structures yet
                    });
                });
                type.Id = type._generateId.Value;

                bool isCrapTier = false;
                if (_trashTier.TryGetValue(type.ClassName, out isCrapTier) && isCrapTier)
                {
                    area.TrashTierCount += 1;
                }
                area.Structures.Add(Tuple.Create(type.Id, x));

                var loc = x.Location;
                if (minmax.MinY == null || loc.Y < minmax.MinY.Y)
                {
                    minmax.MinY = loc;
                }
                if (minmax.MaxY == null || loc.Y > minmax.MaxY.Y)
                {
                    minmax.MaxY = loc;
                }
                if (minmax.MinX == null || loc.X < minmax.MinX.X)
                {
                    minmax.MinX = loc;
                }
                if (minmax.MaxX == null || loc.X > minmax.MaxX.X)
                {
                    minmax.MaxX = loc;
                }
                if (minmax.MinZ == null || loc.Z < minmax.MinZ.Z)
                {
                    minmax.MinZ = loc;
                }
                if (minmax.MaxZ == null || loc.Z > minmax.MaxZ.Z)
                {
                    minmax.MaxZ = loc;
                }
            });

            if (context.Structures != null)
            {
                // make fake structure objects out of rafts to include them in the clustering
                var rafts = context.Rafts?.Select(x => new ArkStructure
                {
                    ClassName      = x.ClassName,
                    Location       = x.Location,
                    OwnerName      = x.OwningPlayerName ?? x.TribeName,
                    OwningPlayerId = x.OwningPlayerId,
                    TargetingTeam  = x.TargetingTeam
                }).ToArray();

                if (rafts == null)
                {
                    rafts = new List <ArkStructure>().ToArray();
                }

                var structureAreas = context.Structures.Concat(rafts).Where(x => (x.TargetingTeam.HasValue || x.OwningPlayerId.HasValue) && x.Location?.Latitude != null && x.Location?.Longitude != null)
                                     .GroupBy(x => x.TargetingTeam ?? x.OwningPlayerId ?? 0)
                                     .AsParallel()
                                     .SelectMany(x =>
                {
                    var first      = x.First();
                    var arkOwnerId = first.TargetingTeam ?? first.OwningPlayerId ?? 0;
                    var isTribe    = first.TargetingTeam.HasValue && (!first.OwningPlayerId.HasValue || first.TargetingTeam.Value != first.OwningPlayerId.Value);
                    var owner      = owners.GetOrAdd(arkOwnerId, (key) =>
                    {
                        var tribe          = isTribe ? context.Tribes.FirstOrDefault(y => y.Id == first.TargetingTeam.Value) : null;
                        var player         = !isTribe ? context.Players.FirstOrDefault(y => y.Id == first.OwningPlayerId) : null;
                        var lastActiveTime = isTribe ? tribe?.LastActiveTime : player?.LastActiveTime;

                        //check saved player last active times for cross server activity
                        var externalLastActiveTime = (DateTime?)null;
                        if (isTribe && tribe != null && tribe.Members.Length > 0)
                        {
                            //for tribes check all last active times for member steamIds (across all servers/clusters)
                            var memberIds = tribe.Members.Select(y => y.SteamId).ToList();
                            var states    = _savedState.PlayerLastActive.Where(y =>
                                                                               y.SteamId != null && memberIds.Contains(y.SteamId, StringComparer.OrdinalIgnoreCase)).ToArray();
                            if (states?.Length > 0)
                            {
                                externalLastActiveTime = states.Max(y => y.LastActiveTime);
                            }
                        }
                        else if (!isTribe && player != null)
                        {
                            //for players check all last active times for player steamid (across all servers/clusters)
                            var states = _savedState.PlayerLastActive.Where(y =>
                                                                            y.SteamId != null && y.SteamId.Equals(player.SteamId, StringComparison.OrdinalIgnoreCase)).ToArray();
                            if (states?.Length > 0)
                            {
                                externalLastActiveTime = states.Max(y => y.LastActiveTime);
                            }
                        }

                        //set last active time to cross server time if it is more recent
                        if ((externalLastActiveTime.HasValue && !lastActiveTime.HasValue) ||
                            (externalLastActiveTime.HasValue && lastActiveTime.HasValue && externalLastActiveTime.Value > lastActiveTime.Value))
                        {
                            lastActiveTime = externalLastActiveTime;
                        }

                        return(new StructureOwnerViewModel(new Lazy <int>(() => ids.AddOrUpdate("ownerId", 0, (key2, value) => value + 1)))
                        {
                            OwnerId = arkOwnerId,
                            Name = demoMode != null ? isTribe ? demoMode.GetTribeName(arkOwnerId) : demoMode.GetPlayerName(arkOwnerId) : first.OwnerName,
                            Type = isTribe ? "tribe" : "player",
                            LastActiveTime = lastActiveTime,
                            CreatureCount = (isTribe ? tribe?.Creatures.Count() : player?.Creatures.Count()) ?? 0
                        });
                    });
                    owner.Id = owner._generateId.Value;

                    var areas      = new List <StructureAreaViewModel>();
                    var structures = new HashSet <ArkStructure>(x);
                    var tree       = KDTree.FromData(x.Select(y => new double[] { y.Location.Latitude.Value, y.Location.Longitude.Value }).ToArray(), x.ToArray());
                    do
                    {
                        var structure = structures.First();
                        structures.Remove(structure);

                        var area   = new Area();
                        var minmax = new MinMaxCoords();
                        addStructureToArea(area, structure, minmax);

                        var n = 0;
                        FindNearbyStructuresRecursive(new double[] { structure.Location.Latitude.Value, structure.Location.Longitude.Value }, structures, tree, area, minmax, ref n, addStructureToArea);

                        //var minLat = area.Min(y => y.Item2.Location.Latitude.Value);
                        //var maxLat = area.Max(y => y.Item2.Location.Latitude.Value);
                        //var minLng = area.Min(y => y.Item2.Location.Longitude.Value);
                        //var maxLng = area.Max(y => y.Item2.Location.Longitude.Value);
                        var dLat   = (minmax.MaxY.Latitude.Value - minmax.MinY.Latitude.Value) / 2f;
                        var dLng   = (minmax.MaxX.Longitude.Value - minmax.MinX.Longitude.Value) / 2f;
                        var avgLat = minmax.MinY.Latitude.Value + dLat;
                        var avgLng = minmax.MinX.Longitude.Value + dLng;

                        var dY   = (minmax.MaxY.Y - minmax.MinY.Y) / 2f;
                        var dX   = (minmax.MaxX.X - minmax.MinX.X) / 2f;
                        var dZ   = (minmax.MaxZ.Z - minmax.MinZ.Z) / 2f;
                        var avgY = minmax.MinY.Y + dY;
                        var avgX = minmax.MinX.X + dX;
                        var avgZ = minmax.MinZ.Z + dZ;

                        var dTopoMapY   = (minmax.MaxY.TopoMapY.Value - minmax.MinY.TopoMapY.Value) / 2f;
                        var dTopoMapX   = (minmax.MaxX.TopoMapX.Value - minmax.MinX.TopoMapX.Value) / 2f;
                        var avgTopoMapY = minmax.MinY.TopoMapY.Value + dTopoMapY;
                        var avgTopoMapX = minmax.MinX.TopoMapX.Value + dTopoMapX;

                        var structureGroups = area.Structures.GroupBy(y => y.Item1).Select(y => new StructureViewModel
                        {
                            TypeId = y.Key,
                            Count  = y.Count()
                        }).OrderByDescending(y => y.Count).ToList();

                        areas.Add(new StructureAreaViewModel
                        {
                            OwnerId        = owner.Id,
                            Structures     = structureGroups,
                            StructureCount = area.Structures.Count,
                            Latitude       = (float)Math.Round(avgLat, 2),
                            Longitude      = (float)Math.Round(avgLng, 2),
                            Radius         = (float)Math.Round(Math.Sqrt(dLat * dLat + dLng * dLng), 2),
                            TopoMapX       = (float)Math.Round(avgTopoMapX, 2),
                            TopoMapY       = (float)Math.Round(avgTopoMapY, 2),
                            RadiusPx       = (float)Math.Round(Math.Sqrt(dTopoMapX * dTopoMapX + dTopoMapY * dTopoMapY), 2),
                            X          = (float)Math.Round(avgX, 2),
                            Y          = (float)Math.Round(avgY, 2),
                            Z          = (float)Math.Round(avgZ, 2),
                            RadiusUu   = (float)Math.Round(Math.Sqrt(dX * dX + dY * dY), 2),
                            TrashQuota = area.TrashTierCount / (float)area.Structures.Count
                        });
                    } while (structures.Count > 0);

                    owner.AreaCount      = areas.Count;
                    owner.StructureCount = areas.Sum(y => y.StructureCount);

                    return(areas);
                }).ToArray();

                result.Areas  = structureAreas.OrderByDescending(x => x.Radius).ThenByDescending(x => x.StructureCount).ToList();
                result.Owners = owners.Values.OrderBy(x => x.Id).ToList();
                result.Types  = types.Values.OrderBy(x => x.Id).ToList();
            }

            return(result);
        }