diff --git a/Changelog.txt b/Changelog.txt index dae17e73b0..5798965727 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,3 +1,6 @@ +Version 2.2.026 + Fixed NPE on ChunkUnloadEvent + Version 2.2.025 Fixed NullPointerException spam when processing XP for child skills diff --git a/pom.xml b/pom.xml index 12419f99c8..f16a290b29 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.2.025 + 2.2.026 mcMMO https://github.com/mcMMO-Dev/mcMMO diff --git a/src/main/java/com/gmail/nossr50/util/blockmeta/HashChunkManager.java b/src/main/java/com/gmail/nossr50/util/blockmeta/HashChunkManager.java index aa5d9da2f4..5d860e0e31 100644 --- a/src/main/java/com/gmail/nossr50/util/blockmeta/HashChunkManager.java +++ b/src/main/java/com/gmail/nossr50/util/blockmeta/HashChunkManager.java @@ -39,9 +39,7 @@ public synchronized void closeAll() { } private synchronized @Nullable ChunkStore readChunkStore(@NotNull World world, int cx, int cz) throws IOException { - McMMOSimpleRegionFile rf = getReadableSimpleRegionFile(world, cx, cz); - if (rf == null) - return null; // If there is no region file, there can't be a chunk + final McMMOSimpleRegionFile rf = getWriteableSimpleRegionFile(world, cx, cz); try (DataInputStream in = rf.getInputStream(cx, cz)) { // Get input stream for chunk if (in == null) return null; // No chunk @@ -74,17 +72,6 @@ private synchronized void writeChunkStore(@NotNull World world, @NotNull ChunkSt }); } - private synchronized @Nullable McMMOSimpleRegionFile getReadableSimpleRegionFile(@NotNull World world, int cx, int cz) { - CoordinateKey regionKey = toRegionKey(world.getUID(), cx, cz); - - return regionMap.computeIfAbsent(regionKey, k -> { - File regionFile = getRegionFile(world, regionKey); - if (!regionFile.exists()) - return null; // Don't create the file on read-only operations - return new McMMOSimpleRegionFile(regionFile, regionKey.x, regionKey.z); - }); - } - private @NotNull File getRegionFile(@NotNull World world, @NotNull CoordinateKey regionKey) { if (world.getUID() != regionKey.worldID) throw new IllegalArgumentException(); @@ -112,7 +99,7 @@ private void unloadChunk(int cx, int cz, @NotNull World world) { CoordinateKey regionKey = toRegionKey(world.getUID(), cx, cz); HashSet chunkKeys = chunkUsageMap.get(regionKey); chunkKeys.remove(chunkKey); // remove from region file in-use set - // If it was last chunk in region, close the region file and remove it from memory + // If it was last chunk in the region, close the region file and remove it from memory if (chunkKeys.isEmpty()) { chunkUsageMap.remove(regionKey); regionMap.remove(regionKey).close(); diff --git a/src/test/java/com/gmail/nossr50/util/blockmeta/UserBlockTrackerTest.java b/src/test/java/com/gmail/nossr50/util/blockmeta/UserBlockTrackerTest.java index 5bdf5e4853..a522b35855 100644 --- a/src/test/java/com/gmail/nossr50/util/blockmeta/UserBlockTrackerTest.java +++ b/src/test/java/com/gmail/nossr50/util/blockmeta/UserBlockTrackerTest.java @@ -170,6 +170,27 @@ void testRegressionChunkMirrorBug() { assertTrue(chunkManager.isIneligible(mockBlockA)); } + @Test + void testUnload() { + final ChunkManager chunkManager = new HashChunkManager(); + Block mockBlockA = Mockito.mock(Block.class); + when(mockBlockA.getX()).thenReturn(15); + when(mockBlockA.getZ()).thenReturn(15); + when(mockBlockA.getY()).thenReturn(0); + when(mockBlockA.getWorld()).thenReturn(mockWorld); + Block mockBlockB = Mockito.mock(Block.class); + when(mockBlockB.getX()).thenReturn(-15); + when(mockBlockB.getZ()).thenReturn(-15); + when(mockBlockB.getY()).thenReturn(0); + when(mockBlockB.getWorld()).thenReturn(mockWorld); + + chunkManager.setIneligible(mockBlockA); + chunkManager.setEligible(mockBlockB); + assertTrue(chunkManager.isIneligible(mockBlockA)); + + chunkManager.chunkUnloaded(0, 0, mockWorld); + } + @NotNull private Block initMockBlock(int x, int y, int z) { final Block mockBlock = Mockito.mock(Block.class);