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);