mirror of
https://github.com/mcMMO-Dev/mcMMO.git
synced 2025-08-01 03:55:28 +02:00
Merge branch 'master' of https://github.com/mcMMO-Dev/mcMMO into endgame
This commit is contained in:
@@ -10,6 +10,7 @@ import com.gmail.nossr50.locale.LocaleLoader;
|
||||
import com.gmail.nossr50.mcMMO;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.FurnaceRecipe;
|
||||
@@ -18,6 +19,7 @@ import org.bukkit.inventory.Recipe;
|
||||
import org.bukkit.inventory.meta.EnchantmentStorageMeta;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -35,14 +37,98 @@ public final class ItemUtils {
|
||||
* @param item Item to check
|
||||
* @return true if the item is a bow, false otherwise
|
||||
*/
|
||||
public static boolean isBow(ItemStack item) {
|
||||
public static boolean isBow(@NotNull ItemStack item) {
|
||||
return mcMMO.getMaterialMapStore().isBow(item.getType().getKey().getKey());
|
||||
}
|
||||
|
||||
public static boolean isCrossbow(@NotNull ItemStack item) {
|
||||
return mcMMO.getMaterialMapStore().isCrossbow(item.getType().getKey().getKey());
|
||||
}
|
||||
|
||||
public static boolean hasItemInEitherHand(@NotNull Player player, Material material) {
|
||||
return player.getInventory().getItemInMainHand().getType() == material || player.getInventory().getItemInOffHand().getType() == material;
|
||||
}
|
||||
|
||||
public static boolean doesPlayerHaveEnchantmentOnArmor(@NotNull Player player, @NotNull String enchantmentByName) {
|
||||
Enchantment enchantment = getEnchantment(enchantmentByName);
|
||||
|
||||
if(enchantment == null)
|
||||
return false;
|
||||
|
||||
return doesPlayerHaveEnchantmentOnArmor(player, enchantment);
|
||||
}
|
||||
|
||||
public static boolean doesPlayerHaveEnchantmentOnArmor(@NotNull Player player, @NotNull Enchantment enchantment) {
|
||||
for(ItemStack itemStack : player.getInventory().getArmorContents()) {
|
||||
if(itemStack != null) {
|
||||
if(hasEnchantment(itemStack, enchantment))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean doesPlayerHaveEnchantmentOnArmorOrHands(@NotNull Player player, @NotNull String enchantmentName) {
|
||||
Enchantment enchantment = getEnchantment(enchantmentName);
|
||||
|
||||
if(enchantment == null)
|
||||
return false;
|
||||
|
||||
return doesPlayerHaveEnchantmentOnArmorOrHands(player, enchantment);
|
||||
}
|
||||
|
||||
public static boolean doesPlayerHaveEnchantmentOnArmorOrHands(@NotNull Player player, @NotNull Enchantment enchantment) {
|
||||
if(doesPlayerHaveEnchantmentOnArmor(player, enchantment))
|
||||
return true;
|
||||
|
||||
if(doesPlayerHaveEnchantmentInHands(player, enchantment))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean doesPlayerHaveEnchantmentInHands(@NotNull Player player, @NotNull NamespacedKey enchantmentNameKey) {
|
||||
Enchantment enchantment = Enchantment.getByKey(enchantmentNameKey);
|
||||
|
||||
if(enchantment == null)
|
||||
return false;
|
||||
|
||||
return doesPlayerHaveEnchantmentInHands(player, enchantment);
|
||||
}
|
||||
|
||||
public static boolean doesPlayerHaveEnchantmentInHands(@NotNull Player player, @NotNull String enchantmentName) {
|
||||
Enchantment enchantment = getEnchantment(enchantmentName);
|
||||
|
||||
if(enchantment == null)
|
||||
return false;
|
||||
|
||||
return doesPlayerHaveEnchantmentInHands(player, enchantment);
|
||||
}
|
||||
|
||||
public static boolean doesPlayerHaveEnchantmentInHands(@NotNull Player player, @NotNull Enchantment enchantment) {
|
||||
return hasEnchantment(player.getInventory().getItemInMainHand(), enchantment) ||
|
||||
hasEnchantment(player.getInventory().getItemInOffHand(), enchantment);
|
||||
}
|
||||
|
||||
public static boolean hasEnchantment(@NotNull ItemStack itemStack, @NotNull Enchantment enchantment) {
|
||||
if(itemStack.getItemMeta() != null) {
|
||||
return itemStack.getItemMeta().hasEnchant(enchantment);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static @Nullable Enchantment getEnchantment(@NotNull String enchantmentName) {
|
||||
for(Enchantment enchantment : Enchantment.values()) {
|
||||
if(enchantment.getKey().getKey().equalsIgnoreCase(enchantmentName)) {
|
||||
return enchantment;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the item is a sword.
|
||||
*
|
||||
|
@@ -49,6 +49,7 @@ public class MaterialMapStore {
|
||||
private final @NotNull HashSet<String> pickAxes;
|
||||
private final @NotNull HashSet<String> tridents;
|
||||
private final @NotNull HashSet<String> bows;
|
||||
private final @NotNull HashSet<String> crossbows;
|
||||
private final @NotNull HashSet<String> tools;
|
||||
|
||||
private final @NotNull HashSet<String> enchantables;
|
||||
@@ -88,6 +89,7 @@ public class MaterialMapStore {
|
||||
diamondTools = new HashSet<>();
|
||||
netheriteTools = new HashSet<>();
|
||||
bows = new HashSet<>();
|
||||
crossbows = new HashSet<>();
|
||||
stringTools = new HashSet<>();
|
||||
tools = new HashSet<>();
|
||||
|
||||
@@ -447,6 +449,7 @@ public class MaterialMapStore {
|
||||
fillTridents();
|
||||
fillStringTools();
|
||||
fillBows();
|
||||
fillCrossbows();
|
||||
|
||||
//Tools collection
|
||||
tools.addAll(woodTools);
|
||||
@@ -464,6 +467,10 @@ public class MaterialMapStore {
|
||||
bows.add("bow");
|
||||
}
|
||||
|
||||
private void fillCrossbows() {
|
||||
crossbows.add("crossbow");
|
||||
}
|
||||
|
||||
private void fillStringTools() {
|
||||
stringTools.add("bow");
|
||||
stringTools.add("fishing_rod");
|
||||
@@ -771,6 +778,14 @@ public class MaterialMapStore {
|
||||
return bows.contains(id);
|
||||
}
|
||||
|
||||
public boolean isCrossbow(@NotNull Material material) {
|
||||
return isCrossbow(material.getKey().getKey());
|
||||
}
|
||||
|
||||
public boolean isCrossbow(@NotNull String id) {
|
||||
return crossbows.contains(id);
|
||||
}
|
||||
|
||||
public boolean isLeatherArmor(@NotNull Material material) {
|
||||
return isLeatherArmor(material.getKey().getKey());
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@ import com.gmail.nossr50.util.player.UserManager;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.entity.*;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
@@ -259,6 +260,12 @@ public final class Misc {
|
||||
}
|
||||
}
|
||||
|
||||
public static int getWorldMinCompat(World world)
|
||||
{
|
||||
// TODO this method should access the world min variable in a version safe manner so that we don't restrict usage to new versions of spigot only
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static void printProgress(int convertedUsers, int progressInterval, long startMillis) {
|
||||
if ((convertedUsers % progressInterval) == 0) {
|
||||
mcMMO.p.getLogger().info(String.format("Conversion progress: %d users at %.2f users/second", convertedUsers, convertedUsers / (double) ((System.currentTimeMillis() - startMillis) / TIME_CONVERSION_FACTOR)));
|
||||
|
@@ -1,5 +1,6 @@
|
||||
package com.gmail.nossr50.util.blockmeta;
|
||||
|
||||
import com.gmail.nossr50.util.Misc;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -10,12 +11,13 @@ import java.util.BitSet;
|
||||
import java.util.UUID;
|
||||
|
||||
public class BitSetChunkStore implements ChunkStore {
|
||||
private static final int CURRENT_VERSION = 8;
|
||||
private static final int CURRENT_VERSION = 9;
|
||||
private static final int MAGIC_NUMBER = 0xEA5EDEBB;
|
||||
|
||||
private final int cx;
|
||||
private final int cz;
|
||||
private final int worldHeight;
|
||||
private final int worldMin;
|
||||
private final int worldMax;
|
||||
private final @NotNull UUID worldUid;
|
||||
// Bitset store conforms to a "bottom-up" bit ordering consisting of a stack of {worldHeight} Y planes, each Y plane consists of 16 Z rows of 16 X bits.
|
||||
private final @NotNull BitSet store;
|
||||
@@ -23,15 +25,16 @@ public class BitSetChunkStore implements ChunkStore {
|
||||
private transient boolean dirty = false;
|
||||
|
||||
public BitSetChunkStore(@NotNull World world, int cx, int cz) {
|
||||
this(world.getUID(), world.getMaxHeight(), cx, cz);
|
||||
this(world.getUID(), Misc.getWorldMinCompat(world), world.getMaxHeight(), cx, cz);
|
||||
}
|
||||
|
||||
private BitSetChunkStore(@NotNull UUID worldUid, int worldHeight, int cx, int cz) {
|
||||
private BitSetChunkStore(@NotNull UUID worldUid, int worldMin, int worldMax, int cx, int cz) {
|
||||
this.cx = cx;
|
||||
this.cz = cz;
|
||||
this.worldUid = worldUid;
|
||||
this.worldHeight = worldHeight;
|
||||
this.store = new BitSet(16 * 16 * worldHeight);
|
||||
this.worldMin = worldMin;
|
||||
this.worldMax = worldMax;
|
||||
this.store = new BitSet(16 * 16 * (worldMax - worldMin));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -54,6 +57,16 @@ public class BitSetChunkStore implements ChunkStore {
|
||||
return cz;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getChunkMin() {
|
||||
return worldMin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getChunkMax() {
|
||||
return worldMax;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull UUID getWorldId() {
|
||||
return worldUid;
|
||||
@@ -86,22 +99,34 @@ public class BitSetChunkStore implements ChunkStore {
|
||||
}
|
||||
|
||||
private int coordToIndex(int x, int y, int z) {
|
||||
return coordToIndex(x, y, z, worldHeight);
|
||||
return coordToIndex(x, y, z, worldMin, worldMax);
|
||||
}
|
||||
|
||||
private static int coordToIndex(int x, int y, int z, int worldHeight) {
|
||||
if (x < 0 || x >= 16 || y < 0 || y >= worldHeight || z < 0 || z >= 16)
|
||||
throw new IndexOutOfBoundsException(String.format("x: %d y: %d z: %d World Height: %d", x, y, z, worldHeight));
|
||||
return (z * 16 + x) + (256 * y);
|
||||
private static int coordToIndex(int x, int y, int z, int worldMin, int worldMax) {
|
||||
if (x < 0 || x >= 16 || y < worldMin || y >= worldMax || z < 0 || z >= 16)
|
||||
throw new IndexOutOfBoundsException(String.format("x: %d y: %d z: %d World Min: %d World Max: %d", x, y, z, worldMin, worldMax));
|
||||
int yOffset = -worldMin; // Ensures y multiplier remains positive
|
||||
return (z * 16 + x) + (256 * (y + yOffset));
|
||||
}
|
||||
|
||||
private static int getWorldHeight(@NotNull UUID worldUid, int storedWorldHeight)
|
||||
private static int getWorldMin(@NotNull UUID worldUid, int storedWorldMin)
|
||||
{
|
||||
World world = Bukkit.getWorld(worldUid);
|
||||
|
||||
// Not sure how this case could come up, but might as well handle it gracefully. Loading a chunkstore for an unloaded world?
|
||||
if (world == null)
|
||||
return storedWorldHeight;
|
||||
return storedWorldMin;
|
||||
|
||||
return Misc.getWorldMinCompat(world);
|
||||
}
|
||||
|
||||
private static int getWorldMax(@NotNull UUID worldUid, int storedWorldMax)
|
||||
{
|
||||
World world = Bukkit.getWorld(worldUid);
|
||||
|
||||
// Not sure how this case could come up, but might as well handle it gracefully. Loading a chunkstore for an unloaded world?
|
||||
if (world == null)
|
||||
return storedWorldMax;
|
||||
|
||||
return world.getMaxHeight();
|
||||
}
|
||||
@@ -114,7 +139,8 @@ public class BitSetChunkStore implements ChunkStore {
|
||||
out.writeLong(worldUid.getMostSignificantBits());
|
||||
out.writeInt(cx);
|
||||
out.writeInt(cz);
|
||||
out.writeInt(worldHeight);
|
||||
out.writeInt(worldMin);
|
||||
out.writeInt(worldMax);
|
||||
|
||||
// Store the byte array directly so we don't have the object type info overhead
|
||||
byte[] storeData = store.toByteArray();
|
||||
@@ -129,7 +155,7 @@ public class BitSetChunkStore implements ChunkStore {
|
||||
// Can be used to determine the format of the file
|
||||
int fileVersionNumber = in.readInt();
|
||||
|
||||
if (magic != MAGIC_NUMBER || fileVersionNumber != CURRENT_VERSION)
|
||||
if (magic != MAGIC_NUMBER || fileVersionNumber < 8)
|
||||
throw new IOException();
|
||||
|
||||
long lsb = in.readLong();
|
||||
@@ -138,21 +164,38 @@ public class BitSetChunkStore implements ChunkStore {
|
||||
int cx = in.readInt();
|
||||
int cz = in.readInt();
|
||||
|
||||
int worldHeight = in.readInt();
|
||||
int worldMin = 0;
|
||||
if (fileVersionNumber >= 9)
|
||||
worldMin = in.readInt();
|
||||
int worldMax = in.readInt();
|
||||
byte[] temp = new byte[in.readInt()];
|
||||
in.readFully(temp);
|
||||
BitSet stored = BitSet.valueOf(temp);
|
||||
|
||||
int currentWorldHeight = getWorldHeight(worldUid, worldHeight);
|
||||
int currentWorldMin = getWorldMin(worldUid, worldMin);
|
||||
int currentWorldMax = getWorldMax(worldUid, worldMax);
|
||||
|
||||
boolean worldHeightShrunk = currentWorldHeight < worldHeight;
|
||||
// Lop off extra data if world height has shrunk
|
||||
if (worldHeightShrunk)
|
||||
stored.clear(coordToIndex(16, currentWorldHeight, 16, worldHeight), stored.length());
|
||||
// The order in which the world height update code occurs here is important, the world max truncate math only holds up if done before adjusting for min changes
|
||||
// Lop off extra data if world max has shrunk
|
||||
if (currentWorldMax < worldMax)
|
||||
stored.clear(coordToIndex(16, currentWorldMax, 16, worldMin, worldMax), stored.length());
|
||||
// Left shift store if world min has shrunk
|
||||
if (currentWorldMin > worldMin)
|
||||
stored = stored.get(currentWorldMin, stored.length()); // Because BitSet's aren't fixed size, a "substring" operation is equivalent to a left shift
|
||||
// Right shift store if world min has expanded
|
||||
if (currentWorldMin < worldMin)
|
||||
{
|
||||
int offset = (worldMin - currentWorldMin) * 16 * 16; // We are adding this many bits to the front
|
||||
// This isn't the most efficient way to do this, however, its a rare case to occur, and in the grand scheme of things, the small performance we could gain would cost us significant reduced readability of the code
|
||||
BitSet shifted = new BitSet();
|
||||
for (int i = 0; i < stored.length(); i++)
|
||||
shifted.set(i + offset, stored.get(i));
|
||||
stored = shifted;
|
||||
}
|
||||
|
||||
BitSetChunkStore chunkStore = new BitSetChunkStore(worldUid, currentWorldHeight, cx, cz);
|
||||
BitSetChunkStore chunkStore = new BitSetChunkStore(worldUid, currentWorldMin, currentWorldMax, cx, cz);
|
||||
chunkStore.store.or(stored);
|
||||
chunkStore.dirty = worldHeightShrunk; // In the expanded case there is no reason to re-write it unless the data changes
|
||||
chunkStore.dirty = currentWorldMin != worldMin || currentWorldMax != worldMax;
|
||||
|
||||
return chunkStore;
|
||||
}
|
||||
@@ -203,7 +246,7 @@ public class BitSetChunkStore implements ChunkStore {
|
||||
|
||||
private int cx;
|
||||
private int cz;
|
||||
private int worldHeight;
|
||||
private int worldMax;
|
||||
private UUID worldUid;
|
||||
private boolean[][][] store;
|
||||
|
||||
@@ -226,19 +269,20 @@ public class BitSetChunkStore implements ChunkStore {
|
||||
cz = in.readInt();
|
||||
|
||||
store = (boolean[][][]) in.readObject();
|
||||
worldHeight = store[0][0].length;
|
||||
worldMax = store[0][0].length;
|
||||
}
|
||||
|
||||
public @NotNull BitSetChunkStore convert()
|
||||
{
|
||||
int currentWorldHeight = getWorldHeight(worldUid, worldHeight);
|
||||
int currentWorldMin = getWorldMin(worldUid, 0);
|
||||
int currentWorldMax = getWorldMax(worldUid, worldMax);
|
||||
|
||||
BitSetChunkStore converted = new BitSetChunkStore(worldUid, currentWorldHeight, cx, cz);
|
||||
BitSetChunkStore converted = new BitSetChunkStore(worldUid, currentWorldMin, currentWorldMax, cx, cz);
|
||||
|
||||
// Read old data into new chunkstore
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int y = 0; y < worldHeight && y < currentWorldHeight; y++) {
|
||||
for (int y = 0; y < worldMax && y < currentWorldMax; y++) {
|
||||
converted.store.set(converted.coordToIndex(x, y, z), store[x][z][y]);
|
||||
}
|
||||
}
|
||||
|
@@ -36,6 +36,9 @@ public interface ChunkStore {
|
||||
*/
|
||||
int getChunkZ();
|
||||
|
||||
int getChunkMin();
|
||||
int getChunkMax();
|
||||
|
||||
@NotNull UUID getWorldId();
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user