public static List <OverlappingSector> GetPermitLockedOverlapping()
        {
            HandAuthoredSectorCollection sectors = Sectors;
            List <HandAuthoredSector>    locked  = new List <HandAuthoredSector>();
            List <OverlappingSector>     lockedAndOverlapping = new List <OverlappingSector>();

            for (int i = sectors.Count - 1; i >= 0; i--)
            {
                HandAuthoredSector       sector   = sectors[i];
                List <OverlappingSector> overlaps = lockedAndOverlapping.Where(s => Math.Pow(s.Sector.X - sector.X, 2) + Math.Pow(s.Sector.Y - sector.Y, 2) + Math.Pow(s.Sector.Z - sector.Z, 2) < Math.Pow(s.Sector.Radius + sector.Radius, 2)).ToList();

                if (sector.PermitLocked)
                {
                    locked.Add(sector);
                    lockedAndOverlapping.Add(new OverlappingSector {
                        Sector = sector, Overlapping = new List <HandAuthoredSector>()
                    });
                }
                else if (overlaps.Count != 0)
                {
                    foreach (OverlappingSector overlap in overlaps)
                    {
                        overlap.Overlapping.Add(sector);
                    }
                }
            }

            return(lockedAndOverlapping);
        }
        public static PGStarMatch[] GetStarMatchByName(string sysname)
        {
            if (SystemsByName.ContainsKey(sysname))
            {
                return(SystemsByName[sysname].Select(i => SystemsById[i]).ToArray());
            }
            else
            {
                int                index     = 0;
                int                starclass = 0;
                ByteXYZ            blkcoords = new ByteXYZ();
                int[]              coords    = null;
                HandAuthoredSector sector    = null;

                string regionname = GetProcGenRegionNameFromSystemName(sysname, out index, out starclass, ref blkcoords);

                if (regionname != null)
                {
                    sector = HandAuthoredSectors.Sectors.FindSector(regionname)?.First();
                    if (sector != null)
                    {
                        int[] basecoords = sector.GetBaseBlockCoords(starclass);
                        coords = new int[]
                        {
                            basecoords[0] + blkcoords.X,
                            basecoords[1] + blkcoords.Y,
                            basecoords[2] + blkcoords.Z
                        };
                    }
                    else
                    {
                        ByteXYZ regioncoords = PGSectors.GetSectorPos(regionname);
                        if (regioncoords != ByteXYZ.Invalid)
                        {
                            string _regionname = PGSectors.GetSectorName(regioncoords);
                            coords = new int[]
                            {
                                (regioncoords.X << starclass) + blkcoords.X,
                                (regioncoords.Y << starclass) + blkcoords.Y,
                                (regioncoords.Z << starclass) + blkcoords.Z
                            };
                        }
                    }

                    if (coords != null)
                    {
                        long id = GetProcGenId(coords, starclass, index);

                        if (SystemsById.ContainsKey(id))
                        {
                            return(new PGStarMatch[] { SystemsById[id] });
                        }
                    }
                }
            }

            return(new PGStarMatch[0]);
        }
        public static long GetProcGenId(string sysname, Vector3 starpos, out HandAuthoredSector sector)
        {
            int     index     = 0;
            int     starclass = 0;
            ByteXYZ blkcoords = new ByteXYZ();

            int[] coords = null;
            sector = null;

            string regionname = GetProcGenRegionNameFromSystemName(sysname, out index, out starclass, ref blkcoords);

            if (regionname == null)
            {
                if (SystemsByName.ContainsKey(sysname))
                {
                    List <PGStarMatch> matches = SystemsByName[sysname].Select(s => SystemsById[s]).ToList();
                    foreach (PGStarMatch sm in matches)
                    {
                        Vector3 smcoords = sm.Coords;
                        Vector3 diff     = new Vector3 {
                            X = smcoords.X - starpos.X, Y = smcoords.Y - starpos.Y, Z = smcoords.Z - starpos.Z
                        };
                        double sqdist = diff.X * diff.X + diff.Y * diff.Y + diff.Z * diff.Z;
                        if (sqdist < 0.015625)
                        {
                            sector = sm.HASector;
                            return(sm.Id);
                        }
                    }
                }
                else
                {
                    return(0);
                }
            }
            else
            {
                sector = HandAuthoredSectors.Sectors.FindSector(regionname).FirstOrDefault();
                if (sector != null)
                {
                    int[] basecoords = sector.GetBaseBlockCoords(starclass);
                    coords = new int[]
                    {
                        basecoords[0] + blkcoords.X,
                        basecoords[1] + blkcoords.Y,
                        basecoords[2] + blkcoords.Z
                    };
                }
                else
                {
                    ByteXYZ regioncoords = PGSectors.GetSectorPos(regionname);
                    if (regioncoords != ByteXYZ.Invalid)
                    {
                        coords = new int[]
                        {
                            (regioncoords.X << starclass) + blkcoords.X,
                            (regioncoords.Y << starclass) + blkcoords.Y,
                            (regioncoords.Z << starclass) + blkcoords.Z
                        };
                    }
                }
            }

            if (coords != null)
            {
                long id = GetProcGenId(coords, starclass, index);

                if (id < 0)
                {
                    Console.WriteLine($"Error: {sysname} => {id} ([{coords[0]},{coords[1]},{coords[2]}]:{starclass}:{index})");
                }

                return(id);
            }
            else
            {
                return(0);
            }
        }
        public static PGStarMatch GetStarMatch(string sysname, Vector3 starpos, uint edsmid = 0, uint eddbid = 0)
        {
            int     index     = 0;
            int     starclass = 0;
            ByteXYZ blkcoords = new ByteXYZ();

            int[] coords = null;
            HandAuthoredSector sector = null;

            if (SystemsByName.ContainsKey(sysname))
            {
                List <PGStarMatch> matches = SystemsByName[sysname].Select(i => SystemsById[i]).ToList();

                if (matches.Count == 1)
                {
                    return(matches[0]);
                }

                foreach (PGStarMatch sm in matches)
                {
                    Vector3 smcoords = sm.Coords;
                    Vector3 diff     = new Vector3 {
                        X = smcoords.X - starpos.X, Y = smcoords.Y - starpos.Y, Z = smcoords.Z - starpos.Z
                    };
                    double sqdist = diff.X * diff.X + diff.Y * diff.Y + diff.Z * diff.Z;
                    if (sqdist < 0.015625)
                    {
                        sector = sm.HASector;
                        return(sm);
                    }
                }
            }

            string regionname = GetProcGenRegionNameFromSystemName(sysname, out index, out starclass, ref blkcoords);

            int blocksize = 40960 >> starclass;

            double vx = starpos.X + 49985;
            double vy = starpos.Y + 40985;
            double vz = starpos.Z + 24105;

            if (vx < 0 || vx >= 163840 || vy < 0 || vy > 163840 || vz < 0 || vz > 163840)
            {
                return(PGStarMatch.Invalid);
            }

            int x = (int)(vx * 32 + 0.5);
            int y = (int)(vy * 32 + 0.5);
            int z = (int)(vz * 32 + 0.5);

            int cx = x / blocksize;
            int cy = y / blocksize;
            int cz = z / blocksize;

            if (regionname != null && starpos != null && !Double.IsNaN(starpos.X) && !Double.IsNaN(starpos.Y) && !Double.IsNaN(starpos.Z))
            {
                sector = HandAuthoredSectors.Sectors.FindSector(regionname)?.First();
                if (sector != null)
                {
                    int[] basecoords = sector.GetBaseBlockCoords(starclass);
                    coords = new int[]
                    {
                        basecoords[0] + blkcoords.X,
                        basecoords[1] + blkcoords.Y,
                        basecoords[2] + blkcoords.Z
                    };
                }
                else
                {
                    int     bx           = (x % 40960) / blocksize;
                    int     by           = (y % 40960) / blocksize;
                    int     bz           = (z % 40960) / blocksize;
                    ByteXYZ regioncoords = new ByteXYZ {
                        X = (sbyte)(x / 40960), Y = (sbyte)(y / 40960), Z = (sbyte)(z / 40960)
                    };
                    string  pgregion   = PGSectors.GetSectorName(regioncoords);
                    ByteXYZ nregcoords = pgregion == regionname ? regioncoords : PGSectors.GetSectorPos(regionname);

                    if (bx == blkcoords.X && by == blkcoords.Y && bz == blkcoords.Z && nregcoords == regioncoords)
                    {
                        coords = new int[] { cx, cy, cz };
                    }
                    else
                    {
                        ByteXYZ relcoords = new ByteXYZ {
                            X = (sbyte)bx, Y = (sbyte)by, Z = (sbyte)bz
                        };

                        if (nregcoords == ByteXYZ.Invalid)
                        {
                            Console.WriteLine($"System {sysname}: Unknown sector {regionname} @ {regioncoords} - coordname={pgregion} {GetPgSuffix(relcoords, starclass, index)}");
                        }
                        else
                        {
                            Vector3 namecoords = new Vector3
                            {
                                X = (nregcoords.X * 40960 + blkcoords.X * blocksize) / 32.0 - 49985,
                                Y = (nregcoords.Y * 40960 + blkcoords.Y * blocksize) / 32.0 - 40985,
                                Z = (nregcoords.Z * 40960 + blkcoords.Z * blocksize) / 32.0 - 24105
                            };
                            Console.WriteLine($"System {sysname}: Bad coordinates for sector {regionname} @ {regioncoords} - coordname={pgregion} {GetPgSuffix(relcoords, starclass, index)} | namecoords={namecoords}");
                        }
                        return(PGStarMatch.Invalid);
                    }
                }

                int ix = coords[0];
                int iy = coords[1];
                int iz = coords[2];

                long id = GetProcGenId(coords, starclass, index);

                if (SystemsById.ContainsKey(id))
                {
                    PGStarMatch sm = SystemsById[id];

                    if (cx != ix || cy != iy || cz != iz)
                    {
                        Vector3 error = new Vector3 {
                            X = coords[0] * blocksize / 32.0 - 49985, Y = coords[1] * blocksize / 32.0 - 40985, Z = coords[2] * blocksize / 32.0 - 24105
                        };
                        Console.WriteLine($"Warning: System {sysname} Coord mismatch - starpos={starpos} | match={sm.Coords} | namepos={error}");
                    }

                    if ((eddbid == 0 && edsmid != 0 && sm._EdsmId == 0) || (sm._EdsmId == edsmid && eddbid != 0 && sm._EddbId == 0))
                    {
                        if (eddbid == 0 && edsmid != 0 && sm._EdsmId == 0)
                        {
                            sm._EdsmId = edsmid;
                        }

                        if (sm._EdsmId == edsmid && eddbid != 0 && sm._EddbId == 0)
                        {
                            sm._EddbId = eddbid;
                        }

                        SystemsById[id] = sm;
                    }

                    return(sm);
                }
                else
                {
                    PGStarMatch sm = new PGStarMatch
                    {
                        _RegionCoordsX           = (sbyte)(x / 40960),
                        _RegionCoordsY           = (sbyte)(y / 40960),
                        _RegionCoordsZ           = (sbyte)(z / 40960),
                        _RelCoordsX              = (ushort)(x % 40960),
                        _RelCoordsY              = (ushort)(y % 40960),
                        _RelCoordsZ              = (ushort)(z % 40960),
                        _StarSeq                 = (ushort)index,
                        _StarClass               = (byte)starclass,
                        _HandAuthoredSectorIndex = (ushort)(HandAuthoredSectors.Sectors.IndexOf(sector) + 1),
                        _EdsmId = edsmid,
                        _EddbId = eddbid
                    };

                    if (cx != ix || cy != iy || cz != iz)
                    {
                        Vector3 error = new Vector3 {
                            X = coords[0] * blocksize / 32.0 - 49985, Y = coords[1] * blocksize / 32.0 - 40985, Z = coords[2] * blocksize / 32.0 - 24105
                        };
                        int[] bc = sm.BlockCoords;
                        Console.WriteLine($"Warning: System {sysname} Coord mismatch - pgname={sm.HPGName} | starpos={starpos} | namepos={error} | nc=({coords[0]}, {coords[1]}, {coords[2]}) | pc=({bc[0]}, {bc[1]}, {bc[2]})");
                    }

                    SystemsById[id] = sm;
                    return(sm);
                }
            }
            else
            {
                return(PGStarMatch.Invalid);
            }
        }