mirror of
https://github.com/mcMMO-Dev/mcMMO.git
synced 2024-11-28 08:06:46 +01:00
Merge branch 'master' of https://github.com/mcMMO-Dev/mcMMO into endgame
This commit is contained in:
commit
1a180c4cdf
51
.github/workflows/maven.yml
vendored
Normal file
51
.github/workflows/maven.yml
vendored
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
# This workflow automatically tests new commits and pull requests as they come in.
|
||||||
|
# Note that this does not upload any artifacts, you will need to compile mcMMO manually
|
||||||
|
# if you wish to create the actual jar.
|
||||||
|
name: Compile and test
|
||||||
|
|
||||||
|
on:
|
||||||
|
# We run our tests whenever the pom or a source file was touched.
|
||||||
|
# There is no need to run Maven when only the changelog was touched.
|
||||||
|
# We may also want to re-run this workflow when the workflow file itself
|
||||||
|
# was updated too.
|
||||||
|
push:
|
||||||
|
paths:
|
||||||
|
- 'src/**'
|
||||||
|
- 'pom.xml'
|
||||||
|
- '.github/workflows/maven.yml'
|
||||||
|
|
||||||
|
# Whenever someone submits a new pull request which modified the pom or a source file,
|
||||||
|
# we want to ensure it compiles successfully and that all tests will pass.
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- 'src/**'
|
||||||
|
- 'pom.xml'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
compile:
|
||||||
|
name: Maven compiler
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
|
||||||
|
# 1. Check out the current working tree
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
# 2. Setup Java 1.8 JDK
|
||||||
|
- name: Java 1.8 setup
|
||||||
|
uses: actions/setup-java@v1.4.3
|
||||||
|
with:
|
||||||
|
java-package: jdk
|
||||||
|
java-version: 1.8
|
||||||
|
|
||||||
|
# 3. Setup local Maven package cache to speed up building
|
||||||
|
- name: Cache Maven packages
|
||||||
|
uses: actions/cache@v2
|
||||||
|
with:
|
||||||
|
path: ~/.m2
|
||||||
|
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
|
||||||
|
restore-keys: ${{ runner.os }}-m2
|
||||||
|
|
||||||
|
# 4. Build via Maven
|
||||||
|
- name: Build via Maven
|
||||||
|
run: mvn verify -B --file pom.xml
|
@ -1,4 +1,7 @@
|
|||||||
Version 2.1.175
|
Version 2.1.175
|
||||||
|
Fixed a bug where mcMMO would occasionally give a 65 item stack from a double smelt on a furnace
|
||||||
|
Fixed a bug where arrows could be duped when fired from a crossbow with piercing enchantment
|
||||||
|
Added setting to enable or disable Green Thumb automatically replanting crops per crop to config.yml under 'Green_Thumb_Replanting_Crops' section
|
||||||
(API) Many skills with RNG elements now send out a SubSkillEvent (which can be used to modify probability or cancel the results), some skills without RNG still send out this event when activated, this event is cancellable so it can be used to make a skill fail
|
(API) Many skills with RNG elements now send out a SubSkillEvent (which can be used to modify probability or cancel the results), some skills without RNG still send out this event when activated, this event is cancellable so it can be used to make a skill fail
|
||||||
Treasure drop rate from Shake, Fishing, Hylian, and Excavation now benefit from the Luck perk
|
Treasure drop rate from Shake, Fishing, Hylian, and Excavation now benefit from the Luck perk
|
||||||
Added a setting to chat.yml to toggle sending party or admin chat messages to console
|
Added a setting to chat.yml to toggle sending party or admin chat messages to console
|
||||||
|
17
pom.xml
17
pom.xml
@ -101,6 +101,7 @@
|
|||||||
<include>commons-logging:commons-logging</include>
|
<include>commons-logging:commons-logging</include>
|
||||||
<include>org.apache.tomcat:tomcat-jdbc</include>
|
<include>org.apache.tomcat:tomcat-jdbc</include>
|
||||||
<include>org.apache.tomcat:tomcat-juli</include>
|
<include>org.apache.tomcat:tomcat-juli</include>
|
||||||
|
<include>org.bstats:bstats-base</include>
|
||||||
<include>org.bstats:bstats-bukkit</include>
|
<include>org.bstats:bstats-bukkit</include>
|
||||||
<include>net.kyori:adventure-api</include>
|
<include>net.kyori:adventure-api</include>
|
||||||
<include>net.kyori:adventure-text-serializer-gson</include>
|
<include>net.kyori:adventure-text-serializer-gson</include>
|
||||||
@ -208,27 +209,27 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.kyori</groupId>
|
<groupId>net.kyori</groupId>
|
||||||
<artifactId>adventure-text-serializer-gson</artifactId>
|
<artifactId>adventure-text-serializer-gson</artifactId>
|
||||||
<version>4.4.0</version>
|
<version>4.5.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.kyori</groupId>
|
<groupId>net.kyori</groupId>
|
||||||
<artifactId>adventure-api</artifactId>
|
<artifactId>adventure-api</artifactId>
|
||||||
<version>4.4.0</version>
|
<version>4.5.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.kyori</groupId>
|
<groupId>net.kyori</groupId>
|
||||||
<artifactId>adventure-nbt</artifactId>
|
<artifactId>adventure-nbt</artifactId>
|
||||||
<version>4.4.0</version>
|
<version>4.5.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.kyori</groupId>
|
<groupId>net.kyori</groupId>
|
||||||
<artifactId>adventure-key</artifactId>
|
<artifactId>adventure-key</artifactId>
|
||||||
<version>4.4.0</version>
|
<version>4.5.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.kyori</groupId>
|
<groupId>net.kyori</groupId>
|
||||||
<artifactId>adventure-text-serializer-gson-legacy-impl</artifactId>
|
<artifactId>adventure-text-serializer-gson-legacy-impl</artifactId>
|
||||||
<version>4.4.0</version>
|
<version>4.5.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.kyori</groupId>
|
<groupId>net.kyori</groupId>
|
||||||
@ -253,13 +254,13 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.bstats</groupId>
|
<groupId>org.bstats</groupId>
|
||||||
<artifactId>bstats-bukkit</artifactId>
|
<artifactId>bstats-bukkit</artifactId>
|
||||||
<version>1.8</version>
|
<version>2.2.1</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.spigotmc</groupId>
|
<groupId>org.spigotmc</groupId>
|
||||||
<artifactId>spigot-api</artifactId>
|
<artifactId>spigot-api</artifactId>
|
||||||
<version>1.16.4-R0.1-SNAPSHOT</version>
|
<version>1.16.5-R0.1-SNAPSHOT</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -307,7 +308,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.mockito</groupId>
|
<groupId>org.mockito</groupId>
|
||||||
<artifactId>mockito-core</artifactId>
|
<artifactId>mockito-core</artifactId>
|
||||||
<version>3.4.6</version>
|
<version>3.8.0</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -9,6 +9,7 @@ import com.gmail.nossr50.util.text.StringUtils;
|
|||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.block.data.BlockData;
|
import org.bukkit.block.data.BlockData;
|
||||||
import org.bukkit.configuration.ConfigurationSection;
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -598,4 +599,7 @@ public class Config extends AutoUpdateConfigLoader {
|
|||||||
public int getPowerLevelUpBroadcastInterval() { return config.getInt("General.Level_Up_Chat_Broadcasts.Broadcast_Powerlevels.Milestone_Interval", 100); }
|
public int getPowerLevelUpBroadcastInterval() { return config.getInt("General.Level_Up_Chat_Broadcasts.Broadcast_Powerlevels.Milestone_Interval", 100); }
|
||||||
|
|
||||||
public boolean isMasterySystemEnabled() { return config.getBoolean( "General.PowerLevel.Skill_Mastery.Enabled"); }
|
public boolean isMasterySystemEnabled() { return config.getBoolean( "General.PowerLevel.Skill_Mastery.Enabled"); }
|
||||||
|
public boolean isGreenThumbReplantableCrop(@NotNull Material material) {
|
||||||
|
return config.getBoolean("Green_Thumb_Replanting_Crops." + StringUtils.getCapitalized(material.toString()), true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -148,10 +148,13 @@ public class BlockListener implements Listener {
|
|||||||
// Get opposite direction so we get correct block
|
// Get opposite direction so we get correct block
|
||||||
BlockFace direction = event.getDirection();
|
BlockFace direction = event.getDirection();
|
||||||
Block movedBlock = event.getBlock().getRelative(direction);
|
Block movedBlock = event.getBlock().getRelative(direction);
|
||||||
|
if (movedBlock.getY() >= Misc.getWorldMinCompat(movedBlock.getWorld())) // Very weird that the event is giving us these, they shouldn't exist
|
||||||
mcMMO.getPlaceStore().setTrue(movedBlock);
|
mcMMO.getPlaceStore().setTrue(movedBlock);
|
||||||
|
|
||||||
for (Block block : event.getBlocks()) {
|
for (Block block : event.getBlocks()) {
|
||||||
movedBlock = block.getRelative(direction);
|
movedBlock = block.getRelative(direction);
|
||||||
|
if (movedBlock.getY() < Misc.getWorldMinCompat(movedBlock.getWorld())) // Very weird that the event is giving us these, they shouldn't exist
|
||||||
|
continue;
|
||||||
mcMMO.getPlaceStore().setTrue(movedBlock);
|
mcMMO.getPlaceStore().setTrue(movedBlock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ import com.gmail.nossr50.skills.taming.Taming;
|
|||||||
import com.gmail.nossr50.skills.taming.TamingManager;
|
import com.gmail.nossr50.skills.taming.TamingManager;
|
||||||
import com.gmail.nossr50.skills.unarmed.UnarmedManager;
|
import com.gmail.nossr50.skills.unarmed.UnarmedManager;
|
||||||
import com.gmail.nossr50.util.BlockUtils;
|
import com.gmail.nossr50.util.BlockUtils;
|
||||||
|
import com.gmail.nossr50.util.ItemUtils;
|
||||||
import com.gmail.nossr50.util.Misc;
|
import com.gmail.nossr50.util.Misc;
|
||||||
import com.gmail.nossr50.util.Permissions;
|
import com.gmail.nossr50.util.Permissions;
|
||||||
import com.gmail.nossr50.util.compat.layers.persistentdata.AbstractPersistentDataLayer;
|
import com.gmail.nossr50.util.compat.layers.persistentdata.AbstractPersistentDataLayer;
|
||||||
@ -155,8 +156,7 @@ public class EntityListener implements Listener {
|
|||||||
Player player = (Player) event.getEntity().getShooter();
|
Player player = (Player) event.getEntity().getShooter();
|
||||||
|
|
||||||
/* WORLD GUARD MAIN FLAG CHECK */
|
/* WORLD GUARD MAIN FLAG CHECK */
|
||||||
if(WorldGuardUtils.isWorldGuardLoaded())
|
if(WorldGuardUtils.isWorldGuardLoaded()) {
|
||||||
{
|
|
||||||
if(!WorldGuardManager.getInstance().hasMainFlag(player))
|
if(!WorldGuardManager.getInstance().hasMainFlag(player))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -173,11 +173,10 @@ public class EntityListener implements Listener {
|
|||||||
if(!projectile.hasMetadata(mcMMO.arrowDistanceKey))
|
if(!projectile.hasMetadata(mcMMO.arrowDistanceKey))
|
||||||
projectile.setMetadata(mcMMO.arrowDistanceKey, new FixedMetadataValue(pluginRef, projectile.getLocation()));
|
projectile.setMetadata(mcMMO.arrowDistanceKey, new FixedMetadataValue(pluginRef, projectile.getLocation()));
|
||||||
|
|
||||||
for (Enchantment enchantment : player.getInventory().getItemInMainHand().getEnchantments().keySet()) {
|
//Check both hands
|
||||||
if (enchantment.getKey().equals(piercingEnchantment)) {
|
if(ItemUtils.doesPlayerHaveEnchantmentInHands(player, "piercing")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (SkillUtils.isSkillRNGSuccessful(SubSkillType.ARCHERY_ARROW_RETRIEVAL, player)) {
|
if (SkillUtils.isSkillRNGSuccessful(SubSkillType.ARCHERY_ARROW_RETRIEVAL, player)) {
|
||||||
projectile.setMetadata(mcMMO.trackedArrow, mcMMO.metadataValue);
|
projectile.setMetadata(mcMMO.trackedArrow, mcMMO.metadataValue);
|
||||||
|
@ -116,7 +116,8 @@ public class InventoryListener implements Listener {
|
|||||||
|
|
||||||
//Profile doesn't exist
|
//Profile doesn't exist
|
||||||
if(offlineProfile != null) {
|
if(offlineProfile != null) {
|
||||||
event.setResult(offlineProfile.getSmeltingManager().smeltProcessing(smelting, event.getResult()));
|
//Process smelting
|
||||||
|
offlineProfile.getSmeltingManager().smeltProcessing(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,21 +52,24 @@ import com.gmail.nossr50.util.skills.RankUtils;
|
|||||||
import com.gmail.nossr50.util.skills.SmeltingTracker;
|
import com.gmail.nossr50.util.skills.SmeltingTracker;
|
||||||
import com.gmail.nossr50.util.upgrade.UpgradeManager;
|
import com.gmail.nossr50.util.upgrade.UpgradeManager;
|
||||||
import com.gmail.nossr50.worldguard.WorldGuardManager;
|
import com.gmail.nossr50.worldguard.WorldGuardManager;
|
||||||
import com.google.common.base.Charsets;
|
|
||||||
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
||||||
import net.shatteredlands.shatt.backup.ZipLibrary;
|
import net.shatteredlands.shatt.backup.ZipLibrary;
|
||||||
import org.bstats.bukkit.Metrics;
|
import org.bstats.bukkit.Metrics;
|
||||||
|
import org.bstats.charts.SimplePie;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.HandlerList;
|
import org.bukkit.event.HandlerList;
|
||||||
import org.bukkit.metadata.FixedMetadataValue;
|
import org.bukkit.metadata.FixedMetadataValue;
|
||||||
import org.bukkit.plugin.PluginManager;
|
import org.bukkit.plugin.PluginManager;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -124,24 +127,24 @@ public class mcMMO extends JavaPlugin {
|
|||||||
private static boolean isRetroModeEnabled;
|
private static boolean isRetroModeEnabled;
|
||||||
|
|
||||||
/* Metadata Values */
|
/* Metadata Values */
|
||||||
public final static String REPLANT_META_KEY = "mcMMO: Recently Replanted";
|
public static final String REPLANT_META_KEY = "mcMMO: Recently Replanted";
|
||||||
public static final String FISH_HOOK_REF_METAKEY = "mcMMO: Fish Hook Tracker";
|
public static final String FISH_HOOK_REF_METAKEY = "mcMMO: Fish Hook Tracker";
|
||||||
public static final String DODGE_TRACKER = "mcMMO: Dodge Tracker";
|
public static final String DODGE_TRACKER = "mcMMO: Dodge Tracker";
|
||||||
public static final String CUSTOM_DAMAGE_METAKEY = "mcMMO: Custom Damage";
|
public static final String CUSTOM_DAMAGE_METAKEY = "mcMMO: Custom Damage";
|
||||||
public final static String travelingBlock = "mcMMO: Traveling Block";
|
public static final String travelingBlock = "mcMMO: Traveling Block";
|
||||||
public final static String blockMetadataKey = "mcMMO: Piston Tracking";
|
public static final String blockMetadataKey = "mcMMO: Piston Tracking";
|
||||||
public final static String tntMetadataKey = "mcMMO: Tracked TNT";
|
public static final String tntMetadataKey = "mcMMO: Tracked TNT";
|
||||||
public final static String customNameKey = "mcMMO: Custom Name";
|
public static final String customNameKey = "mcMMO: Custom Name";
|
||||||
public final static String customVisibleKey = "mcMMO: Name Visibility";
|
public static final String customVisibleKey = "mcMMO: Name Visibility";
|
||||||
public final static String droppedItemKey = "mcMMO: Tracked Item";
|
public static final String droppedItemKey = "mcMMO: Tracked Item";
|
||||||
public final static String infiniteArrowKey = "mcMMO: Infinite Arrow";
|
public static final String infiniteArrowKey = "mcMMO: Infinite Arrow";
|
||||||
public final static String trackedArrow = "mcMMO: Tracked Arrow";
|
public static final String trackedArrow = "mcMMO: Tracked Arrow";
|
||||||
public final static String bowForceKey = "mcMMO: Bow Force";
|
public static final String bowForceKey = "mcMMO: Bow Force";
|
||||||
public final static String arrowDistanceKey = "mcMMO: Arrow Distance";
|
public static final String arrowDistanceKey = "mcMMO: Arrow Distance";
|
||||||
public final static String BONUS_DROPS_METAKEY = "mcMMO: Double Drops";
|
public static final String BONUS_DROPS_METAKEY = "mcMMO: Double Drops";
|
||||||
public final static String disarmedItemKey = "mcMMO: Disarmed Item";
|
public static final String disarmedItemKey = "mcMMO: Disarmed Item";
|
||||||
public final static String playerDataKey = "mcMMO: Player Data";
|
public static final String playerDataKey = "mcMMO: Player Data";
|
||||||
public final static String databaseCommandKey = "mcMMO: Processing Database Command";
|
public static final String databaseCommandKey = "mcMMO: Processing Database Command";
|
||||||
|
|
||||||
public static FixedMetadataValue metadataValue;
|
public static FixedMetadataValue metadataValue;
|
||||||
|
|
||||||
@ -158,7 +161,9 @@ public class mcMMO extends JavaPlugin {
|
|||||||
//Platform Manager
|
//Platform Manager
|
||||||
platformManager = new PlatformManager();
|
platformManager = new PlatformManager();
|
||||||
|
|
||||||
|
//Filter out any debug messages (if debug/verbose logging is not enabled)
|
||||||
getLogger().setFilter(new LogFilter(this));
|
getLogger().setFilter(new LogFilter(this));
|
||||||
|
|
||||||
metadataValue = new FixedMetadataValue(this, true);
|
metadataValue = new FixedMetadataValue(this, true);
|
||||||
|
|
||||||
PluginManager pluginManager = getServer().getPluginManager();
|
PluginManager pluginManager = getServer().getPluginManager();
|
||||||
@ -254,12 +259,12 @@ public class mcMMO extends JavaPlugin {
|
|||||||
|
|
||||||
if(Config.getInstance().getIsMetricsEnabled()) {
|
if(Config.getInstance().getIsMetricsEnabled()) {
|
||||||
metrics = new Metrics(this, 3894);
|
metrics = new Metrics(this, 3894);
|
||||||
metrics.addCustomChart(new Metrics.SimplePie("version", () -> getDescription().getVersion()));
|
metrics.addCustomChart(new SimplePie("version", () -> getDescription().getVersion()));
|
||||||
|
|
||||||
if(Config.getInstance().getIsRetroMode())
|
if(Config.getInstance().getIsRetroMode())
|
||||||
metrics.addCustomChart(new Metrics.SimplePie("leveling_system", () -> "Retro"));
|
metrics.addCustomChart(new SimplePie("leveling_system", () -> "Retro"));
|
||||||
else
|
else
|
||||||
metrics.addCustomChart(new Metrics.SimplePie("leveling_system", () -> "Standard"));
|
metrics.addCustomChart(new SimplePie("leveling_system", () -> "Standard"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Throwable t) {
|
catch (Throwable t) {
|
||||||
@ -273,6 +278,9 @@ public class mcMMO extends JavaPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getServer().getPluginManager().disablePlugin(this);
|
getServer().getPluginManager().disablePlugin(this);
|
||||||
|
|
||||||
|
//Fixes #4438 - Don't initialize things if we are going to disable mcMMO anyway
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Init player level values
|
//Init player level values
|
||||||
@ -284,6 +292,7 @@ public class mcMMO extends JavaPlugin {
|
|||||||
//Init smelting tracker
|
//Init smelting tracker
|
||||||
smeltingTracker = new SmeltingTracker();
|
smeltingTracker = new SmeltingTracker();
|
||||||
|
|
||||||
|
//Set up Adventure's audiences
|
||||||
audiences = BukkitAudiences.create(this);
|
audiences = BukkitAudiences.create(this);
|
||||||
|
|
||||||
transientMetadataTools = new TransientMetadataTools(this);
|
transientMetadataTools = new TransientMetadataTools(this);
|
||||||
@ -347,8 +356,9 @@ public class mcMMO extends JavaPlugin {
|
|||||||
holidayManager.saveAnniversaryFiles();
|
holidayManager.saveAnniversaryFiles();
|
||||||
placeStore.closeAll();
|
placeStore.closeAll();
|
||||||
}
|
}
|
||||||
|
catch (Exception e) {
|
||||||
catch (Exception e) { e.printStackTrace(); }
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
if (Config.getInstance().getBackupsEnabled()) {
|
if (Config.getInstance().getBackupsEnabled()) {
|
||||||
// Remove other tasks BEFORE starting the Backup, or we just cancel it straight away.
|
// Remove other tasks BEFORE starting the Backup, or we just cancel it straight away.
|
||||||
@ -358,16 +368,14 @@ public class mcMMO extends JavaPlugin {
|
|||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
getLogger().severe(e.toString());
|
getLogger().severe(e.toString());
|
||||||
}
|
}
|
||||||
catch (Throwable e) {
|
catch(NoClassDefFoundError e) {
|
||||||
if (e instanceof NoClassDefFoundError) {
|
|
||||||
getLogger().severe("Backup class not found!");
|
getLogger().severe("Backup class not found!");
|
||||||
getLogger().info("Please do not replace the mcMMO jar while the server is running.");
|
getLogger().info("Please do not replace the mcMMO jar while the server is running.");
|
||||||
}
|
}
|
||||||
else {
|
catch (Throwable e) {
|
||||||
getLogger().severe(e.toString());
|
getLogger().severe(e.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
debug("Canceling all tasks...");
|
debug("Canceling all tasks...");
|
||||||
getServer().getScheduler().cancelTasks(this); // This removes our tasks
|
getServer().getScheduler().cancelTasks(this); // This removes our tasks
|
||||||
@ -682,9 +690,9 @@ public class mcMMO extends JavaPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public InputStreamReader getResourceAsReader(String fileName) {
|
public @Nullable InputStreamReader getResourceAsReader(@NotNull String fileName) {
|
||||||
InputStream in = getResource(fileName);
|
InputStream in = getResource(fileName);
|
||||||
return in == null ? null : new InputStreamReader(in, Charsets.UTF_8);
|
return in == null ? null : new InputStreamReader(in, StandardCharsets.UTF_8);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -179,10 +179,12 @@ public class HerbalismManager extends SkillManager {
|
|||||||
|
|
||||||
//TODO: The design of Green Terra needs to change, this is a mess
|
//TODO: The design of Green Terra needs to change, this is a mess
|
||||||
if(Permissions.greenThumbPlant(getPlayer(), originalBreak.getType())) {
|
if(Permissions.greenThumbPlant(getPlayer(), originalBreak.getType())) {
|
||||||
|
if(Config.getInstance().isGreenThumbReplantableCrop(originalBreak.getType())) {
|
||||||
if(!getPlayer().isSneaking()) {
|
if(!getPlayer().isSneaking()) {
|
||||||
greenThumbActivated = processGreenThumbPlants(originalBreak, blockBreakEvent, isGreenTerraActive());
|
greenThumbActivated = processGreenThumbPlants(originalBreak, blockBreakEvent, isGreenTerraActive());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//When replanting a immature crop we cancel the block break event and back out
|
//When replanting a immature crop we cancel the block break event and back out
|
||||||
if(greenThumbActivated) {
|
if(greenThumbActivated) {
|
||||||
|
@ -11,7 +11,9 @@ import com.gmail.nossr50.util.Permissions;
|
|||||||
import com.gmail.nossr50.util.skills.RankUtils;
|
import com.gmail.nossr50.util.skills.RankUtils;
|
||||||
import com.gmail.nossr50.util.skills.SkillUtils;
|
import com.gmail.nossr50.util.skills.SkillUtils;
|
||||||
import org.bukkit.event.inventory.FurnaceBurnEvent;
|
import org.bukkit.event.inventory.FurnaceBurnEvent;
|
||||||
|
import org.bukkit.event.inventory.FurnaceSmeltEvent;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
public class SmeltingManager extends SkillManager {
|
public class SmeltingManager extends SkillManager {
|
||||||
public SmeltingManager(McMMOPlayer mcMMOPlayer) {
|
public SmeltingManager(McMMOPlayer mcMMOPlayer) {
|
||||||
@ -107,19 +109,29 @@ public class SmeltingManager extends SkillManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ItemStack smeltProcessing(ItemStack smelting, ItemStack result) {
|
public void smeltProcessing(@NotNull FurnaceSmeltEvent furnaceSmeltEvent) {
|
||||||
|
ItemStack sourceItemStack = furnaceSmeltEvent.getSource();
|
||||||
|
ItemStack resultItemStack = furnaceSmeltEvent.getResult();
|
||||||
|
|
||||||
applyXpGain(Smelting.getResourceXp(smelting), XPGainReason.PVE, XPGainSource.PASSIVE);
|
applyXpGain(Smelting.getResourceXp(sourceItemStack), XPGainReason.PVE, XPGainSource.PASSIVE); //Add XP
|
||||||
|
int itemLimit = resultItemStack.getMaxStackSize();
|
||||||
|
|
||||||
if (Config.getInstance().getDoubleDropsEnabled(PrimarySkillType.SMELTING, result.getType())
|
processDoubleSmelt(furnaceSmeltEvent, resultItemStack, itemLimit);
|
||||||
&& isSecondSmeltSuccessful() && result.getAmount() < 64) {
|
|
||||||
ItemStack newResult = result.clone();
|
|
||||||
|
|
||||||
newResult.setAmount(result.getAmount() + 1);
|
|
||||||
return newResult;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
private void processDoubleSmelt(@NotNull FurnaceSmeltEvent furnaceSmeltEvent, @NotNull ItemStack resultItemStack, int itemLimit) {
|
||||||
|
//TODO: Permission check work around, could store it as NBT on the furnace
|
||||||
|
//We don't do permission checks because this can be for an offline player and Bukkit has nothing to grab permissions for offline players
|
||||||
|
|
||||||
|
//Process double smelt
|
||||||
|
if (Config.getInstance().getDoubleDropsEnabled(PrimarySkillType.SMELTING, resultItemStack.getType())
|
||||||
|
&& resultItemStack.getAmount() < itemLimit
|
||||||
|
&& isSecondSmeltSuccessful()) {
|
||||||
|
|
||||||
|
ItemStack newResult = resultItemStack.clone();
|
||||||
|
newResult.setAmount(Math.min(resultItemStack.getAmount() + 1, itemLimit)); //Don't go over max stack limits
|
||||||
|
furnaceSmeltEvent.setResult(newResult);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int vanillaXPBoost(int experience) {
|
public int vanillaXPBoost(int experience) {
|
||||||
|
@ -10,6 +10,7 @@ import com.gmail.nossr50.locale.LocaleLoader;
|
|||||||
import com.gmail.nossr50.mcMMO;
|
import com.gmail.nossr50.mcMMO;
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
import org.bukkit.enchantments.Enchantment;
|
import org.bukkit.enchantments.Enchantment;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.inventory.FurnaceRecipe;
|
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.EnchantmentStorageMeta;
|
||||||
import org.bukkit.inventory.meta.ItemMeta;
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -35,14 +37,98 @@ public final class ItemUtils {
|
|||||||
* @param item Item to check
|
* @param item Item to check
|
||||||
* @return true if the item is a bow, false otherwise
|
* @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());
|
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) {
|
public static boolean hasItemInEitherHand(@NotNull Player player, Material material) {
|
||||||
return player.getInventory().getItemInMainHand().getType() == material || player.getInventory().getItemInOffHand().getType() == 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.
|
* 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> pickAxes;
|
||||||
private final @NotNull HashSet<String> tridents;
|
private final @NotNull HashSet<String> tridents;
|
||||||
private final @NotNull HashSet<String> bows;
|
private final @NotNull HashSet<String> bows;
|
||||||
|
private final @NotNull HashSet<String> crossbows;
|
||||||
private final @NotNull HashSet<String> tools;
|
private final @NotNull HashSet<String> tools;
|
||||||
|
|
||||||
private final @NotNull HashSet<String> enchantables;
|
private final @NotNull HashSet<String> enchantables;
|
||||||
@ -88,6 +89,7 @@ public class MaterialMapStore {
|
|||||||
diamondTools = new HashSet<>();
|
diamondTools = new HashSet<>();
|
||||||
netheriteTools = new HashSet<>();
|
netheriteTools = new HashSet<>();
|
||||||
bows = new HashSet<>();
|
bows = new HashSet<>();
|
||||||
|
crossbows = new HashSet<>();
|
||||||
stringTools = new HashSet<>();
|
stringTools = new HashSet<>();
|
||||||
tools = new HashSet<>();
|
tools = new HashSet<>();
|
||||||
|
|
||||||
@ -447,6 +449,7 @@ public class MaterialMapStore {
|
|||||||
fillTridents();
|
fillTridents();
|
||||||
fillStringTools();
|
fillStringTools();
|
||||||
fillBows();
|
fillBows();
|
||||||
|
fillCrossbows();
|
||||||
|
|
||||||
//Tools collection
|
//Tools collection
|
||||||
tools.addAll(woodTools);
|
tools.addAll(woodTools);
|
||||||
@ -464,6 +467,10 @@ public class MaterialMapStore {
|
|||||||
bows.add("bow");
|
bows.add("bow");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void fillCrossbows() {
|
||||||
|
crossbows.add("crossbow");
|
||||||
|
}
|
||||||
|
|
||||||
private void fillStringTools() {
|
private void fillStringTools() {
|
||||||
stringTools.add("bow");
|
stringTools.add("bow");
|
||||||
stringTools.add("fishing_rod");
|
stringTools.add("fishing_rod");
|
||||||
@ -771,6 +778,14 @@ public class MaterialMapStore {
|
|||||||
return bows.contains(id);
|
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) {
|
public boolean isLeatherArmor(@NotNull Material material) {
|
||||||
return isLeatherArmor(material.getKey().getKey());
|
return isLeatherArmor(material.getKey().getKey());
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import com.gmail.nossr50.util.player.UserManager;
|
|||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.World;
|
||||||
import org.bukkit.block.BlockState;
|
import org.bukkit.block.BlockState;
|
||||||
import org.bukkit.entity.*;
|
import org.bukkit.entity.*;
|
||||||
import org.bukkit.inventory.ItemStack;
|
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) {
|
public static void printProgress(int convertedUsers, int progressInterval, long startMillis) {
|
||||||
if ((convertedUsers % progressInterval) == 0) {
|
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)));
|
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;
|
package com.gmail.nossr50.util.blockmeta;
|
||||||
|
|
||||||
|
import com.gmail.nossr50.util.Misc;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@ -10,12 +11,13 @@ import java.util.BitSet;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public class BitSetChunkStore implements ChunkStore {
|
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 static final int MAGIC_NUMBER = 0xEA5EDEBB;
|
||||||
|
|
||||||
private final int cx;
|
private final int cx;
|
||||||
private final int cz;
|
private final int cz;
|
||||||
private final int worldHeight;
|
private final int worldMin;
|
||||||
|
private final int worldMax;
|
||||||
private final @NotNull UUID worldUid;
|
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.
|
// 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;
|
private final @NotNull BitSet store;
|
||||||
@ -23,15 +25,16 @@ public class BitSetChunkStore implements ChunkStore {
|
|||||||
private transient boolean dirty = false;
|
private transient boolean dirty = false;
|
||||||
|
|
||||||
public BitSetChunkStore(@NotNull World world, int cx, int cz) {
|
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.cx = cx;
|
||||||
this.cz = cz;
|
this.cz = cz;
|
||||||
this.worldUid = worldUid;
|
this.worldUid = worldUid;
|
||||||
this.worldHeight = worldHeight;
|
this.worldMin = worldMin;
|
||||||
this.store = new BitSet(16 * 16 * worldHeight);
|
this.worldMax = worldMax;
|
||||||
|
this.store = new BitSet(16 * 16 * (worldMax - worldMin));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -54,6 +57,16 @@ public class BitSetChunkStore implements ChunkStore {
|
|||||||
return cz;
|
return cz;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getChunkMin() {
|
||||||
|
return worldMin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getChunkMax() {
|
||||||
|
return worldMax;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull UUID getWorldId() {
|
public @NotNull UUID getWorldId() {
|
||||||
return worldUid;
|
return worldUid;
|
||||||
@ -86,22 +99,34 @@ public class BitSetChunkStore implements ChunkStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private int coordToIndex(int x, int y, int z) {
|
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) {
|
private static int coordToIndex(int x, int y, int z, int worldMin, int worldMax) {
|
||||||
if (x < 0 || x >= 16 || y < 0 || y >= worldHeight || z < 0 || z >= 16)
|
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 Height: %d", x, y, z, worldHeight));
|
throw new IndexOutOfBoundsException(String.format("x: %d y: %d z: %d World Min: %d World Max: %d", x, y, z, worldMin, worldMax));
|
||||||
return (z * 16 + x) + (256 * y);
|
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);
|
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?
|
// 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)
|
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();
|
return world.getMaxHeight();
|
||||||
}
|
}
|
||||||
@ -114,7 +139,8 @@ public class BitSetChunkStore implements ChunkStore {
|
|||||||
out.writeLong(worldUid.getMostSignificantBits());
|
out.writeLong(worldUid.getMostSignificantBits());
|
||||||
out.writeInt(cx);
|
out.writeInt(cx);
|
||||||
out.writeInt(cz);
|
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
|
// Store the byte array directly so we don't have the object type info overhead
|
||||||
byte[] storeData = store.toByteArray();
|
byte[] storeData = store.toByteArray();
|
||||||
@ -129,7 +155,7 @@ public class BitSetChunkStore implements ChunkStore {
|
|||||||
// Can be used to determine the format of the file
|
// Can be used to determine the format of the file
|
||||||
int fileVersionNumber = in.readInt();
|
int fileVersionNumber = in.readInt();
|
||||||
|
|
||||||
if (magic != MAGIC_NUMBER || fileVersionNumber != CURRENT_VERSION)
|
if (magic != MAGIC_NUMBER || fileVersionNumber < 8)
|
||||||
throw new IOException();
|
throw new IOException();
|
||||||
|
|
||||||
long lsb = in.readLong();
|
long lsb = in.readLong();
|
||||||
@ -138,21 +164,38 @@ public class BitSetChunkStore implements ChunkStore {
|
|||||||
int cx = in.readInt();
|
int cx = in.readInt();
|
||||||
int cz = 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()];
|
byte[] temp = new byte[in.readInt()];
|
||||||
in.readFully(temp);
|
in.readFully(temp);
|
||||||
BitSet stored = BitSet.valueOf(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;
|
// 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 height has shrunk
|
// Lop off extra data if world max has shrunk
|
||||||
if (worldHeightShrunk)
|
if (currentWorldMax < worldMax)
|
||||||
stored.clear(coordToIndex(16, currentWorldHeight, 16, worldHeight), stored.length());
|
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.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;
|
return chunkStore;
|
||||||
}
|
}
|
||||||
@ -203,7 +246,7 @@ public class BitSetChunkStore implements ChunkStore {
|
|||||||
|
|
||||||
private int cx;
|
private int cx;
|
||||||
private int cz;
|
private int cz;
|
||||||
private int worldHeight;
|
private int worldMax;
|
||||||
private UUID worldUid;
|
private UUID worldUid;
|
||||||
private boolean[][][] store;
|
private boolean[][][] store;
|
||||||
|
|
||||||
@ -226,19 +269,20 @@ public class BitSetChunkStore implements ChunkStore {
|
|||||||
cz = in.readInt();
|
cz = in.readInt();
|
||||||
|
|
||||||
store = (boolean[][][]) in.readObject();
|
store = (boolean[][][]) in.readObject();
|
||||||
worldHeight = store[0][0].length;
|
worldMax = store[0][0].length;
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NotNull BitSetChunkStore convert()
|
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
|
// Read old data into new chunkstore
|
||||||
for (int x = 0; x < 16; x++) {
|
for (int x = 0; x < 16; x++) {
|
||||||
for (int z = 0; z < 16; z++) {
|
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]);
|
converted.store.set(converted.coordToIndex(x, y, z), store[x][z][y]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,9 @@ public interface ChunkStore {
|
|||||||
*/
|
*/
|
||||||
int getChunkZ();
|
int getChunkZ();
|
||||||
|
|
||||||
|
int getChunkMin();
|
||||||
|
int getChunkMax();
|
||||||
|
|
||||||
@NotNull UUID getWorldId();
|
@NotNull UUID getWorldId();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -454,6 +454,14 @@ Skills:
|
|||||||
Tree_Feller_Sounds: true
|
Tree_Feller_Sounds: true
|
||||||
Level_Cap: 0
|
Level_Cap: 0
|
||||||
|
|
||||||
|
# Disable or Enable the Green Thumb auto replant feature for specific crops, use the name of the block not the crop itemstack
|
||||||
|
Green_Thumb_Replanting_Crops:
|
||||||
|
Carrots: true
|
||||||
|
Wheat: true
|
||||||
|
Nether_Wart: true
|
||||||
|
Potatoes: true
|
||||||
|
Beetroots: true
|
||||||
|
Cocoa: true
|
||||||
#
|
#
|
||||||
# Settings for Double Drops
|
# Settings for Double Drops
|
||||||
###
|
###
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,7 @@
|
|||||||
package com.gmail.nossr50.util.blockmeta;
|
package com.gmail.nossr50.util.blockmeta;
|
||||||
|
|
||||||
import com.gmail.nossr50.TestUtil;
|
import com.gmail.nossr50.TestUtil;
|
||||||
|
import com.gmail.nossr50.util.Misc;
|
||||||
import com.google.common.io.Files;
|
import com.google.common.io.Files;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
@ -22,7 +23,7 @@ import static org.mockito.Mockito.mock;
|
|||||||
* 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.
|
* 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.
|
||||||
*/
|
*/
|
||||||
@RunWith(PowerMockRunner.class)
|
@RunWith(PowerMockRunner.class)
|
||||||
@PrepareForTest(Bukkit.class)
|
@PrepareForTest({ Bukkit.class, Misc.class })
|
||||||
public class ChunkStoreTest {
|
public class ChunkStoreTest {
|
||||||
private static File tempDir;
|
private static File tempDir;
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
@ -76,6 +77,34 @@ public class ChunkStoreTest {
|
|||||||
assertEqual(original, deserialized);
|
assertEqual(original, deserialized);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNegativeWorldMin() throws IOException {
|
||||||
|
PowerMockito.mockStatic(Misc.class);
|
||||||
|
Mockito.when(Misc.getWorldMinCompat(mockWorld)).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
|
||||||
|
public 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);
|
||||||
|
|
||||||
|
PowerMockito.mockStatic(Misc.class);
|
||||||
|
Mockito.when(Misc.getWorldMinCompat(mockWorld)).thenReturn(-64);
|
||||||
|
ChunkStore deserialized = BitSetChunkStore.Serialization.readChunkStore(new DataInputStream(new ByteArrayInputStream(serializedBytes)));
|
||||||
|
assertEqualIgnoreMinMax(original, deserialized);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testChunkCoords() throws IOException {
|
public void testChunkCoords() throws IOException {
|
||||||
for (int x = -96; x < 0; x++) {
|
for (int x = -96; x < 0; x++) {
|
||||||
@ -175,15 +204,26 @@ public class ChunkStoreTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void assertEqual(ChunkStore expected, ChunkStore actual)
|
private void assertEqual(ChunkStore expected, ChunkStore actual)
|
||||||
|
{
|
||||||
|
Assert.assertEquals(expected.getChunkMin(), actual.getChunkMin());
|
||||||
|
Assert.assertEquals(expected.getChunkMax(), actual.getChunkMax());
|
||||||
|
assertEqualIgnoreMinMax(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertEqualIgnoreMinMax(ChunkStore expected, ChunkStore actual)
|
||||||
{
|
{
|
||||||
Assert.assertEquals(expected.getChunkX(), actual.getChunkX());
|
Assert.assertEquals(expected.getChunkX(), actual.getChunkX());
|
||||||
Assert.assertEquals(expected.getChunkZ(), actual.getChunkZ());
|
Assert.assertEquals(expected.getChunkZ(), actual.getChunkZ());
|
||||||
Assert.assertEquals(expected.getWorldId(), actual.getWorldId());
|
Assert.assertEquals(expected.getWorldId(), actual.getWorldId());
|
||||||
for (int y = 0; y < 256; y++)
|
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 x = 0; x < 16; x++)
|
||||||
for (int z = 0; z < 16; z++)
|
for (int z = 0; z < 16; z++)
|
||||||
Assert.assertTrue(expected.isTrue(x, y, z) == actual.isTrue(x, y, z));
|
Assert.assertTrue(expected.isTrue(x, y, z) == actual.isTrue(x, y, z));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static byte[] serializeChunkstore(@NotNull ChunkStore chunkStore) throws IOException {
|
private static byte[] serializeChunkstore(@NotNull ChunkStore chunkStore) throws IOException {
|
||||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||||
@ -231,6 +271,16 @@ public class ChunkStoreTest {
|
|||||||
return cz;
|
return cz;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getChunkMin() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getChunkMax() {
|
||||||
|
return store[0][0].length;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull UUID getWorldId() {
|
public @NotNull UUID getWorldId() {
|
||||||
return worldUid;
|
return worldUid;
|
||||||
|
Loading…
Reference in New Issue
Block a user