diff --git a/Changelog.txt b/Changelog.txt
index 4641b529d..4515641b0 100644
--- a/Changelog.txt
+++ b/Changelog.txt
@@ -1,3 +1,11 @@
+Version 2.2.013
+ (API) Added new methods to com.gmail.nossr50.util.blockmeta.UserBlockTracker for easier readability
+ (API) Deprecated the old poorly named methods in UserBlockTracker
+ (Codebase) Cleaned up and organized unit tests relating to UserBlockTracker
+
+ NOTES:
+ Not planning to delete the deprecated methods in UserBlockTracker anytime soon, as nothing has really changed other than the names
+
Version 2.2.012
Fixed a bug where Daze would cause an exception in older game versions (1.20.4 and older)
diff --git a/pom.xml b/pom.xml
index a8ce46efc..dbfe0175c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2,7 +2,7 @@
4.0.0
com.gmail.nossr50.mcMMO
mcMMO
- 2.2.012
+ 2.2.013-SNAPSHOT
mcMMO
https://github.com/mcMMO-Dev/mcMMO
diff --git a/src/main/java/com/gmail/nossr50/config/skills/alchemy/PotionConfig.java b/src/main/java/com/gmail/nossr50/config/skills/alchemy/PotionConfig.java
index ecc16e66e..d0cad88b5 100644
--- a/src/main/java/com/gmail/nossr50/config/skills/alchemy/PotionConfig.java
+++ b/src/main/java/com/gmail/nossr50/config/skills/alchemy/PotionConfig.java
@@ -4,7 +4,6 @@ import com.gmail.nossr50.config.LegacyConfigLoader;
import com.gmail.nossr50.datatypes.skills.alchemy.AlchemyPotion;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.util.ItemUtils;
-import com.gmail.nossr50.util.PotionUtil;
import org.bukkit.ChatColor;
import org.bukkit.Color;
import org.bukkit.Material;
diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/alchemy/PotionStage.java b/src/main/java/com/gmail/nossr50/datatypes/skills/alchemy/PotionStage.java
index 64bf65009..7825c717f 100644
--- a/src/main/java/com/gmail/nossr50/datatypes/skills/alchemy/PotionStage.java
+++ b/src/main/java/com/gmail/nossr50/datatypes/skills/alchemy/PotionStage.java
@@ -1,7 +1,6 @@
package com.gmail.nossr50.datatypes.skills.alchemy;
import com.gmail.nossr50.util.PotionUtil;
-import org.bukkit.Bukkit;
import org.bukkit.inventory.meta.PotionMeta;
import org.bukkit.potion.PotionEffect;
diff --git a/src/main/java/com/gmail/nossr50/listeners/BlockListener.java b/src/main/java/com/gmail/nossr50/listeners/BlockListener.java
index 5e6ea6a78..23e17af53 100644
--- a/src/main/java/com/gmail/nossr50/listeners/BlockListener.java
+++ b/src/main/java/com/gmail/nossr50/listeners/BlockListener.java
@@ -310,7 +310,7 @@ public class BlockListener implements Listener {
// Minecraft is dumb, the events still throw when a plant "grows" higher than the max block height. Even though no new block is created
if (BlockUtils.isWithinWorldBounds(block)) {
- mcMMO.getPlaceStore().setFalse(block);
+ mcMMO.getPlaceStore().setEligible(block);
}
}
@@ -400,14 +400,14 @@ public class BlockListener implements Listener {
else if (BlockUtils.affectedBySuperBreaker(blockState)
&& (ItemUtils.isPickaxe(heldItem) || ItemUtils.isHoe(heldItem))
&& mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.MINING)
- && !mcMMO.getPlaceStore().isTrue(blockState)) {
+ && !mcMMO.getPlaceStore().isIneligible(blockState)) {
MiningManager miningManager = mcMMOPlayer.getMiningManager();
miningManager.miningBlockCheck(blockState);
}
/* WOOD CUTTING */
else if (BlockUtils.hasWoodcuttingXP(blockState) && ItemUtils.isAxe(heldItem)
- && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.WOODCUTTING) && !mcMMO.getPlaceStore().isTrue(blockState)) {
+ && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.WOODCUTTING) && !mcMMO.getPlaceStore().isIneligible(blockState)) {
WoodcuttingManager woodcuttingManager = mcMMOPlayer.getWoodcuttingManager();
if (woodcuttingManager.canUseTreeFeller(heldItem)) {
woodcuttingManager.processTreeFeller(blockState);
@@ -422,7 +422,7 @@ public class BlockListener implements Listener {
}
/* EXCAVATION */
- else if (BlockUtils.affectedByGigaDrillBreaker(blockState) && ItemUtils.isShovel(heldItem) && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.EXCAVATION) && !mcMMO.getPlaceStore().isTrue(blockState)) {
+ else if (BlockUtils.affectedByGigaDrillBreaker(blockState) && ItemUtils.isShovel(heldItem) && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.EXCAVATION) && !mcMMO.getPlaceStore().isIneligible(blockState)) {
ExcavationManager excavationManager = mcMMOPlayer.getExcavationManager();
excavationManager.excavationBlockCheck(blockState);
@@ -687,7 +687,7 @@ public class BlockListener implements Listener {
if (UserManager.getPlayer(player).isDebugMode())
{
- if (mcMMO.getPlaceStore().isTrue(blockState))
+ if (mcMMO.getPlaceStore().isIneligible(blockState))
player.sendMessage("[mcMMO DEBUG] This block is not natural and does not reward treasures/XP");
else
{
diff --git a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java
index 5e3002a15..fb36629de 100644
--- a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java
+++ b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java
@@ -44,7 +44,6 @@ import org.bukkit.metadata.FixedMetadataValue;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.projectiles.ProjectileSource;
-import org.jetbrains.annotations.NotNull;
import static com.gmail.nossr50.util.MobMetadataUtils.*;
@@ -207,8 +206,8 @@ public class EntityListener implements Listener {
if (entity instanceof FallingBlock || entity instanceof Enderman) {
boolean isTracked = entity.hasMetadata(MetadataConstants.METADATA_KEY_TRAVELING_BLOCK);
- if (mcMMO.getPlaceStore().isTrue(block) && !isTracked) {
- mcMMO.getPlaceStore().setFalse(block);
+ if (mcMMO.getPlaceStore().isIneligible(block) && !isTracked) {
+ mcMMO.getPlaceStore().setEligible(block);
entity.setMetadata(MetadataConstants.METADATA_KEY_TRAVELING_BLOCK, MetadataConstants.MCMMO_METADATA_VALUE);
TravelingBlockMetaCleanup metaCleanupTask = new TravelingBlockMetaCleanup(entity, pluginRef);
@@ -222,8 +221,8 @@ public class EntityListener implements Listener {
//Redstone ore fire this event and should be ignored
}
else {
- if (mcMMO.getPlaceStore().isTrue(block)) {
- mcMMO.getPlaceStore().setFalse(block);
+ if (mcMMO.getPlaceStore().isIneligible(block)) {
+ mcMMO.getPlaceStore().setEligible(block);
}
}
}
diff --git a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java
index 28a321f88..e9b8daf62 100644
--- a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java
+++ b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java
@@ -852,7 +852,7 @@ public class PlayerListener implements Listener {
case "NETHER_WART_BLOCK":
case "POTATO":
case "MANGROVE_PROPAGULE":
- mcMMO.getPlaceStore().setFalse(blockState);
+ mcMMO.getPlaceStore().setEligible(blockState);
break;
}
}
diff --git a/src/main/java/com/gmail/nossr50/listeners/WorldListener.java b/src/main/java/com/gmail/nossr50/listeners/WorldListener.java
index aedecfea1..010185e9e 100644
--- a/src/main/java/com/gmail/nossr50/listeners/WorldListener.java
+++ b/src/main/java/com/gmail/nossr50/listeners/WorldListener.java
@@ -32,7 +32,7 @@ public class WorldListener implements Listener {
// Using 50 ms later as I do not know of a way to run one tick later (safely)
plugin.getFoliaLib().getImpl().runLater(() -> {
for (BlockState blockState : event.getBlocks()) {
- mcMMO.getPlaceStore().setFalse(blockState);
+ mcMMO.getPlaceStore().setEligible(blockState);
}
}, 1);
}
diff --git a/src/main/java/com/gmail/nossr50/runnables/PistonTrackerTask.java b/src/main/java/com/gmail/nossr50/runnables/PistonTrackerTask.java
deleted file mode 100644
index d4e69c5bc..000000000
--- a/src/main/java/com/gmail/nossr50/runnables/PistonTrackerTask.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.gmail.nossr50.runnables;
-
-import com.gmail.nossr50.mcMMO;
-import com.gmail.nossr50.util.BlockUtils;
-import com.gmail.nossr50.util.CancellableRunnable;
-import com.gmail.nossr50.util.MetadataConstants;
-import org.bukkit.block.Block;
-import org.bukkit.block.BlockFace;
-
-import java.util.List;
-
-public class PistonTrackerTask extends CancellableRunnable {
- private final List blocks;
- private final BlockFace direction;
- private final Block futureEmptyBlock;
-
- public PistonTrackerTask(List blocks, BlockFace direction, Block futureEmptyBlock) {
- this.blocks = blocks;
- this.direction = direction;
- this.futureEmptyBlock = futureEmptyBlock;
- }
-
- @Override
- public void run() {
- // Check to see if futureEmptyBlock is empty - if it isn't; the blocks didn't move
- if (!BlockUtils.isPistonPiece(futureEmptyBlock.getState())) {
- return;
- }
-
- if (mcMMO.getPlaceStore().isTrue(futureEmptyBlock)) {
- mcMMO.getPlaceStore().setFalse(futureEmptyBlock);
- }
-
- for (Block b : blocks) {
- Block nextBlock = b.getRelative(direction);
-
- if (nextBlock.hasMetadata(MetadataConstants.METADATA_KEY_PISTON_TRACKING)) {
- BlockUtils.setUnnaturalBlock(nextBlock);
- nextBlock.removeMetadata(MetadataConstants.METADATA_KEY_PISTON_TRACKING, mcMMO.p);
- }
- else if (mcMMO.getPlaceStore().isTrue(nextBlock)) {
- // Block doesn't have metadatakey but isTrue - set it to false
- mcMMO.getPlaceStore().setFalse(nextBlock);
- }
- }
- }
-}
diff --git a/src/main/java/com/gmail/nossr50/runnables/StickyPistonTrackerTask.java b/src/main/java/com/gmail/nossr50/runnables/StickyPistonTrackerTask.java
index d8f52ae30..02590c53f 100644
--- a/src/main/java/com/gmail/nossr50/runnables/StickyPistonTrackerTask.java
+++ b/src/main/java/com/gmail/nossr50/runnables/StickyPistonTrackerTask.java
@@ -19,7 +19,7 @@ public class StickyPistonTrackerTask extends CancellableRunnable {
@Override
public void run() {
- if (!mcMMO.getPlaceStore().isTrue(movedBlock.getRelative(direction))) {
+ if (!mcMMO.getPlaceStore().isIneligible(movedBlock.getRelative(direction))) {
return;
}
@@ -29,7 +29,7 @@ public class StickyPistonTrackerTask extends CancellableRunnable {
}
// The sticky piston actually pulled the block so move the PlaceStore data
- mcMMO.getPlaceStore().setFalse(movedBlock.getRelative(direction));
+ mcMMO.getPlaceStore().setEligible(movedBlock.getRelative(direction));
BlockUtils.setUnnaturalBlock(movedBlock);
}
}
diff --git a/src/main/java/com/gmail/nossr50/runnables/skills/AlchemyBrewCheckTask.java b/src/main/java/com/gmail/nossr50/runnables/skills/AlchemyBrewCheckTask.java
index 11618147e..640b498e8 100644
--- a/src/main/java/com/gmail/nossr50/runnables/skills/AlchemyBrewCheckTask.java
+++ b/src/main/java/com/gmail/nossr50/runnables/skills/AlchemyBrewCheckTask.java
@@ -2,7 +2,6 @@ package com.gmail.nossr50.runnables.skills;
import com.gmail.nossr50.datatypes.player.McMMOPlayer;
import com.gmail.nossr50.skills.alchemy.Alchemy;
-import com.gmail.nossr50.skills.alchemy.AlchemyPotionBrewer;
import com.gmail.nossr50.util.CancellableRunnable;
import com.gmail.nossr50.util.ContainerMetadataUtils;
import com.gmail.nossr50.util.player.UserManager;
@@ -17,7 +16,6 @@ import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import static com.gmail.nossr50.skills.alchemy.AlchemyPotionBrewer.isValidBrew;
-import static com.gmail.nossr50.util.EventUtils.getMcMMOPlayer;
public class AlchemyBrewCheckTask extends CancellableRunnable {
private final BrewingStand brewingStand;
diff --git a/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java b/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java
index b60c33b7f..a93f6b3f7 100644
--- a/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java
+++ b/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java
@@ -282,7 +282,7 @@ public class HerbalismManager extends SkillManager {
if (brokenPlant.getLocation().equals(originalBreak.getBlock().getLocation())) {
//If its the same block as the original, we are going to directly check it for being a valid XP gain and add it to the nonChorusBlocks list even if its a chorus block
//This stops a delay from happening when bringing up the XP bar for chorus trees
- if (!mcMMO.getPlaceStore().isTrue(originalBreak)) {
+ if (!mcMMO.getPlaceStore().isIneligible(originalBreak)) {
//Even if its a chorus block, the original break will be moved to nonChorusBlocks for immediate XP rewards
noDelayPlantBlocks.add(brokenPlant);
} else {
@@ -335,7 +335,7 @@ public class HerbalismManager extends SkillManager {
BlockData plantData = brokenPlantState.getBlockData();
//Check for double drops
- if (!mcMMO.getPlaceStore().isTrue(brokenPlant)) {
+ if (!mcMMO.getPlaceStore().isIneligible(brokenPlant)) {
/*
*
@@ -413,7 +413,7 @@ public class HerbalismManager extends SkillManager {
BlockState brokenBlockNewState = brokenPlantBlock.getState();
BlockData plantData = brokenBlockNewState.getBlockData();
- if (mcMMO.getPlaceStore().isTrue(brokenBlockNewState)) {
+ if (mcMMO.getPlaceStore().isIneligible(brokenBlockNewState)) {
/*
*
* Unnatural Blocks
@@ -427,7 +427,7 @@ public class HerbalismManager extends SkillManager {
}
//Mark it as natural again as it is being broken
- mcMMO.getPlaceStore().setFalse(brokenBlockNewState);
+ mcMMO.getPlaceStore().setEligible(brokenBlockNewState);
} else {
/*
*
@@ -489,9 +489,9 @@ public class HerbalismManager extends SkillManager {
continue;
}
- if (mcMMO.getPlaceStore().isTrue(brokenBlockNewState)) {
+ if (mcMMO.getPlaceStore().isIneligible(brokenBlockNewState)) {
//Mark it as natural again as it is being broken
- mcMMO.getPlaceStore().setFalse(brokenBlockNewState);
+ mcMMO.getPlaceStore().setEligible(brokenBlockNewState);
} else {
//TODO: Do we care about chorus flower age?
//Calculate XP for the old type
diff --git a/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java b/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java
index 1d8738de2..a4c8eade0 100644
--- a/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java
+++ b/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java
@@ -181,7 +181,7 @@ public class MiningManager extends SkillManager {
//Containers usually have 0 XP unless someone edited their config in a very strange way
if (ExperienceConfig.getInstance().getXp(PrimarySkillType.MINING, targetBlock) != 0
&& !(targetBlock instanceof Container)
- && !mcMMO.getPlaceStore().isTrue(targetBlock)) {
+ && !mcMMO.getPlaceStore().isIneligible(targetBlock)) {
if (BlockUtils.isOre(blockState)) {
ores.add(blockState);
} else {
@@ -216,7 +216,7 @@ public class MiningManager extends SkillManager {
Misc.spawnItem(getPlayer(), Misc.getBlockCenter(blockState), new ItemStack(blockState.getType()), ItemSpawnReason.BLAST_MINING_ORES); // Initial block that would have been dropped
- if (mcMMO.p.getAdvancedConfig().isBlastMiningBonusDropsEnabled() && !mcMMO.getPlaceStore().isTrue(blockState)) {
+ if (mcMMO.p.getAdvancedConfig().isBlastMiningBonusDropsEnabled() && !mcMMO.getPlaceStore().isIneligible(blockState)) {
for (int i = 1; i < dropMultiplier; i++) {
// Bukkit.broadcastMessage("Bonus Drop on Ore: "+blockState.getType().toString());
Misc.spawnItem(getPlayer(), Misc.getBlockCenter(blockState), new ItemStack(blockState.getType()), ItemSpawnReason.BLAST_MINING_ORES_BONUS_DROP); // Initial block that would have been dropped
diff --git a/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java b/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java
index 877f0cc24..b68cedad7 100644
--- a/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java
+++ b/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java
@@ -113,7 +113,7 @@ public class WoodcuttingManager extends SkillManager {
}
public void processWoodcuttingBlockXP(@NotNull BlockState blockState) {
- if (mcMMO.getPlaceStore().isTrue(blockState))
+ if (mcMMO.getPlaceStore().isIneligible(blockState))
return;
int xp = getExperienceFromLog(blockState);
@@ -269,7 +269,7 @@ public class WoodcuttingManager extends SkillManager {
* in treeFellerBlocks.
*/
private boolean processTreeFellerTargetBlock(@NotNull BlockState blockState, @NotNull List futureCenterBlocks, @NotNull Set treeFellerBlocks) {
- if (treeFellerBlocks.contains(blockState) || mcMMO.getPlaceStore().isTrue(blockState)) {
+ if (treeFellerBlocks.contains(blockState) || mcMMO.getPlaceStore().isIneligible(blockState)) {
return false;
}
@@ -373,7 +373,7 @@ public class WoodcuttingManager extends SkillManager {
* @return Amount of experience
*/
private static int processTreeFellerXPGains(BlockState blockState, int woodCount) {
- if (mcMMO.getPlaceStore().isTrue(blockState))
+ if (mcMMO.getPlaceStore().isIneligible(blockState))
return 0;
int rawXP = ExperienceConfig.getInstance().getXp(PrimarySkillType.WOODCUTTING, blockState.getType());
diff --git a/src/main/java/com/gmail/nossr50/util/BlockUtils.java b/src/main/java/com/gmail/nossr50/util/BlockUtils.java
index 56d1d698d..59245fc9d 100644
--- a/src/main/java/com/gmail/nossr50/util/BlockUtils.java
+++ b/src/main/java/com/gmail/nossr50/util/BlockUtils.java
@@ -65,7 +65,7 @@ public final class BlockUtils {
* @param block target block
*/
public static void setUnnaturalBlock(@NotNull Block block) {
- mcMMO.getPlaceStore().setTrue(block);
+ mcMMO.getPlaceStore().setIneligible(block);
// Failsafe against lingering metadata
if (block.hasMetadata(MetadataConstants.METADATA_KEY_BONUS_DROPS))
@@ -82,7 +82,7 @@ public final class BlockUtils {
block.removeMetadata(MetadataConstants.METADATA_KEY_REPLANT, mcMMO.p);
}
- mcMMO.getPlaceStore().setFalse(block);
+ mcMMO.getPlaceStore().setEligible(block);
}
/**
diff --git a/src/main/java/com/gmail/nossr50/util/TransientEntityTracker.java b/src/main/java/com/gmail/nossr50/util/TransientEntityTracker.java
index ba410788d..c463077db 100644
--- a/src/main/java/com/gmail/nossr50/util/TransientEntityTracker.java
+++ b/src/main/java/com/gmail/nossr50/util/TransientEntityTracker.java
@@ -1,7 +1,6 @@
package com.gmail.nossr50.util;
import com.gmail.nossr50.datatypes.skills.subskills.taming.CallOfTheWildType;
-import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.skills.taming.TrackedTamingEntity;
import com.gmail.nossr50.util.player.NotificationManager;
import com.gmail.nossr50.util.skills.ParticleEffectUtils;
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 5f38022d5..d572ec518 100644
--- a/src/main/java/com/gmail/nossr50/util/blockmeta/HashChunkManager.java
+++ b/src/main/java/com/gmail/nossr50/util/blockmeta/HashChunkManager.java
@@ -152,7 +152,7 @@ public class HashChunkManager implements ChunkManager {
}
}
- private synchronized boolean isTrue(int x, int y, int z, @NotNull World world) {
+ private synchronized boolean isIneligible(int x, int y, int z, @NotNull World world) {
CoordinateKey chunkKey = blockCoordinateToChunkKey(world.getUID(), x, y, z);
// Get chunk, load from file if necessary
@@ -178,32 +178,42 @@ public class HashChunkManager implements ChunkManager {
}
@Override
- public synchronized boolean isTrue(@NotNull Block block) {
- return isTrue(block.getX(), block.getY(), block.getZ(), block.getWorld());
+ public synchronized boolean isIneligible(@NotNull Block block) {
+ return isIneligible(block.getX(), block.getY(), block.getZ(), block.getWorld());
}
@Override
- public synchronized boolean isTrue(@NotNull BlockState blockState) {
- return isTrue(blockState.getX(), blockState.getY(), blockState.getZ(), blockState.getWorld());
+ public synchronized boolean isIneligible(@NotNull BlockState blockState) {
+ return isIneligible(blockState.getX(), blockState.getY(), blockState.getZ(), blockState.getWorld());
}
@Override
- public synchronized void setTrue(@NotNull Block block) {
+ public synchronized boolean isEligible(@NotNull Block block) {
+ return !isIneligible(block);
+ }
+
+ @Override
+ public synchronized boolean isEligible(@NotNull BlockState blockState) {
+ return !isIneligible(blockState);
+ }
+
+ @Override
+ public synchronized void setIneligible(@NotNull Block block) {
set(block.getX(), block.getY(), block.getZ(), block.getWorld(), true);
}
@Override
- public synchronized void setTrue(@NotNull BlockState blockState) {
+ public synchronized void setIneligible(@NotNull BlockState blockState) {
set(blockState.getX(), blockState.getY(), blockState.getZ(), blockState.getWorld(), true);
}
@Override
- public synchronized void setFalse(@NotNull Block block) {
+ public synchronized void setEligible(@NotNull Block block) {
set(block.getX(), block.getY(), block.getZ(), block.getWorld(), false);
}
@Override
- public synchronized void setFalse(@NotNull BlockState blockState) {
+ public synchronized void setEligible(@NotNull BlockState blockState) {
set(blockState.getX(), blockState.getY(), blockState.getZ(), blockState.getWorld(), false);
}
diff --git a/src/main/java/com/gmail/nossr50/util/blockmeta/NullChunkManager.java b/src/main/java/com/gmail/nossr50/util/blockmeta/NullChunkManager.java
index 203376780..bc700b6e4 100644
--- a/src/main/java/com/gmail/nossr50/util/blockmeta/NullChunkManager.java
+++ b/src/main/java/com/gmail/nossr50/util/blockmeta/NullChunkManager.java
@@ -17,24 +17,34 @@ public class NullChunkManager implements ChunkManager {
public void unloadWorld(@NotNull World world) {}
@Override
- public boolean isTrue(@NotNull Block block) {
+ public boolean isIneligible(@NotNull Block block) {
return false;
}
@Override
- public boolean isTrue(@NotNull BlockState blockState) {
+ public boolean isIneligible(@NotNull BlockState blockState) {
return false;
}
@Override
- public void setTrue(@NotNull Block block) {}
+ public boolean isEligible(@NotNull Block block) {
+ return false;
+ }
@Override
- public void setTrue(@NotNull BlockState blockState) {}
+ public boolean isEligible(@NotNull BlockState blockState) {
+ return false;
+ }
@Override
- public void setFalse(@NotNull Block block) {}
+ public void setIneligible(@NotNull Block block) {}
@Override
- public void setFalse(@NotNull BlockState blockState) {}
+ public void setIneligible(@NotNull BlockState blockState) {}
+
+ @Override
+ public void setEligible(@NotNull Block block) {}
+
+ @Override
+ public void setEligible(@NotNull BlockState blockState) {}
}
diff --git a/src/main/java/com/gmail/nossr50/util/blockmeta/UserBlockTracker.java b/src/main/java/com/gmail/nossr50/util/blockmeta/UserBlockTracker.java
index e5428b0c1..501b16cfa 100644
--- a/src/main/java/com/gmail/nossr50/util/blockmeta/UserBlockTracker.java
+++ b/src/main/java/com/gmail/nossr50/util/blockmeta/UserBlockTracker.java
@@ -11,46 +11,136 @@ import org.jetbrains.annotations.NotNull;
*/
public interface UserBlockTracker {
/**
- * Check to see if a given block location is set to true
+ * Check to see if a given {@link Block} is ineligible for rewards.
+ * This is a location-based lookup, and the other properties of the {@link Block} do not matter.
*
- * @param block Block location to check
- * @return true if the given block location is set to true, false if otherwise
+ * @param block Block to check
+ * @return true if the given block should not give rewards, false if otherwise
*/
- boolean isTrue(@NotNull Block block);
+ boolean isIneligible(@NotNull Block block);
/**
- * Check to see if a given BlockState location is set to true
+ * Check to see if a given {@link Block} is eligible for rewards.
+ * This is a location-based lookup, and the other properties of the {@link Block} do not matter.
+ *
+ * @param block Block to check
+ * @return true if the given block should give rewards, false if otherwise
+ */
+ boolean isEligible(@NotNull Block block);
+
+ /**
+ * Check to see if a given {@link BlockState} is eligible for rewards.
+ * This is a location-based lookup, and the other properties of the {@link BlockState} do not matter.
*
* @param blockState BlockState to check
* @return true if the given BlockState location is set to true, false if otherwise
*/
- boolean isTrue(@NotNull BlockState blockState);
+ boolean isEligible(@NotNull BlockState blockState);
/**
- * Set a given block location to true
+ * Check to see if a given {@link BlockState} is ineligible for rewards.
+ * This is a location-based lookup, and the other properties of the {@link BlockState} do not matter.
*
- * @param block Block location to set
+ * @param blockState BlockState to check
+ * @return true if the given BlockState location is set to true, false if otherwise
*/
- void setTrue(@NotNull Block block);
+ boolean isIneligible(@NotNull BlockState blockState);
+
+ /**
+ * Set a given {@link Block} as ineligible for rewards.
+ * This is a location-based lookup, and the other properties of the {@link Block} do not matter.
+ *
+ * @param block block whose location to set as ineligible
+ */
+ void setIneligible(@NotNull Block block);
/**
* Set a given BlockState location to true
*
* @param blockState BlockState location to set
*/
- void setTrue(@NotNull BlockState blockState);
+ void setIneligible(@NotNull BlockState blockState);
/**
- * Set a given block location to false
+ * Set a given {@link Block} as eligible for rewards.
+ * This is a location-based lookup, and the other properties of the {@link Block} do not matter.
*
- * @param block Block location to set
+ * @param block block whose location to set as eligible
*/
- void setFalse(@NotNull Block block);
+ void setEligible(@NotNull Block block);
/**
* Set a given BlockState location to false
*
* @param blockState BlockState location to set
*/
- void setFalse(@NotNull BlockState blockState);
+ void setEligible(@NotNull BlockState blockState);
+
+ /**
+ * Check to see if a given block location is set to true
+ *
+ * @param block Block location to check
+ * @return true if the given block location is set to true, false if otherwise
+ * @deprecated Use {@link #isIneligible(Block)} instead
+ */
+ @Deprecated(since = "2.2.013")
+ default boolean isTrue(@NotNull Block block) {
+ return isIneligible(block);
+ }
+
+ /**
+ * Check to see if a given BlockState location is set to true
+ *
+ * @param blockState BlockState to check
+ * @return true if the given BlockState location is set to true, false if otherwise
+ * @deprecated Use {@link #isIneligible(BlockState)} instead
+ */
+ @Deprecated(since = "2.2.013")
+ default boolean isTrue(@NotNull BlockState blockState) {
+ return isIneligible(blockState);
+ }
+
+ /**
+ * Set a given block location to true
+ *
+ * @param block Block location to set
+ * @deprecated Use {@link #setIneligible(Block)} instead
+ */
+ @Deprecated(since = "2.2.013")
+ default void setTrue(@NotNull Block block) {
+ setIneligible(block);
+ }
+
+ /**
+ * Set a given BlockState location to true
+ *
+ * @param blockState BlockState location to set
+ * @deprecated Use {@link #setIneligible(BlockState)} instead
+ */
+ @Deprecated(since = "2.2.013")
+ default void setTrue(@NotNull BlockState blockState) {
+ setIneligible(blockState);
+ }
+
+ /**
+ * Set a given block location to false
+ *
+ * @param block Block location to set
+ * @deprecated Use {@link #setEligible(Block)} instead
+ */
+ @Deprecated(since = "2.2.013")
+ default void setFalse(@NotNull Block block) {
+ setEligible(block);
+ }
+
+ /**
+ * Set a given BlockState location to false
+ *
+ * @param blockState BlockState location to set
+ * @deprecated Use {@link #setEligible(BlockState)} instead
+ */
+ @Deprecated(since = "2.2.013")
+ default void setFalse(@NotNull BlockState blockState) {
+ setEligible(blockState);
+ }
}
diff --git a/src/test/java/com/gmail/nossr50/util/PotionEffectUtilTest.java b/src/test/java/com/gmail/nossr50/util/PotionEffectUtilTest.java
index 1618988e9..c8125b763 100644
--- a/src/test/java/com/gmail/nossr50/util/PotionEffectUtilTest.java
+++ b/src/test/java/com/gmail/nossr50/util/PotionEffectUtilTest.java
@@ -13,9 +13,8 @@ import org.mockito.MockedStatic;
import static com.gmail.nossr50.util.PotionEffectUtil.getNauseaPotionEffectType;
import static java.util.logging.Logger.getLogger;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.Mockito.*;
-import static org.mockito.Mockito.when;
class PotionEffectUtilTest {
private MockedStatic mockedStaticMcMMO;
diff --git a/src/test/java/com/gmail/nossr50/util/blockmeta/BitSetChunkStoreTest.java b/src/test/java/com/gmail/nossr50/util/blockmeta/BitSetChunkStoreTest.java
new file mode 100644
index 000000000..9e266d8d6
--- /dev/null
+++ b/src/test/java/com/gmail/nossr50/util/blockmeta/BitSetChunkStoreTest.java
@@ -0,0 +1,121 @@
+package com.gmail.nossr50.util.blockmeta;
+
+import com.gmail.nossr50.mcMMO;
+import com.google.common.io.Files;
+import org.bukkit.Bukkit;
+import org.bukkit.World;
+import org.junit.jupiter.api.*;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.util.UUID;
+
+import static com.gmail.nossr50.util.blockmeta.BlockStoreTestUtils.*;
+import static com.gmail.nossr50.util.blockmeta.UserBlockTrackerTest.recursiveDelete;
+import static org.bukkit.Bukkit.getWorld;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.when;
+
+class BitSetChunkStoreTest {
+ private static File tempDir;
+
+ @BeforeAll
+ public static void setUpClass() {
+ tempDir = Files.createTempDir();
+ }
+
+ @AfterAll
+ public static void tearDownClass() {
+ recursiveDelete(tempDir);
+ }
+
+ private World mockWorld;
+
+ private MockedStatic bukkitMock;
+ private MockedStatic mcMMOMock;
+
+ @BeforeEach
+ void setUpMock() {
+ UUID worldUUID = UUID.randomUUID();
+ mockWorld = Mockito.mock(World.class);
+ when(mockWorld.getUID()).thenReturn(worldUUID);
+ when(mockWorld.getMaxHeight()).thenReturn(256);
+ when(mockWorld.getWorldFolder()).thenReturn(tempDir);
+
+ bukkitMock = mockStatic(Bukkit.class);
+ bukkitMock.when(() -> getWorld(worldUUID)).thenReturn(mockWorld);
+
+ mcMMOMock = mockStatic(mcMMO.class);
+
+ when(mockWorld.getMinHeight()).thenReturn(LEGACY_WORLD_HEIGHT_MIN);
+ when(mockWorld.getMaxHeight()).thenReturn(LEGACY_WORLD_HEIGHT_MAX);
+ }
+
+ @AfterEach
+ void teardownMock() {
+ bukkitMock.close();
+ mcMMOMock.close();
+ }
+
+ @Test
+ void testSetValue() {
+ final BitSetChunkStore original = new BitSetChunkStore(mockWorld, 0, 0);
+ original.setTrue(0, 0, 0);
+ assertTrue(original.isTrue(0, 0, 0));
+ original.setFalse(0, 0, 0);
+ assertFalse(original.isTrue(0, 0, 0));
+ }
+
+ @Test
+ void testIsEmpty() {
+ final BitSetChunkStore original = new BitSetChunkStore(mockWorld, 0, 0);
+ assertTrue(original.isEmpty());
+ original.setTrue(0, 0, 0);
+ original.setFalse(0, 0, 0);
+ assertTrue(original.isEmpty());
+ }
+
+ @Test
+ void testRoundTrip() throws IOException {
+ final BitSetChunkStore original = new BitSetChunkStore(mockWorld, 1, 2);
+ original.setTrue(14, 89, 12);
+ original.setTrue(14, 90, 12);
+ original.setTrue(13, 89, 12);
+ byte[] serializedBytes = serializeChunkStore(original);
+ final ChunkStore deserialized = BitSetChunkStore.Serialization.readChunkStore(new DataInputStream(new ByteArrayInputStream(serializedBytes)));
+ assertChunkStoreEquals(original, deserialized);
+ }
+
+ @Test
+ void testNegativeWorldMin() throws IOException {
+ when(mockWorld.getMinHeight()).thenReturn(-64);
+
+ final BitSetChunkStore original = new BitSetChunkStore(mockWorld, 1, 2);
+ original.setTrue(14, -32, 12);
+ original.setTrue(14, -64, 12);
+ original.setTrue(13, -63, 12);
+ byte[] serializedBytes = serializeChunkStore(original);
+ final ChunkStore deserialized = BitSetChunkStore.Serialization.readChunkStore(new DataInputStream(new ByteArrayInputStream(serializedBytes)));
+ assertChunkStoreEquals(original, deserialized);
+ }
+
+ @Test
+ void testNegativeWorldMinUpgrade() throws IOException {
+ final BitSetChunkStore original = new BitSetChunkStore(mockWorld, 1, 2);
+ original.setTrue(14, 1, 12);
+ original.setTrue(14, 2, 12);
+ original.setTrue(13, 3, 12);
+ byte[] serializedBytes = serializeChunkStore(original);
+
+ when(mockWorld.getMinHeight()).thenReturn(-64);
+ final ChunkStore deserialized = BitSetChunkStore.Serialization.readChunkStore(new DataInputStream(new ByteArrayInputStream(serializedBytes)));
+ assert deserialized != null;
+ assertEqualIgnoreMinMax(original, deserialized);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/gmail/nossr50/util/blockmeta/BlockStoreTestUtils.java b/src/test/java/com/gmail/nossr50/util/blockmeta/BlockStoreTestUtils.java
new file mode 100644
index 000000000..709a7b57f
--- /dev/null
+++ b/src/test/java/com/gmail/nossr50/util/blockmeta/BlockStoreTestUtils.java
@@ -0,0 +1,49 @@
+package com.gmail.nossr50.util.blockmeta;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class BlockStoreTestUtils {
+ public static final int LEGACY_WORLD_HEIGHT_MAX = 256;
+ public static final int LEGACY_WORLD_HEIGHT_MIN = 0;
+
+ /**
+ * Asserts that the two ChunkStores are equal.
+ * @param expected The expected ChunkStore
+ * @param actual The actual ChunkStore
+ */
+ static void assertChunkStoreEquals(ChunkStore expected, ChunkStore actual) {
+ assertEquals(expected.getChunkMin(), actual.getChunkMin());
+ assertEquals(expected.getChunkMax(), actual.getChunkMax());
+ assertEqualIgnoreMinMax(expected, actual);
+ }
+
+ static byte[] serializeChunkStore(@NotNull ChunkStore chunkStore) throws IOException {
+ final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ if (chunkStore instanceof BitSetChunkStore)
+ BitSetChunkStore.Serialization.writeChunkStore(new DataOutputStream(byteArrayOutputStream), chunkStore);
+ else
+ new UnitTestObjectOutputStream(byteArrayOutputStream).writeObject(chunkStore); // Serializes the class as if
+ // it were the old
+ // PrimitiveChunkStore
+ return byteArrayOutputStream.toByteArray();
+ }
+
+ static void assertEqualIgnoreMinMax(ChunkStore expected, ChunkStore actual) {
+ assertEquals(expected.getChunkX(), actual.getChunkX());
+ assertEquals(expected.getChunkZ(), actual.getChunkZ());
+ assertEquals(expected.getWorldId(), actual.getWorldId());
+ for (int y = Math.min(actual.getChunkMin(), expected.getChunkMin()); y < Math.max(actual.getChunkMax(), expected.getChunkMax()); y++) {
+ if (expected.getChunkMin() > y || actual.getChunkMin() > y || expected.getChunkMax() <= y || actual.getChunkMax() <= y)
+ continue; // Ignore
+ for (int x = 0; x < 16; x++)
+ for (int z = 0; z < 16; z++)
+ assertEquals(expected.isTrue(x, y, z), actual.isTrue(x, y, z));
+ }
+ }
+}
diff --git a/src/test/java/com/gmail/nossr50/util/blockmeta/ChunkStoreTest.java b/src/test/java/com/gmail/nossr50/util/blockmeta/ChunkStoreTest.java
index 969de6ec4..f7f369076 100644
--- a/src/test/java/com/gmail/nossr50/util/blockmeta/ChunkStoreTest.java
+++ b/src/test/java/com/gmail/nossr50/util/blockmeta/ChunkStoreTest.java
@@ -1,13 +1,9 @@
package com.gmail.nossr50.util.blockmeta;
-
import com.gmail.nossr50.mcMMO;
-import com.gmail.nossr50.util.BlockUtils;
import com.google.common.io.Files;
import org.bukkit.Bukkit;
import org.bukkit.World;
-import org.bukkit.block.Block;
-import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.*;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
@@ -15,14 +11,13 @@ import org.mockito.Mockito;
import java.io.*;
import java.util.UUID;
-/**
- * Could be a lot better. But some tests are better than none! Tests the major things, still kinda unit-testy. Verifies
- * that the serialization isn't completely broken.
- */
-class ChunkStoreTest {
+import static com.gmail.nossr50.util.blockmeta.BlockStoreTestUtils.*;
+import static com.gmail.nossr50.util.blockmeta.UserBlockTrackerTest.recursiveDelete;
+import static org.bukkit.Bukkit.getWorld;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.when;
- public static final int LEGACY_WORLD_HEIGHT_MAX = 256;
- public static final int LEGACY_WORLD_HEIGHT_MIN = 0;
+class ChunkStoreTest {
private static File tempDir;
@BeforeAll
@@ -44,151 +39,39 @@ class ChunkStoreTest {
void setUpMock() {
UUID worldUUID = UUID.randomUUID();
mockWorld = Mockito.mock(World.class);
- Mockito.when(mockWorld.getUID()).thenReturn(worldUUID);
- Mockito.when(mockWorld.getMaxHeight()).thenReturn(256);
- Mockito.when(mockWorld.getWorldFolder()).thenReturn(tempDir);
+ when(mockWorld.getUID()).thenReturn(worldUUID);
+ when(mockWorld.getMaxHeight()).thenReturn(256);
+ when(mockWorld.getWorldFolder()).thenReturn(tempDir);
- bukkitMock = Mockito.mockStatic(Bukkit.class);
- bukkitMock.when(() -> Bukkit.getWorld(worldUUID)).thenReturn(mockWorld);
+ bukkitMock = mockStatic(Bukkit.class);
+ bukkitMock.when(() -> getWorld(worldUUID)).thenReturn(mockWorld);
- mcMMOMock = Mockito.mockStatic(mcMMO.class);
+ mcMMOMock = mockStatic(mcMMO.class);
- Mockito.when(mockWorld.getMinHeight()).thenReturn(LEGACY_WORLD_HEIGHT_MIN);
- Mockito.when(mockWorld.getMaxHeight()).thenReturn(LEGACY_WORLD_HEIGHT_MAX);
+ when(mockWorld.getMinHeight()).thenReturn(LEGACY_WORLD_HEIGHT_MIN);
+ when(mockWorld.getMaxHeight()).thenReturn(LEGACY_WORLD_HEIGHT_MAX);
}
-
+
@AfterEach
void teardownMock() {
bukkitMock.close();
mcMMOMock.close();
}
- @Test
- void testIndexOutOfBounds() {
- Mockito.when(mockWorld.getMinHeight()).thenReturn(-64);
- HashChunkManager hashChunkManager = new HashChunkManager();
-
- // Top Block
- Block illegalHeightBlock = initMockBlock(1337, 256, -1337);
- Assertions.assertFalse(hashChunkManager.isTrue(illegalHeightBlock));
- Assertions.assertThrows(IndexOutOfBoundsException.class, () -> hashChunkManager.setTrue(illegalHeightBlock));
- }
-
- @Test
- void testSetTrue() {
- Mockito.when(mockWorld.getMinHeight()).thenReturn(-64);
- HashChunkManager hashChunkManager = new HashChunkManager();
- int radius = 2; // Could be anything but drastically changes test time
-
- for (int x = -radius; x <= radius; x++) {
- for (int y = mockWorld.getMinHeight(); y < mockWorld.getMaxHeight(); y++) {
- for (int z = -radius; z <= radius; z++) {
- Block testBlock = initMockBlock(x, y, z);
-
- hashChunkManager.setTrue(testBlock);
- Assertions.assertTrue(hashChunkManager.isTrue(testBlock));
- hashChunkManager.setFalse(testBlock);
- Assertions.assertFalse(hashChunkManager.isTrue(testBlock));
- }
- }
- }
-
- // Bot Block
- Block bottomBlock = initMockBlock(1337, 0, -1337);
- Assertions.assertFalse(hashChunkManager.isTrue(bottomBlock));
-
- Assertions.assertTrue(BlockUtils.isWithinWorldBounds(bottomBlock));
- hashChunkManager.setTrue(bottomBlock);
- Assertions.assertTrue(hashChunkManager.isTrue(bottomBlock));
-
- // Top Block
- Block topBlock = initMockBlock(1337, 255, -1337);
- Assertions.assertFalse(hashChunkManager.isTrue(topBlock));
-
- Assertions.assertTrue(BlockUtils.isWithinWorldBounds(topBlock));
- hashChunkManager.setTrue(topBlock);
- Assertions.assertTrue(hashChunkManager.isTrue(topBlock));
- }
-
- @Test
- void testSetValue() {
- BitSetChunkStore original = new BitSetChunkStore(mockWorld, 0, 0);
- original.setTrue(0, 0, 0);
- Assertions.assertTrue(original.isTrue(0, 0, 0));
- original.setFalse(0, 0, 0);
- Assertions.assertFalse(original.isTrue(0, 0, 0));
- }
-
- @Test
- void testIsEmpty() {
- BitSetChunkStore original = new BitSetChunkStore(mockWorld, 0, 0);
- Assertions.assertTrue(original.isEmpty());
- original.setTrue(0, 0, 0);
- original.setFalse(0, 0, 0);
- Assertions.assertTrue(original.isEmpty());
- }
-
- @Test
- void testRoundTrip() throws IOException {
- BitSetChunkStore original = new BitSetChunkStore(mockWorld, 1, 2);
- original.setTrue(14, 89, 12);
- original.setTrue(14, 90, 12);
- original.setTrue(13, 89, 12);
- byte[] serializedBytes = serializeChunkstore(original);
- ChunkStore deserialized = BitSetChunkStore.Serialization.readChunkStore(new DataInputStream(new ByteArrayInputStream(serializedBytes)));
- assertEqual(original, deserialized);
- }
-
- @Test
- void testNegativeWorldMin() throws IOException {
- Mockito.when(mockWorld.getMinHeight()).thenReturn(-64);
-
- BitSetChunkStore original = new BitSetChunkStore(mockWorld, 1, 2);
- original.setTrue(14, -32, 12);
- original.setTrue(14, -64, 12);
- original.setTrue(13, -63, 12);
- byte[] serializedBytes = serializeChunkstore(original);
- ChunkStore deserialized = BitSetChunkStore.Serialization.readChunkStore(new DataInputStream(new ByteArrayInputStream(serializedBytes)));
- assertEqual(original, deserialized);
- }
-
- @Test
- void testNegativeWorldMinUpgrade() throws IOException {
- BitSetChunkStore original = new BitSetChunkStore(mockWorld, 1, 2);
- original.setTrue(14, 1, 12);
- original.setTrue(14, 2, 12);
- original.setTrue(13, 3, 12);
- byte[] serializedBytes = serializeChunkstore(original);
-
- Mockito.when(mockWorld.getMinHeight()).thenReturn(-64);
- ChunkStore deserialized = BitSetChunkStore.Serialization.readChunkStore(new DataInputStream(new ByteArrayInputStream(serializedBytes)));
- assert deserialized != null;
- assertEqualIgnoreMinMax(original, deserialized);
- }
-
- @Test
- void testChunkCoords() throws IOException {
- for (int x = -96; x < 0; x++) {
- int cx = x >> 4;
- int ix = Math.abs(x) % 16;
- //System.out.print(cx + ":" + ix + " ");
- }
- }
-
@Test
void testUpgrade() throws IOException {
LegacyChunkStore original = new LegacyChunkStore(mockWorld, 12, 32);
original.setTrue(14, 89, 12);
original.setTrue(14, 90, 12);
original.setTrue(13, 89, 12);
- byte[] serializedBytes = serializeChunkstore(original);
+ byte[] serializedBytes = serializeChunkStore(original);
ChunkStore deserialized = BitSetChunkStore.Serialization.readChunkStore(new DataInputStream(new ByteArrayInputStream(serializedBytes)));
assert deserialized != null;
- assertEqual(original, deserialized);
+ assertChunkStoreEquals(original, deserialized);
}
@Test
- void testSimpleRegionRoundtrip() throws IOException {
+ void testSimpleRegionRoundTrip() throws IOException {
LegacyChunkStore original = new LegacyChunkStore(mockWorld, 12, 12);
original.setTrue(14, 89, 12);
original.setTrue(14, 90, 12);
@@ -196,7 +79,7 @@ class ChunkStoreTest {
File file = new File(tempDir, "SimpleRegionRoundTrip.region");
McMMOSimpleRegionFile region = new McMMOSimpleRegionFile(file, 0, 0);
try (DataOutputStream outputStream = region.getOutputStream(12, 12)) {
- outputStream.write(serializeChunkstore(original));
+ outputStream.write(serializeChunkStore(original));
}
region.close();
region = new McMMOSimpleRegionFile(file, 0, 0);
@@ -204,229 +87,10 @@ class ChunkStoreTest {
Assertions.assertNotNull(is);
ChunkStore deserialized = BitSetChunkStore.Serialization.readChunkStore(is);
assert deserialized != null;
- assertEqual(original, deserialized);
+ assertChunkStoreEquals(original, deserialized);
}
region.close();
file.delete();
}
- @Test
- void testSimpleRegionRejectsOutOfBounds() {
- File file = new File(tempDir, "SimpleRegionRoundTrip.region");
- McMMOSimpleRegionFile region = new McMMOSimpleRegionFile(file, 0, 0);
- Assertions.assertThrows(IndexOutOfBoundsException.class, () -> region.getOutputStream(-1, 0));
- Assertions.assertThrows(IndexOutOfBoundsException.class, () -> region.getOutputStream(0, -1));
- Assertions.assertThrows(IndexOutOfBoundsException.class, () -> region.getOutputStream(32, 0));
- Assertions.assertThrows(IndexOutOfBoundsException.class, () -> region.getOutputStream(0, 32));
- region.close();
- }
-
- @Test
- void testChunkStoreRejectsOutOfBounds() {
- ChunkStore chunkStore = new BitSetChunkStore(mockWorld, 0, 0);
- Assertions.assertThrows(IndexOutOfBoundsException.class, () -> chunkStore.setTrue(-1, 0, 0));
- Assertions.assertThrows(IndexOutOfBoundsException.class, () -> chunkStore.setTrue(0, -1, 0));
- Assertions.assertThrows(IndexOutOfBoundsException.class, () -> chunkStore.setTrue(0, 0, -1));
- Assertions.assertThrows(IndexOutOfBoundsException.class, () -> chunkStore.setTrue(16, 0, 0));
- Assertions.assertThrows(IndexOutOfBoundsException.class, () -> chunkStore.setTrue(0, mockWorld.getMaxHeight(), 0));
- Assertions.assertThrows(IndexOutOfBoundsException.class, () -> chunkStore.setTrue(0, 0, 16));
- }
-
- @Test
- void testRegressionChunkMirrorBug() {
- ChunkManager chunkManager = new HashChunkManager();
- Block mockBlockA = Mockito.mock(Block.class);
- Mockito.when(mockBlockA.getX()).thenReturn(15);
- Mockito.when(mockBlockA.getZ()).thenReturn(15);
- Mockito.when(mockBlockA.getY()).thenReturn(0);
- Mockito.when(mockBlockA.getWorld()).thenReturn(mockWorld);
- Block mockBlockB = Mockito.mock(Block.class);
- Mockito.when(mockBlockB.getX()).thenReturn(-15);
- Mockito.when(mockBlockB.getZ()).thenReturn(-15);
- Mockito.when(mockBlockB.getY()).thenReturn(0);
- Mockito.when(mockBlockB.getWorld()).thenReturn(mockWorld);
-
- chunkManager.setTrue(mockBlockA);
- chunkManager.setFalse(mockBlockB);
- Assertions.assertTrue(chunkManager.isTrue(mockBlockA));
- }
-
- private void assertEqual(ChunkStore expected, ChunkStore actual) {
- Assertions.assertEquals(expected.getChunkMin(), actual.getChunkMin());
- Assertions.assertEquals(expected.getChunkMax(), actual.getChunkMax());
- assertEqualIgnoreMinMax(expected, actual);
- }
-
- private void assertEqualIgnoreMinMax(ChunkStore expected, ChunkStore actual) {
- Assertions.assertEquals(expected.getChunkX(), actual.getChunkX());
- Assertions.assertEquals(expected.getChunkZ(), actual.getChunkZ());
- Assertions.assertEquals(expected.getWorldId(), actual.getWorldId());
- for (int y = Math.min(actual.getChunkMin(), expected.getChunkMin()); y < Math.max(actual.getChunkMax(), expected.getChunkMax()); y++) {
- if (expected.getChunkMin() > y || actual.getChunkMin() > y || expected.getChunkMax() <= y || actual.getChunkMax() <= y)
- continue; // Ignore
- for (int x = 0; x < 16; x++)
- for (int z = 0; z < 16; z++)
- Assertions.assertEquals(expected.isTrue(x, y, z), actual.isTrue(x, y, z));
- }
- }
-
- private static byte[] serializeChunkstore(@NotNull ChunkStore chunkStore) throws IOException {
- ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
- if (chunkStore instanceof BitSetChunkStore)
- BitSetChunkStore.Serialization.writeChunkStore(new DataOutputStream(byteArrayOutputStream), chunkStore);
- else
- new UnitTestObjectOutputStream(byteArrayOutputStream).writeObject(chunkStore); // Serializes the class as if
- // it were the old
- // PrimitiveChunkStore
- return byteArrayOutputStream.toByteArray();
- }
-
- public static class LegacyChunkStore implements ChunkStore, Serializable {
- private static final long serialVersionUID = -1L;
- transient private boolean dirty = false;
- public boolean[][][] store;
- private static final int CURRENT_VERSION = 7;
- private static final int MAGIC_NUMBER = 0xEA5EDEBB;
- private final int cx;
- private final int cz;
- private final @NotNull UUID worldUid;
-
- public LegacyChunkStore(@NotNull World world, int cx, int cz) {
- this.cx = cx;
- this.cz = cz;
- this.worldUid = world.getUID();
- this.store = new boolean[16][16][world.getMaxHeight()];
- }
-
- @Override
- public boolean isDirty() {
- return dirty;
- }
-
- @Override
- public void setDirty(boolean dirty) {
- this.dirty = dirty;
- }
-
- @Override
- public int getChunkX() {
- return cx;
- }
-
- @Override
- public int getChunkZ() {
- return cz;
- }
-
- @Override
- public int getChunkMin() {
- return 0;
- }
-
- @Override
- public int getChunkMax() {
- return store[0][0].length;
- }
-
- @Override
- public @NotNull UUID getWorldId() {
- return worldUid;
- }
-
- @Override
- public boolean isTrue(int x, int y, int z) {
- return store[x][z][y];
- }
-
- @Override
- public void setTrue(int x, int y, int z) {
- if (y >= store[0][0].length || y < 0)
- return;
- store[x][z][y] = true;
- dirty = true;
- }
-
- @Override
- public void setFalse(int x, int y, int z) {
- if (y >= store[0][0].length || y < 0)
- return;
- store[x][z][y] = false;
- dirty = true;
- }
-
- @Override
- public void set(int x, int y, int z, boolean value) {
- if (y >= store[0][0].length || y < 0)
- return;
- store[x][z][y] = value;
- dirty = true;
- }
-
- @Override
- public boolean isEmpty() {
- for (int x = 0; x < 16; x++) {
- for (int z = 0; z < 16; z++) {
- for (int y = 0; y < store[0][0].length; y++) {
- if (store[x][z][y]) {
- return false;
- }
- }
- }
- }
- return true;
- }
-
- private void writeObject(@NotNull ObjectOutputStream out) throws IOException {
- out.writeInt(MAGIC_NUMBER);
- out.writeInt(CURRENT_VERSION);
-
- out.writeLong(worldUid.getLeastSignificantBits());
- out.writeLong(worldUid.getMostSignificantBits());
- out.writeInt(cx);
- out.writeInt(cz);
- out.writeObject(store);
-
- dirty = false;
- }
-
- private void readObject(@NotNull ObjectInputStream in) throws IOException, ClassNotFoundException {
- throw new UnsupportedOperationException();
- }
-
- }
-
- private static class UnitTestObjectOutputStream extends ObjectOutputStream {
-
- public UnitTestObjectOutputStream(@NotNull OutputStream outputStream) throws IOException {
- super(outputStream);
- }
-
- @Override
- public void writeUTF(@NotNull String str) throws IOException {
- // Pretend to be the old class
- if (str.equals(LegacyChunkStore.class.getName()))
- str = "com.gmail.nossr50.util.blockmeta.chunkmeta.PrimitiveChunkStore";
- super.writeUTF(str);
- }
-
- }
-
- @NotNull
- private Block initMockBlock(int x, int y, int z) {
- Block mockBlock = Mockito.mock(Block.class);
- Mockito.when(mockBlock.getX()).thenReturn(x);
- Mockito.when(mockBlock.getY()).thenReturn(y);
- Mockito.when(mockBlock.getZ()).thenReturn(z);
- Mockito.when(mockBlock.getWorld()).thenReturn(mockWorld);
- return mockBlock;
- }
-
- public static void recursiveDelete(@NotNull File directoryToBeDeleted) {
- if (directoryToBeDeleted.isDirectory()) {
- for (File file : directoryToBeDeleted.listFiles()) {
- recursiveDelete(file);
- }
- }
- directoryToBeDeleted.delete();
- }
-}
+}
\ No newline at end of file
diff --git a/src/test/java/com/gmail/nossr50/util/blockmeta/LegacyChunkStore.java b/src/test/java/com/gmail/nossr50/util/blockmeta/LegacyChunkStore.java
new file mode 100644
index 000000000..b21cf2594
--- /dev/null
+++ b/src/test/java/com/gmail/nossr50/util/blockmeta/LegacyChunkStore.java
@@ -0,0 +1,127 @@
+package com.gmail.nossr50.util.blockmeta;
+
+import org.bukkit.World;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.UUID;
+
+/**
+ * Used for unit testing upgrades from the old ChunkStore class.
+ */
+class LegacyChunkStore implements ChunkStore, Serializable {
+ private static final long serialVersionUID = -1L;
+ transient private boolean dirty = false;
+ public boolean[][][] store;
+ private static final int CURRENT_VERSION = 7;
+ private static final int MAGIC_NUMBER = 0xEA5EDEBB;
+ private final int cx;
+ private final int cz;
+ private final @NotNull UUID worldUid;
+
+ public LegacyChunkStore(@NotNull World world, int cx, int cz) {
+ this.cx = cx;
+ this.cz = cz;
+ this.worldUid = world.getUID();
+ this.store = new boolean[16][16][world.getMaxHeight()];
+ }
+
+ @Override
+ public boolean isDirty() {
+ return dirty;
+ }
+
+ @Override
+ public void setDirty(boolean dirty) {
+ this.dirty = dirty;
+ }
+
+ @Override
+ public int getChunkX() {
+ return cx;
+ }
+
+ @Override
+ public int getChunkZ() {
+ return cz;
+ }
+
+ @Override
+ public int getChunkMin() {
+ return 0;
+ }
+
+ @Override
+ public int getChunkMax() {
+ return store[0][0].length;
+ }
+
+ @Override
+ public @NotNull UUID getWorldId() {
+ return worldUid;
+ }
+
+ @Override
+ public boolean isTrue(int x, int y, int z) {
+ return store[x][z][y];
+ }
+
+ @Override
+ public void setTrue(int x, int y, int z) {
+ if (y >= store[0][0].length || y < 0)
+ return;
+ store[x][z][y] = true;
+ dirty = true;
+ }
+
+ @Override
+ public void setFalse(int x, int y, int z) {
+ if (y >= store[0][0].length || y < 0)
+ return;
+ store[x][z][y] = false;
+ dirty = true;
+ }
+
+ @Override
+ public void set(int x, int y, int z, boolean value) {
+ if (y >= store[0][0].length || y < 0)
+ return;
+ store[x][z][y] = value;
+ dirty = true;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ for (int x = 0; x < 16; x++) {
+ for (int z = 0; z < 16; z++) {
+ for (int y = 0; y < store[0][0].length; y++) {
+ if (store[x][z][y]) {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ private void writeObject(@NotNull ObjectOutputStream out) throws IOException {
+ out.writeInt(MAGIC_NUMBER);
+ out.writeInt(CURRENT_VERSION);
+
+ out.writeLong(worldUid.getLeastSignificantBits());
+ out.writeLong(worldUid.getMostSignificantBits());
+ out.writeInt(cx);
+ out.writeInt(cz);
+ out.writeObject(store);
+
+ dirty = false;
+ }
+
+ private void readObject(@NotNull ObjectInputStream in) throws IOException, ClassNotFoundException {
+ throw new UnsupportedOperationException();
+ }
+
+}
diff --git a/src/test/java/com/gmail/nossr50/util/blockmeta/UnitTestObjectOutputStream.java b/src/test/java/com/gmail/nossr50/util/blockmeta/UnitTestObjectOutputStream.java
new file mode 100644
index 000000000..d7eb1c140
--- /dev/null
+++ b/src/test/java/com/gmail/nossr50/util/blockmeta/UnitTestObjectOutputStream.java
@@ -0,0 +1,23 @@
+package com.gmail.nossr50.util.blockmeta;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+
+class UnitTestObjectOutputStream extends ObjectOutputStream {
+
+ public UnitTestObjectOutputStream(@NotNull OutputStream outputStream) throws IOException {
+ super(outputStream);
+ }
+
+ @Override
+ public void writeUTF(@NotNull String str) throws IOException {
+ // Pretend to be the old class
+ if (str.equals(LegacyChunkStore.class.getName()))
+ str = "com.gmail.nossr50.util.blockmeta.chunkmeta.PrimitiveChunkStore";
+ super.writeUTF(str);
+ }
+
+}
diff --git a/src/test/java/com/gmail/nossr50/util/blockmeta/UserBlockTrackerTest.java b/src/test/java/com/gmail/nossr50/util/blockmeta/UserBlockTrackerTest.java
new file mode 100644
index 000000000..89a2f63ff
--- /dev/null
+++ b/src/test/java/com/gmail/nossr50/util/blockmeta/UserBlockTrackerTest.java
@@ -0,0 +1,192 @@
+package com.gmail.nossr50.util.blockmeta;
+
+import com.gmail.nossr50.mcMMO;
+import com.gmail.nossr50.util.BlockUtils;
+import com.google.common.io.Files;
+import org.bukkit.Bukkit;
+import org.bukkit.World;
+import org.bukkit.block.Block;
+import org.jetbrains.annotations.NotNull;
+import org.junit.jupiter.api.*;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.UUID;
+
+import static com.gmail.nossr50.util.blockmeta.BlockStoreTestUtils.LEGACY_WORLD_HEIGHT_MAX;
+import static com.gmail.nossr50.util.blockmeta.BlockStoreTestUtils.LEGACY_WORLD_HEIGHT_MIN;
+import static org.bukkit.Bukkit.getWorld;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.when;
+
+/**
+ * Could be a lot better. But some tests are better than none! Tests the major things, still kinda unit-testy. Verifies
+ * that the serialization isn't completely broken.
+ */
+class UserBlockTrackerTest {
+ private static File tempDir;
+
+ @BeforeAll
+ public static void setUpClass() {
+ tempDir = Files.createTempDir();
+ }
+
+ @AfterAll
+ public static void tearDownClass() {
+ recursiveDelete(tempDir);
+ }
+
+ private World mockWorld;
+
+ private MockedStatic bukkitMock;
+ private MockedStatic mcMMOMock;
+
+ @BeforeEach
+ void setUpMock() {
+ UUID worldUUID = UUID.randomUUID();
+ mockWorld = Mockito.mock(World.class);
+ when(mockWorld.getUID()).thenReturn(worldUUID);
+ when(mockWorld.getMaxHeight()).thenReturn(256);
+ when(mockWorld.getWorldFolder()).thenReturn(tempDir);
+
+ bukkitMock = mockStatic(Bukkit.class);
+ bukkitMock.when(() -> getWorld(worldUUID)).thenReturn(mockWorld);
+
+ mcMMOMock = mockStatic(mcMMO.class);
+
+ when(mockWorld.getMinHeight()).thenReturn(LEGACY_WORLD_HEIGHT_MIN);
+ when(mockWorld.getMaxHeight()).thenReturn(LEGACY_WORLD_HEIGHT_MAX);
+ }
+
+ @AfterEach
+ void teardownMock() {
+ bukkitMock.close();
+ mcMMOMock.close();
+ }
+
+ @Test
+ void setIneligibleShouldThrowIndexOutOfBoundsException() {
+ when(mockWorld.getMinHeight()).thenReturn(-64);
+ final HashChunkManager hashChunkManager = new HashChunkManager();
+
+ // Top Block
+ final Block illegalHeightBlock = initMockBlock(1337, 256, -1337);
+ assertFalse(hashChunkManager.isIneligible(illegalHeightBlock));
+ Assertions.assertThrows(IndexOutOfBoundsException.class, () -> hashChunkManager.setIneligible(illegalHeightBlock));
+ }
+
+ @Test
+ void testSetEligibility() {
+ when(mockWorld.getMinHeight()).thenReturn(-64);
+ final HashChunkManager hashChunkManager = new HashChunkManager();
+ int radius = 2; // Could be anything but drastically changes test time
+
+ for (int x = -radius; x <= radius; x++) {
+ for (int y = mockWorld.getMinHeight(); y < mockWorld.getMaxHeight(); y++) {
+ for (int z = -radius; z <= radius; z++) {
+ final Block testBlock = initMockBlock(x, y, z);
+ // mark ineligible
+ hashChunkManager.setIneligible(testBlock);
+ assertTrue(hashChunkManager.isIneligible(testBlock));
+
+ // mark eligible
+ hashChunkManager.setEligible(testBlock);
+ // Might as well test both isIneligible and isEligible while we are here
+ assertFalse(hashChunkManager.isIneligible(testBlock));
+ assertTrue(hashChunkManager.isEligible(testBlock));
+ }
+ }
+ }
+
+ // TODO: Whatever is going on down here should be in its own test
+ // Bot Block
+ final Block bottomBlock = initMockBlock(1337, 0, -1337);
+ assertFalse(hashChunkManager.isIneligible(bottomBlock));
+
+ assertTrue(BlockUtils.isWithinWorldBounds(bottomBlock));
+ hashChunkManager.setIneligible(bottomBlock);
+ assertTrue(hashChunkManager.isIneligible(bottomBlock));
+
+ // Top Block
+ final Block topBlock = initMockBlock(1337, 255, -1337);
+ assertFalse(hashChunkManager.isIneligible(topBlock));
+
+ assertTrue(BlockUtils.isWithinWorldBounds(topBlock));
+ hashChunkManager.setIneligible(topBlock);
+ assertTrue(hashChunkManager.isIneligible(topBlock));
+ }
+
+ @Test
+ void testChunkCoords() throws IOException {
+ // TODO: Unfinished test?
+ for (int x = -96; x < 0; x++) {
+ int cx = x >> 4;
+ int ix = Math.abs(x) % 16;
+ //System.out.print(cx + ":" + ix + " ");
+ }
+ }
+
+ @Test
+ void testSimpleRegionRejectsOutOfBounds() {
+ File file = new File(tempDir, "SimpleRegionRoundTrip.region");
+ McMMOSimpleRegionFile region = new McMMOSimpleRegionFile(file, 0, 0);
+ Assertions.assertThrows(IndexOutOfBoundsException.class, () -> region.getOutputStream(-1, 0));
+ Assertions.assertThrows(IndexOutOfBoundsException.class, () -> region.getOutputStream(0, -1));
+ Assertions.assertThrows(IndexOutOfBoundsException.class, () -> region.getOutputStream(32, 0));
+ Assertions.assertThrows(IndexOutOfBoundsException.class, () -> region.getOutputStream(0, 32));
+ region.close();
+ }
+
+ @Test
+ void testChunkStoreRejectsOutOfBounds() {
+ ChunkStore chunkStore = new BitSetChunkStore(mockWorld, 0, 0);
+ Assertions.assertThrows(IndexOutOfBoundsException.class, () -> chunkStore.setTrue(-1, 0, 0));
+ Assertions.assertThrows(IndexOutOfBoundsException.class, () -> chunkStore.setTrue(0, -1, 0));
+ Assertions.assertThrows(IndexOutOfBoundsException.class, () -> chunkStore.setTrue(0, 0, -1));
+ Assertions.assertThrows(IndexOutOfBoundsException.class, () -> chunkStore.setTrue(16, 0, 0));
+ Assertions.assertThrows(IndexOutOfBoundsException.class, () -> chunkStore.setTrue(0, mockWorld.getMaxHeight(), 0));
+ Assertions.assertThrows(IndexOutOfBoundsException.class, () -> chunkStore.setTrue(0, 0, 16));
+ }
+
+ @Test
+ void testRegressionChunkMirrorBug() {
+ final UserBlockTracker 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));
+ }
+
+ @NotNull
+ private Block initMockBlock(int x, int y, int z) {
+ final Block mockBlock = Mockito.mock(Block.class);
+ when(mockBlock.getX()).thenReturn(x);
+ when(mockBlock.getY()).thenReturn(y);
+ when(mockBlock.getZ()).thenReturn(z);
+ when(mockBlock.getWorld()).thenReturn(mockWorld);
+ return mockBlock;
+ }
+
+ public static void recursiveDelete(@NotNull File directoryToBeDeleted) {
+ if (directoryToBeDeleted.isDirectory()) {
+ for (File file : directoryToBeDeleted.listFiles()) {
+ recursiveDelete(file);
+ }
+ }
+ directoryToBeDeleted.delete();
+ }
+}