diff --git a/src/main/java/cr0s/warpdrive/data/GlobalRegionManager.java b/src/main/java/cr0s/warpdrive/data/GlobalRegionManager.java index 9ce7213d4..2c9ec71ee 100644 --- a/src/main/java/cr0s/warpdrive/data/GlobalRegionManager.java +++ b/src/main/java/cr0s/warpdrive/data/GlobalRegionManager.java @@ -52,6 +52,10 @@ public class GlobalRegionManager { public static String GALAXY_UNDEFINED = "???"; private static final HashMap> registry = new HashMap<>(); + private static final HashMap>> cache_registryByType = new HashMap<>(); + private static final HashMap>> cache_registryByChunk = new HashMap<>(); + private static final HashMap cache_registryByUUID = new HashMap<>(); + private static final HashMap> cache_registryByName = new HashMap<>(); private static int countAdd = 0; private static int countRemove = 0; private static int countRead = 0; @@ -68,6 +72,11 @@ public static void updateInRegistry(@Nonnull final IGlobalRegionProvider globalR globalRegionProvider )); return; } + if (globalRegionProvider.getGlobalRegionType() == null) { + WarpDrive.logger.error(String.format("Ignoring invalid IGlobalRegionProvider with no region type %s", + globalRegionProvider )); + return; + } // update statistics countRead++; @@ -101,6 +110,7 @@ public static void updateInRegistry(@Nonnull final IGlobalRegionProvider globalR // note: in-place update only works as long as hashcode remains unchanged, that means same position, same type, same UUID registryItem.update(globalRegionProvider); setRegistryItems.removeAll(listToRemove); + rebuildIndexes(); if (WarpDriveConfig.LOGGING_GLOBAL_REGION_REGISTRY) { printRegistry("updated"); } @@ -116,6 +126,7 @@ public static void updateInRegistry(@Nonnull final IGlobalRegionProvider globalR countAdd++; setRegistryItems.add(new GlobalRegion(globalRegionProvider)); registry.put(globalRegionProvider.getDimension(), setRegistryItems); + rebuildIndexes(); if (WarpDriveConfig.LOGGING_GLOBAL_REGION_REGISTRY) { printRegistry("added"); } @@ -135,6 +146,7 @@ public static void removeFromRegistry(@Nonnull final IGlobalRegionProvider globa // found it, remove and exit countRemove++; setRegistryItems.remove(registryItem); + rebuildIndexes(); return; } } @@ -143,6 +155,15 @@ public static void removeFromRegistry(@Nonnull final IGlobalRegionProvider globa @Nullable public static GlobalRegion getByName(final EnumGlobalRegionType enumGlobalRegionType, final String name) { + final Set setByName = cache_registryByName.get(name == null ? "" : name); + if (setByName != null) { + for (final GlobalRegion globalRegion : setByName) { + if ( enumGlobalRegionType == null + || globalRegion.type == enumGlobalRegionType ) { + return globalRegion; + } + } + } for (final Integer dimensionId : registry.keySet()) { final CopyOnWriteArraySet setGlobalRegions = registry.get(dimensionId); if (setGlobalRegions == null) { @@ -165,6 +186,12 @@ public static GlobalRegion getByUUID(final EnumGlobalRegionType enumGlobalRegion if (uuid == null) { return null; } + final GlobalRegion globalRegionCached = cache_registryByUUID.get(uuid); + if ( globalRegionCached != null + && ( enumGlobalRegionType == null + || globalRegionCached.type == enumGlobalRegionType ) ) { + return globalRegionCached; + } for (final Integer dimensionId : registry.keySet()) { final CopyOnWriteArraySet setGlobalRegions = registry.get(dimensionId); if (setGlobalRegions == null) { @@ -251,7 +278,7 @@ public static String listByKeyword(final EnumGlobalRegionType enumGlobalRegionTy @Nullable public static GlobalRegion getNearest(final EnumGlobalRegionType enumGlobalRegionType, @Nonnull final World world, @Nonnull final BlockPos blockPos) { - final CopyOnWriteArraySet setGlobalRegions = registry.get(world.provider.getDimension()); + final Set setGlobalRegions = getRegionsByType(world.provider.getDimension(), enumGlobalRegionType); if (setGlobalRegions == null) { return null; } @@ -280,7 +307,7 @@ public static GlobalRegion getNearest(final EnumGlobalRegionType enumGlobalRegio @Nonnull public static ArrayList getContainers(final EnumGlobalRegionType enumGlobalRegionType, @Nonnull final World world, @Nonnull final BlockPos blockPos) { - final CopyOnWriteArraySet setGlobalRegions = registry.get(world.provider.getDimension()); + final Set setGlobalRegions = getRegionsByChunk(world.provider.getDimension(), blockPos); if (setGlobalRegions == null) { return new ArrayList<>(0); } @@ -316,7 +343,7 @@ public static boolean onBlockUpdating(@Nullable final Entity entity, @Nonnull fi blockState, Commons.format(world, blockPos) )); return false; } - final CopyOnWriteArraySet setGlobalRegions = registry.get(world.provider.getDimension()); + final Set setGlobalRegions = getRegionsByChunk(world.provider.getDimension(), blockPos); if (setGlobalRegions == null) { return true; } @@ -339,11 +366,11 @@ public static boolean onChatReceived(@Nonnull final EntityPlayer entityPlayer, @ entityPlayer, message )); return false; } - final CopyOnWriteArraySet setGlobalRegions = registry.get(entityPlayer.world.provider.getDimension()); + final BlockPos blockPos = entityPlayer.getPosition(); + final Set setGlobalRegions = getRegionsByChunk(entityPlayer.world.provider.getDimension(), blockPos); if (setGlobalRegions == null) { return true; } - final BlockPos blockPos = entityPlayer.getPosition(); boolean isCancelled = false; for (final GlobalRegion registryItem : setGlobalRegions) { if (registryItem.type == EnumGlobalRegionType.VIRTUAL_ASSISTANT @@ -431,6 +458,68 @@ public static Vector3 getUniversalCoordinates(final CelestialObject celestialObj } return hasHyperspace ? vec3Result : null; } + + @Nullable + private static Set getRegionsByType(final int dimensionId, @Nullable final EnumGlobalRegionType enumGlobalRegionType) { + if (enumGlobalRegionType == null) { + return registry.get(dimensionId); + } + final HashMap> mapByType = cache_registryByType.get(dimensionId); + return mapByType == null ? null : mapByType.get(enumGlobalRegionType); + } + + @Nullable + private static Set getRegionsByChunk(final int dimensionId, @Nonnull final BlockPos blockPos) { + final HashMap> mapByChunk = cache_registryByChunk.get(dimensionId); + return mapByChunk == null ? null : mapByChunk.get(ChunkPos.asLong(blockPos.getX() >> 4, blockPos.getZ() >> 4)); + } + + private static void rebuildIndexes() { + cache_registryByType.clear(); + cache_registryByChunk.clear(); + cache_registryByUUID.clear(); + cache_registryByName.clear(); + for (final Map.Entry> entryDimension : registry.entrySet()) { + final int dimensionId = entryDimension.getKey(); + final HashMap> mapByType = new HashMap<>(); + final HashMap> mapByChunk = new HashMap<>(); + for (final GlobalRegion globalRegion : entryDimension.getValue()) { + if ( globalRegion == null + || globalRegion.type == null ) { + continue; + } + CopyOnWriteArraySet setByType = mapByType.get(globalRegion.type); + if (setByType == null) { + setByType = new CopyOnWriteArraySet<>(); + mapByType.put(globalRegion.type, setByType); + } + setByType.add(globalRegion); + if (globalRegion.uuid != null) { + cache_registryByUUID.put(globalRegion.uuid, globalRegion); + } + final String name = globalRegion.name == null ? "" : globalRegion.name; + CopyOnWriteArraySet setByName = cache_registryByName.get(name); + if (setByName == null) { + setByName = new CopyOnWriteArraySet<>(); + cache_registryByName.put(name, setByName); + } + setByName.add(globalRegion); + for (int xChunk = globalRegion.minX >> 4; xChunk <= globalRegion.maxX >> 4; xChunk++) { + for (int zChunk = globalRegion.minZ >> 4; zChunk <= globalRegion.maxZ >> 4; zChunk++) { + final Long keyChunk = ChunkPos.asLong(xChunk, zChunk); + CopyOnWriteArraySet setByChunk = mapByChunk.get(keyChunk); + if (setByChunk == null) { + setByChunk = new CopyOnWriteArraySet<>(); + mapByChunk.put(keyChunk, setByChunk); + } + setByChunk.add(globalRegion); + } + } + } + cache_registryByType.put(dimensionId, mapByType); + cache_registryByChunk.put(dimensionId, mapByChunk); + } + } public static void printRegistry(final String trigger) { WarpDrive.logger.info(String.format("Global region registry after %s:", trigger)); @@ -564,7 +653,9 @@ private static void cleanup() { final TileEntity tileEntity = world.getTileEntity(registryItem.getBlockPos()); isValid = true; - switch (registryItem.type) { + if (registryItem.type == null) { + isValid = false; + } else switch (registryItem.type) { case UNDEFINED: break; case SHIP: @@ -608,6 +699,7 @@ private static void cleanup() { } } } + rebuildIndexes(); LocalProfiler.stop(); } @@ -617,6 +709,7 @@ public static void readFromNBT(@Nullable final NBTTagCompound tagCompound) { || ( !tagCompound.hasKey("starMapRegistryItems") && !tagCompound.hasKey("globalRegions") ) ) { registry.clear(); + rebuildIndexes(); return; } @@ -631,6 +724,9 @@ public static void readFromNBT(@Nullable final NBTTagCompound tagCompound) { final HashMap sizeDimensions = new HashMap<>(); for (int index = 0; index < tagList.tagCount(); index++) { final GlobalRegion globalRegion = new GlobalRegion(tagList.getCompoundTagAt(index)); + if (globalRegion.type == null) { + continue; + } registryFlat[index] = globalRegion; // update stats @@ -647,6 +743,9 @@ public static void readFromNBT(@Nullable final NBTTagCompound tagCompound) { // fill the local collections for (final GlobalRegion globalRegion : registryFlat) { + if (globalRegion == null) { + continue; + } registryLocal.get(globalRegion.dimensionId).add(globalRegion); } @@ -655,6 +754,7 @@ public static void readFromNBT(@Nullable final NBTTagCompound tagCompound) { for (final Entry> entry : registryLocal.entrySet()) { registry.put(entry.getKey(), new CopyOnWriteArraySet<>(entry.getValue())); } + rebuildIndexes(); } public static void writeToNBT(@Nonnull final NBTTagCompound tagCompound) {