mirror of
https://github.com/mcMMO-Dev/mcMMO.git
synced 2024-11-24 14:16:45 +01:00
Merge branch 'master' of github.com:mcMMO-Dev/mcMMO into tridentsxbows
This commit is contained in:
commit
7c270feacb
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
|
@ -103,7 +103,15 @@ Version 2.2.000
|
|||||||
Parties got unnecessarily complex in my absence, I have removed many party features in order to simplify parties and bring them closer to my vision. I have also added new features which should improve parties where it matters.
|
Parties got unnecessarily complex in my absence, I have removed many party features in order to simplify parties and bring them closer to my vision. I have also added new features which should improve parties where it matters.
|
||||||
About the removed party features, all the features I removed I consider poor quality features and I don't think they belong in mcMMO. Feel free to yell at me in discord if you disagree.
|
About the removed party features, all the features I removed I consider poor quality features and I don't think they belong in mcMMO. Feel free to yell at me in discord if you disagree.
|
||||||
I don't know what genius decided to make parties public by default, when I found out that parties had been changed to such a system I could barely contain my disgust. Parties are back to being private, you get invited by a party leader or party officer. That is the only way to join a party.
|
I don't know what genius decided to make parties public by default, when I found out that parties had been changed to such a system I could barely contain my disgust. Parties are back to being private, you get invited by a party leader or party officer. That is the only way to join a party.
|
||||||
|
Version 2.1.176
|
||||||
|
Added another measure to prevent item stacks from reaching 65 from double smelt
|
||||||
|
|
||||||
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
|
||||||
|
Updated Adventure (our text dependency) fixes some errors when using color codes in party/admin chat (thanks TheBusyBiscuit)
|
||||||
|
Added some support for negative Y values in anticipation of 1.17 world height changes (thanks t00thpick1)
|
||||||
|
|
||||||
Version 2.1.174
|
Version 2.1.174
|
||||||
Some legacy color codes in our locale file were swapped to &-code equivalents (thanks ViaSnake)
|
Some legacy color codes in our locale file were swapped to &-code equivalents (thanks ViaSnake)
|
||||||
|
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>
|
||||||
@ -235,27 +236,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>
|
||||||
@ -280,13 +281,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>
|
||||||
@ -334,7 +335,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>
|
||||||
|
@ -612,4 +612,7 @@ public class Config extends AutoUpdateConfigLoader {
|
|||||||
public int getPowerLevelUpBroadcastRadius() { return config.getInt("General.Level_Up_Chat_Broadcasts.Broadcast_Powerlevels.Broadcast_Targets.Distance_Restrictions.Restricted_Radius", 100); }
|
public int getPowerLevelUpBroadcastRadius() { return config.getInt("General.Level_Up_Chat_Broadcasts.Broadcast_Powerlevels.Broadcast_Targets.Distance_Restrictions.Restricted_Radius", 100); }
|
||||||
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 isGreenThumbReplantableCrop(@NotNull Material material) {
|
||||||
|
return config.getBoolean("Green_Thumb_Replanting_Crops." + StringUtils.getCapitalized(material.toString()), true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -147,10 +147,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);
|
||||||
mcMMO.getPlaceStore().setTrue(movedBlock);
|
if (movedBlock.getY() >= Misc.getWorldMinCompat(movedBlock.getWorld())) // Very weird that the event is giving us these, they shouldn't exist
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -207,14 +207,10 @@ public class EntityListener implements Listener {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Check both hands
|
||||||
//Bow only
|
if(ItemUtils.doesPlayerHaveEnchantmentInHands(player, "piercing")) {
|
||||||
if (!isCrossbow) {
|
return;
|
||||||
for (Enchantment enchantment : player.getInventory().getItemInMainHand().getEnchantments().keySet()) {
|
}
|
||||||
if (enchantment.getKey().equals(piercingEnchantment)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.ARCHERY_ARROW_RETRIEVAL, player)) {
|
if (RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.ARCHERY_ARROW_RETRIEVAL, player)) {
|
||||||
projectile.setMetadata(mcMMO.trackedArrow, mcMMO.metadataValue);
|
projectile.setMetadata(mcMMO.trackedArrow, mcMMO.metadataValue);
|
||||||
|
@ -115,7 +115,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, furnace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,6 +55,7 @@ import com.neetgames.mcmmo.party.PartyManager;
|
|||||||
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;
|
||||||
@ -68,6 +69,7 @@ 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;
|
||||||
|
|
||||||
@ -129,24 +131,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 final static String bredMetadataKey = "mcMMO: Bred Animal";
|
public final static String bredMetadataKey = "mcMMO: Bred Animal";
|
||||||
public final static String PROJECTILE_ORIGIN_METAKEY = "mcMMO: Projectile Origin";
|
public final static String PROJECTILE_ORIGIN_METAKEY = "mcMMO: Projectile Origin";
|
||||||
|
|
||||||
@ -168,7 +170,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();
|
||||||
@ -260,12 +264,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) {
|
||||||
@ -279,6 +283,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
|
||||||
@ -295,6 +302,8 @@ public class mcMMO extends JavaPlugin {
|
|||||||
|
|
||||||
//Init Player Data Manager
|
//Init Player Data Manager
|
||||||
userManager = new UserManager();
|
userManager = new UserManager();
|
||||||
|
|
||||||
|
//Set up Adventure's audiences
|
||||||
audiences = BukkitAudiences.create(this);
|
audiences = BukkitAudiences.create(this);
|
||||||
|
|
||||||
transientMetadataTools = new TransientMetadataTools(this);
|
transientMetadataTools = new TransientMetadataTools(this);
|
||||||
@ -358,8 +367,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.
|
||||||
@ -369,14 +379,12 @@ public class mcMMO extends JavaPlugin {
|
|||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
getLogger().severe(e.toString());
|
getLogger().severe(e.toString());
|
||||||
}
|
}
|
||||||
|
catch(NoClassDefFoundError e) {
|
||||||
|
getLogger().severe("Backup class not found!");
|
||||||
|
getLogger().info("Please do not replace the mcMMO jar while the server is running.");
|
||||||
|
}
|
||||||
catch (Throwable e) {
|
catch (Throwable e) {
|
||||||
if (e instanceof NoClassDefFoundError) {
|
getLogger().severe(e.toString());
|
||||||
getLogger().severe("Backup class not found!");
|
|
||||||
getLogger().info("Please do not replace the mcMMO jar while the server is running.");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
getLogger().severe(e.toString());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -656,7 +664,7 @@ public class mcMMO extends JavaPlugin {
|
|||||||
|
|
||||||
public @Nullable InputStreamReader getResourceAsReader(String fileName) {
|
public @Nullable InputStreamReader getResourceAsReader(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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -180,8 +180,10 @@ 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(!getPlayer().isSneaking()) {
|
if(Config.getInstance().isGreenThumbReplantableCrop(originalBreak.getType())) {
|
||||||
greenThumbActivated = processGreenThumbPlants(originalBreak, blockBreakEvent, isGreenTerraActive());
|
if(!getPlayer().isSneaking()) {
|
||||||
|
greenThumbActivated = processGreenThumbPlants(originalBreak, blockBreakEvent, isGreenTerraActive());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -686,7 +688,7 @@ public class HerbalismManager extends SkillManager {
|
|||||||
*/
|
*/
|
||||||
private boolean processGreenThumbPlants(BlockState blockState, BlockBreakEvent blockBreakEvent, boolean greenTerra) {
|
private boolean processGreenThumbPlants(BlockState blockState, BlockBreakEvent blockBreakEvent, boolean greenTerra) {
|
||||||
if (!ItemUtils.isHoe(blockBreakEvent.getPlayer().getInventory().getItemInMainHand())
|
if (!ItemUtils.isHoe(blockBreakEvent.getPlayer().getInventory().getItemInMainHand())
|
||||||
&& !ItemUtils.isAxe(blockBreakEvent.getPlayer().getInventory().getItemInMainHand())) {
|
&& !ItemUtils.isAxe(blockBreakEvent.getPlayer().getInventory().getItemInMainHand())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,8 +9,12 @@ import com.gmail.nossr50.util.Permissions;
|
|||||||
import com.gmail.nossr50.util.random.RandomChanceUtil;
|
import com.gmail.nossr50.util.random.RandomChanceUtil;
|
||||||
import com.gmail.nossr50.util.skills.RankUtils;
|
import com.gmail.nossr50.util.skills.RankUtils;
|
||||||
import com.gmail.nossr50.util.skills.SkillActivationType;
|
import com.gmail.nossr50.util.skills.SkillActivationType;
|
||||||
|
import org.bukkit.block.Furnace;
|
||||||
import org.bukkit.event.inventory.FurnaceBurnEvent;
|
import org.bukkit.event.inventory.FurnaceBurnEvent;
|
||||||
|
import org.bukkit.event.inventory.FurnaceSmeltEvent;
|
||||||
|
import org.bukkit.inventory.FurnaceInventory;
|
||||||
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(OnlineMMOPlayer mmoPlayer) {
|
public SmeltingManager(OnlineMMOPlayer mmoPlayer) {
|
||||||
@ -106,19 +110,41 @@ public class SmeltingManager extends SkillManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ItemStack smeltProcessing(ItemStack smelting, ItemStack result) {
|
public void smeltProcessing(@NotNull FurnaceSmeltEvent furnaceSmeltEvent, @NotNull Furnace furnace) {
|
||||||
|
applyXpGain(Smelting.getResourceXp(furnaceSmeltEvent.getSource()), XPGainReason.PVE, XPGainSource.PASSIVE); //Add XP
|
||||||
|
|
||||||
applyXpGain(Smelting.getResourceXp(smelting), XPGainReason.PVE, XPGainSource.PASSIVE);
|
processDoubleSmelt(furnaceSmeltEvent, furnace);
|
||||||
|
}
|
||||||
|
|
||||||
if (Config.getInstance().getDoubleDropsEnabled(PrimarySkillType.SMELTING, result.getType())
|
private void processDoubleSmelt(@NotNull FurnaceSmeltEvent furnaceSmeltEvent, @NotNull Furnace furnace) {
|
||||||
&& isSecondSmeltSuccessful() && result.getAmount() < 64) {
|
ItemStack resultItemStack = furnaceSmeltEvent.getResult();
|
||||||
ItemStack newResult = result.clone();
|
/*
|
||||||
|
doubleSmeltCondition should be equal to the max
|
||||||
|
*/
|
||||||
|
|
||||||
newResult.setAmount(result.getAmount() + 1);
|
//Process double smelt
|
||||||
return newResult;
|
if (Config.getInstance().getDoubleDropsEnabled(PrimarySkillType.SMELTING, resultItemStack.getType())
|
||||||
|
&& canDoubleSmeltItemStack(furnace) //Effectively two less than max stack size
|
||||||
|
&& isSecondSmeltSuccessful()) {
|
||||||
|
|
||||||
|
ItemStack doubleSmeltStack = resultItemStack.clone(); //TODO: Necessary?
|
||||||
|
doubleSmeltStack.setAmount(resultItemStack.getAmount() + 1); //Add one
|
||||||
|
furnaceSmeltEvent.setResult(doubleSmeltStack); //Set result
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
private boolean canDoubleSmeltItemStack(@NotNull Furnace furnace) {
|
||||||
|
FurnaceInventory furnaceInventory = furnace.getInventory();
|
||||||
|
ItemStack furnaceResult = furnaceInventory.getResult();
|
||||||
|
|
||||||
|
if(furnaceResult == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int resultAmount = furnaceResult.getAmount(); //Amount before double smelt
|
||||||
|
int itemLimit = furnaceResult.getMaxStackSize();
|
||||||
|
int doubleSmeltCondition = itemLimit - 2; //Don't double smelt if it would cause an illegal stack size
|
||||||
|
|
||||||
|
return resultAmount <= doubleSmeltCondition;
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
@ -58,11 +60,99 @@ public final class ItemUtils {
|
|||||||
return player.getInventory().getItemInMainHand().getType().getKey().getKey().equalsIgnoreCase(id);
|
return player.getInventory().getItemInMainHand().getType().getKey().getKey().equalsIgnoreCase(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 hasItemInOffHand(@NotNull Player player, @NotNull String id) {
|
public static boolean hasItemInOffHand(@NotNull Player player, @NotNull String id) {
|
||||||
return player.getInventory().getItemInOffHand().getType().getKey().getKey().equalsIgnoreCase(id);
|
return player.getInventory().getItemInOffHand().getType().getKey().getKey().equalsIgnoreCase(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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,7 +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> xbows;
|
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,7 +88,7 @@ public class MaterialMapStore {
|
|||||||
diamondTools = new HashSet<>();
|
diamondTools = new HashSet<>();
|
||||||
netheriteTools = new HashSet<>();
|
netheriteTools = new HashSet<>();
|
||||||
bows = new HashSet<>();
|
bows = new HashSet<>();
|
||||||
xbows = new HashSet<>();
|
crossbows = new HashSet<>();
|
||||||
stringTools = new HashSet<>();
|
stringTools = new HashSet<>();
|
||||||
tools = new HashSet<>();
|
tools = new HashSet<>();
|
||||||
|
|
||||||
@ -459,15 +459,15 @@ public class MaterialMapStore {
|
|||||||
tools.addAll(tridents);
|
tools.addAll(tridents);
|
||||||
tools.addAll(stringTools);
|
tools.addAll(stringTools);
|
||||||
tools.addAll(bows);
|
tools.addAll(bows);
|
||||||
tools.addAll(xbows);
|
tools.addAll(crossbows);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fillBows() {
|
private void fillBows() {
|
||||||
bows.add("bow");
|
bows.add("bow");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fillCrossBows() {
|
private void fillCrossbows() {
|
||||||
xbows.add("crossbow");
|
crossbows.add("crossbow");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fillStringTools() {
|
private void fillStringTools() {
|
||||||
@ -782,7 +782,7 @@ public class MaterialMapStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isCrossbow(@NotNull String id) {
|
public boolean isCrossbow(@NotNull String id) {
|
||||||
return xbows.contains(id);
|
return crossbows.contains(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isLeatherArmor(@NotNull Material material) {
|
public boolean isLeatherArmor(@NotNull Material material) {
|
||||||
|
@ -8,6 +8,7 @@ import com.gmail.nossr50.runnables.player.PlayerProfileLoadingTask;
|
|||||||
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;
|
||||||
@ -258,6 +259,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();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -459,6 +459,14 @@ Skills:
|
|||||||
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,14 +204,25 @@ 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 {
|
||||||
@ -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