mirror of
https://github.com/mcMMO-Dev/mcMMO.git
synced 2024-11-24 22:26:46 +01:00
Merge branch 'master' of github.com:mcMMO-Dev/mcMMO into tridentsxbows
This commit is contained in:
commit
4e8262d818
@ -99,15 +99,50 @@ 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.165
|
Version 2.1.168
|
||||||
The mcMMO system which tracks player placed blocks has had some major rewrites (thanks t00thpick1)
|
Fixed an IndexOutOfBoundsException error when trying to access UserBlockTracker from an invalid range (thanks t00thpick1)
|
||||||
mcMMO will now be compatible with changes to world height (1.17 compatibility)
|
(API) UserBlockTracker is now the interface by which our block-tracker will be known (thanks t00thpick1)
|
||||||
Added missing cooldown locale message 'Commands.Database.Cooldown'
|
|
||||||
|
Version 2.1.167
|
||||||
|
Fixed a serious dupe bug
|
||||||
|
Add McMMOPlayerPreXpGainEvent event for plugins to modify given exp (thanks electronicboy)
|
||||||
|
Add SkillActivationPerkEvent (thanks electronicboy)
|
||||||
|
|
||||||
|
NOTE:
|
||||||
|
This bug was introduced in 2.1.165, update immediately if you are on 2.1.165 or 2.1.166
|
||||||
|
|
||||||
|
Version 2.1.166
|
||||||
|
Fixed a small memory leak in the new COTW tracker
|
||||||
|
Potentially fixed a ConcurrentModificationException involving the TransientEntityTracker (report this error if you encounter it)
|
||||||
|
Music discs removed from the default fishing_treasures.yml
|
||||||
|
Optimized how mcMMO saves player data (should improve timings on servers with bad disk speeds and or bad connectivity to their SQL server instance)
|
||||||
|
|
||||||
NOTES:
|
NOTES:
|
||||||
|
No one likes fishing up music discs, if you want this change it is recommended you delete fishing_treasures.yml and let it regenerate
|
||||||
|
(You won't have this file if you haven't updated in a while, if so you don't need to do anything)
|
||||||
|
If any of you encounter a ConcurrentModificationException error that mentions TransientEntityTracker in its stack trace after this update let me know, I have another fix in mind for this if this update didn't fix it.
|
||||||
|
|
||||||
|
Version 2.1.165
|
||||||
|
Fixed a bug where Enchanted Books dropped by mcMMO (in Fishing) did not function correctly
|
||||||
|
The mcMMO system which tracks player placed blocks has had some major rewrites (thanks t00thpick1)
|
||||||
|
Optimized our ChunkUnloadEvent, this should improve timings in this area
|
||||||
|
How mcMMO tracks COTW entities has been rewritten
|
||||||
|
When COTW summons are killed players are now informed (from anything other than the time expiring).
|
||||||
|
mcMMO will now be compatible with changes to world height (1.17 compatibility)
|
||||||
|
mcMMO will ignore EntityPickupItemEvents from "Fake-Player" NPCs if it recognizes them as such, this will prevent some compatibility issues with some plugins
|
||||||
|
SuperBreaker will now always activate if the target blocks fastest tool is a Pickaxe (used to require the block giving XP or being considered an ore)
|
||||||
|
Master Angler mentions that it works better with a boat in its hover tip
|
||||||
|
Added missing cooldown locale message 'Commands.Database.Cooldown'
|
||||||
|
Added new locale message 'Taming.Summon.COTW.Removed'
|
||||||
|
Updated locale entry 'Fishing.SubSkill.MasterAngler.Description'
|
||||||
|
|
||||||
|
NOTES:
|
||||||
|
Books dropped before this fix will not be usable and should just be chucked in lava, the broken books have blue names, the working books have yellow names.
|
||||||
t00thpick1 has taken time to rewrite our block meta tracking system to be more efficient, easier to maintain, and support upcoming features such as world height changes
|
t00thpick1 has taken time to rewrite our block meta tracking system to be more efficient, easier to maintain, and support upcoming features such as world height changes
|
||||||
This new system is compatible with the old one, it will convert old files to the new format as needed.
|
This new system is compatible with the old one, it will convert old files to the new format as needed. You won't even know it is doing anything.
|
||||||
This update shouldn't break anything as the API is the same
|
This update shouldn't break anything as the API is the same.
|
||||||
|
|
||||||
|
Alright back to work on T&C unless some major bugs come out of this...
|
||||||
|
|
||||||
Version 2.1.164
|
Version 2.1.164
|
||||||
mcMMO will now let players use vanilla blocks that have interactions (such as the vanilla Anvil) which are assigned as either Repair or Salvage blocks if a player is sneaking (see notes)
|
mcMMO will now let players use vanilla blocks that have interactions (such as the vanilla Anvil) which are assigned as either Repair or Salvage blocks if a player is sneaking (see notes)
|
||||||
|
4
pom.xml
4
pom.xml
@ -124,6 +124,10 @@
|
|||||||
</artifactSet>
|
</artifactSet>
|
||||||
<!-- <dependencyReducedPomLocation>${project.build.directory}/dependency-reduced-pom.xml</dependencyReducedPomLocation>-->
|
<!-- <dependencyReducedPomLocation>${project.build.directory}/dependency-reduced-pom.xml</dependencyReducedPomLocation>-->
|
||||||
<relocations>
|
<relocations>
|
||||||
|
<relocation>
|
||||||
|
<pattern>net.kyori.examination</pattern>
|
||||||
|
<shadedPattern>com.gmail.nossr50.kyori.examination</shadedPattern>
|
||||||
|
</relocation>
|
||||||
<relocation>
|
<relocation>
|
||||||
<pattern>net.kyori.adventure</pattern>
|
<pattern>net.kyori.adventure</pattern>
|
||||||
<shadedPattern>com.gmail.nossr50.mcmmo.kyori.adventure</shadedPattern>
|
<shadedPattern>com.gmail.nossr50.mcmmo.kyori.adventure</shadedPattern>
|
||||||
|
@ -0,0 +1,50 @@
|
|||||||
|
package com.gmail.nossr50.events.experience;
|
||||||
|
|
||||||
|
import com.gmail.nossr50.datatypes.experience.XPGainReason;
|
||||||
|
import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.HandlerList;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a player gains XP in a skill
|
||||||
|
*/
|
||||||
|
public class McMMOPlayerPreXpGainEvent extends McMMOPlayerExperienceEvent {
|
||||||
|
private float xpGained;
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public McMMOPlayerPreXpGainEvent(Player player, PrimarySkillType skill, float xpGained) {
|
||||||
|
super(player, skill, XPGainReason.UNKNOWN);
|
||||||
|
this.xpGained = xpGained;
|
||||||
|
}
|
||||||
|
|
||||||
|
public McMMOPlayerPreXpGainEvent(Player player, PrimarySkillType skill, float xpGained, XPGainReason xpGainReason) {
|
||||||
|
super(player, skill, xpGainReason);
|
||||||
|
this.xpGained = xpGained;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return int amount of experience gained in this event
|
||||||
|
*/
|
||||||
|
public int getXpGained() {
|
||||||
|
return (int) xpGained;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param xpGained int amount of experience gained in this event
|
||||||
|
*/
|
||||||
|
public void setXpGained(int xpGained) {
|
||||||
|
this.xpGained = xpGained;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final HandlerList handlers = new HandlerList();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull HandlerList getHandlers() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HandlerList getHandlerList() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
package com.gmail.nossr50.events.skills;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.Event;
|
||||||
|
import org.bukkit.event.HandlerList;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public class SkillActivationPerkEvent extends Event {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private static final HandlerList handlers = new HandlerList();
|
||||||
|
private final Player player;
|
||||||
|
private int ticks;
|
||||||
|
private final int maxTicks;
|
||||||
|
|
||||||
|
public SkillActivationPerkEvent(Player player, int ticks, int maxTicks) {
|
||||||
|
|
||||||
|
this.player = player;
|
||||||
|
this.ticks = ticks;
|
||||||
|
this.maxTicks = maxTicks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Player getPlayer() {
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTicks() {
|
||||||
|
return ticks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTicks(int ticks) {
|
||||||
|
this.ticks = ticks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxTicks() {
|
||||||
|
return maxTicks;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull HandlerList getHandlers() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HandlerList getHandlerList() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
}
|
@ -252,12 +252,18 @@ public class BlockListener implements Listener {
|
|||||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||||
public void onBlockGrow(BlockGrowEvent event)
|
public void onBlockGrow(BlockGrowEvent event)
|
||||||
{
|
{
|
||||||
|
Block block = event.getBlock();
|
||||||
|
World world = block.getWorld();
|
||||||
|
|
||||||
/* WORLD BLACKLIST CHECK */
|
/* WORLD BLACKLIST CHECK */
|
||||||
if(WorldBlacklist.isWorldBlacklisted(event.getBlock().getWorld()))
|
if(WorldBlacklist.isWorldBlacklisted(world))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
BlockState blockState = event.getBlock().getState();
|
// Minecraft is dumb, the events still throw when a plant "grows" higher than the max block height. Even though no new block is created
|
||||||
mcMMO.getPlaceStore().setFalse(blockState);
|
if (block.getY() >= world.getMaxHeight())
|
||||||
|
return;
|
||||||
|
|
||||||
|
mcMMO.getPlaceStore().setFalse(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,30 +1,20 @@
|
|||||||
package com.gmail.nossr50.listeners;
|
package com.gmail.nossr50.listeners;
|
||||||
|
|
||||||
import com.gmail.nossr50.mcMMO;
|
import com.gmail.nossr50.mcMMO;
|
||||||
import com.gmail.nossr50.util.compat.layers.persistentdata.MobMetaFlagType;
|
|
||||||
import org.bukkit.entity.Entity;
|
|
||||||
import org.bukkit.entity.LivingEntity;
|
import org.bukkit.entity.LivingEntity;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.world.ChunkUnloadEvent;
|
import org.bukkit.event.world.ChunkUnloadEvent;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class ChunkListener implements Listener {
|
public class ChunkListener implements Listener {
|
||||||
|
|
||||||
@EventHandler(ignoreCancelled = true)
|
@EventHandler(ignoreCancelled = true)
|
||||||
public void onChunkUnload(ChunkUnloadEvent event) {
|
public void onChunkUnload(ChunkUnloadEvent event) {
|
||||||
for(Entity entity : event.getChunk().getEntities()) {
|
List<LivingEntity> matchingEntities = mcMMO.getTransientEntityTracker().getAllTransientEntitiesInChunk(event.getChunk());
|
||||||
if(entity instanceof LivingEntity) {
|
for(LivingEntity livingEntity : matchingEntities) {
|
||||||
LivingEntity livingEntity = (LivingEntity) entity;
|
mcMMO.getTransientEntityTracker().removeSummon(livingEntity, null, false);
|
||||||
if(mcMMO.getCompatibilityManager().getPersistentDataLayer().hasMobFlag(MobMetaFlagType.COTW_SUMMONED_MOB, livingEntity)) {
|
|
||||||
|
|
||||||
//Remove from existence
|
|
||||||
if(livingEntity.isValid()) {
|
|
||||||
mcMMO.getCompatibilityManager().getPersistentDataLayer().removeMobFlags(livingEntity);
|
|
||||||
livingEntity.setHealth(0);
|
|
||||||
livingEntity.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -689,12 +689,17 @@ public class EntityListener implements Listener {
|
|||||||
*/
|
*/
|
||||||
@EventHandler(ignoreCancelled = true)
|
@EventHandler(ignoreCancelled = true)
|
||||||
public void onEntityDeath(EntityDeathEvent event) {
|
public void onEntityDeath(EntityDeathEvent event) {
|
||||||
/* WORLD BLACKLIST CHECK */
|
|
||||||
if(WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld()))
|
|
||||||
return;
|
|
||||||
|
|
||||||
LivingEntity entity = event.getEntity();
|
LivingEntity entity = event.getEntity();
|
||||||
|
|
||||||
|
if(mcMMO.getTransientEntityTracker().isTransientSummon(entity)) {
|
||||||
|
mcMMO.getTransientEntityTracker().removeSummon(entity, null, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* WORLD BLACKLIST CHECK */
|
||||||
|
if(WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (ExperienceConfig.getInstance().isNPCInteractionPrevented() && Misc.isNPCEntityExcludingVillagers(entity)) {
|
if (ExperienceConfig.getInstance().isNPCInteractionPrevented() && Misc.isNPCEntityExcludingVillagers(entity)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -448,6 +448,10 @@ public class PlayerListener implements Listener {
|
|||||||
if(WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld()))
|
if(WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld()))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if(Misc.isNPCEntityExcludingVillagers(event.getEntity())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(event.getEntity() instanceof Player)
|
if(event.getEntity() instanceof Player)
|
||||||
{
|
{
|
||||||
Player player = (Player) event.getEntity();
|
Player player = (Player) event.getEntity();
|
||||||
@ -463,14 +467,13 @@ public class PlayerListener implements Listener {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OnlineMMOPlayer mmoPlayer = mcMMO.getUserManager().queryPlayer(player);
|
||||||
|
|
||||||
//Profile not loaded
|
//Profile not loaded
|
||||||
if(mcMMO.getUserManager().queryPlayer(player) == null)
|
if(mmoPlayer == null) {
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
OnlineMMOPlayer mmoPlayer = mcMMO.getUserManager().queryPlayer(player);
|
|
||||||
|
|
||||||
Item drop = event.getItem();
|
Item drop = event.getItem();
|
||||||
ItemStack dropStack = drop.getItemStack();
|
ItemStack dropStack = drop.getItemStack();
|
||||||
|
|
||||||
@ -525,18 +528,32 @@ public class PlayerListener implements Listener {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
|
||||||
|
|
||||||
//Profile not loaded
|
//Profile not loaded
|
||||||
OnlineMMOPlayer mmoPlayer = mcMMO.getUserManager().queryPlayer(player);
|
McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryPlayer(player);
|
||||||
|
|
||||||
if(mmoPlayer == null) {
|
if(mmoPlayer == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: There's an issue with using Async saves on player quit
|
mcMMO.getUserManager().saveUserImmediately(mmoPlayer, mcMMO.isServerShutdownExecuted());
|
||||||
//TODO: Basically there are conditions in which an async task does not execute fast enough to save the data if the server shutdown shortly after this task was scheduled
|
//Use a sync save if the server is shutting down to avoid race conditions
|
||||||
mcMMO.getUserManager().saveUserWithDelay(mmoPlayer.getMMOPlayerData(), false, 20);
|
//TODO: Make sure this cleans up
|
||||||
|
//TODO: Make sure this cleans up
|
||||||
mcMMO.getUserManager().cleanupPlayer(mmoPlayer); //Handles cleaning up the player when their profile is no longer needed
|
//TODO: Make sure this cleans up
|
||||||
|
//TODO: Make sure this cleans up
|
||||||
|
//TODO: Make sure this cleans up
|
||||||
|
//TODO: Make sure this cleans up
|
||||||
|
//TODO: Make sure this cleans up
|
||||||
|
//TODO: Make sure this cleans up
|
||||||
|
//TODO: Make sure this cleans up
|
||||||
|
//TODO: Make sure this cleans up
|
||||||
|
//TODO: Make sure this cleans up
|
||||||
|
//TODO: Make sure this cleans up
|
||||||
|
//TODO: Make sure this cleans up
|
||||||
|
//TODO: Make sure this cleans up
|
||||||
|
mmoPlayer.logout(mcMMO.isServerShutdownExecuted());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -91,6 +91,8 @@ public class mcMMO extends JavaPlugin {
|
|||||||
private static ChatManager chatManager;
|
private static ChatManager chatManager;
|
||||||
private static CommandManager commandManager; //ACF
|
private static CommandManager commandManager; //ACF
|
||||||
private static SkillRegister skillRegister;
|
private static SkillRegister skillRegister;
|
||||||
|
private static TransientEntityTracker transientEntityTracker;
|
||||||
|
private static boolean serverShutdownExecuted = false;
|
||||||
|
|
||||||
/* Adventure */
|
/* Adventure */
|
||||||
private static BukkitAudiences audiences;
|
private static BukkitAudiences audiences;
|
||||||
@ -299,6 +301,9 @@ public class mcMMO extends JavaPlugin {
|
|||||||
chatManager = new ChatManager(this);
|
chatManager = new ChatManager(this);
|
||||||
|
|
||||||
commandManager = new CommandManager(this);
|
commandManager = new CommandManager(this);
|
||||||
|
|
||||||
|
transientEntityTracker = new TransientEntityTracker();
|
||||||
|
setServerShutdown(false); //Reset flag, used to make decisions about async saves
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PlayerLevelUtils getPlayerLevelUtils() {
|
public static PlayerLevelUtils getPlayerLevelUtils() {
|
||||||
@ -334,6 +339,10 @@ public class mcMMO extends JavaPlugin {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void onDisable() {
|
public void onDisable() {
|
||||||
|
setServerShutdown(true);
|
||||||
|
//TODO: Write code to catch unfinished async save tasks, for now we just hope they finish in time, which they should in most cases
|
||||||
|
mcMMO.p.getLogger().info("Server shutdown has been executed, saving and cleaning up data...");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
userManager.saveAllSync(); // Make sure to save player information if the server shuts down
|
userManager.saveAllSync(); // Make sure to save player information if the server shuts down
|
||||||
userManager.clearAll();
|
userManager.clearAll();
|
||||||
@ -346,17 +355,11 @@ public class mcMMO extends JavaPlugin {
|
|||||||
|
|
||||||
formulaManager.saveFormula();
|
formulaManager.saveFormula();
|
||||||
holidayManager.saveAnniversaryFiles();
|
holidayManager.saveAnniversaryFiles();
|
||||||
placeStore.cleanUp(); // Cleanup empty metadata stores
|
|
||||||
placeStore.closeAll();
|
placeStore.closeAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (Exception e) { e.printStackTrace(); }
|
catch (Exception e) { e.printStackTrace(); }
|
||||||
|
|
||||||
debug("Canceling all tasks...");
|
|
||||||
getServer().getScheduler().cancelTasks(this); // This removes our tasks
|
|
||||||
debug("Unregister all events...");
|
|
||||||
HandlerList.unregisterAll(this); // Cancel event registrations
|
|
||||||
|
|
||||||
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.
|
||||||
try {
|
try {
|
||||||
@ -376,6 +379,11 @@ public class mcMMO extends JavaPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug("Canceling all tasks...");
|
||||||
|
getServer().getScheduler().cancelTasks(this); // This removes our tasks
|
||||||
|
debug("Unregister all events...");
|
||||||
|
HandlerList.unregisterAll(this); // Cancel event registrations
|
||||||
|
|
||||||
databaseManager.onDisable();
|
databaseManager.onDisable();
|
||||||
debug("Was disabled."); // How informative!
|
debug("Was disabled."); // How informative!
|
||||||
}
|
}
|
||||||
@ -704,5 +712,18 @@ public class mcMMO extends JavaPlugin {
|
|||||||
return commandManager;
|
return commandManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static TransientEntityTracker getTransientEntityTracker() {
|
||||||
|
return transientEntityTracker;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static synchronized boolean isServerShutdownExecuted() {
|
||||||
|
return serverShutdownExecuted;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static synchronized void setServerShutdown(boolean bool) {
|
||||||
|
serverShutdownExecuted = bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public @NotNull SkillRegister getSkillRegister() { return skillRegister; }
|
public @NotNull SkillRegister getSkillRegister() { return skillRegister; }
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,6 @@ import org.bukkit.entity.*;
|
|||||||
import org.bukkit.event.entity.EntityDamageEvent;
|
import org.bukkit.event.entity.EntityDamageEvent;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.inventory.PlayerInventory;
|
import org.bukkit.inventory.PlayerInventory;
|
||||||
import org.bukkit.inventory.meta.ItemMeta;
|
|
||||||
import org.bukkit.inventory.meta.SkullMeta;
|
import org.bukkit.inventory.meta.SkullMeta;
|
||||||
import org.bukkit.util.BoundingBox;
|
import org.bukkit.util.BoundingBox;
|
||||||
import org.bukkit.util.Vector;
|
import org.bukkit.util.Vector;
|
||||||
@ -396,7 +395,7 @@ public class FishingManager extends SkillManager {
|
|||||||
|
|
||||||
if (treasure != null) {
|
if (treasure != null) {
|
||||||
if(treasure instanceof FishingTreasureBook) {
|
if(treasure instanceof FishingTreasureBook) {
|
||||||
treasureDrop = createEnchantBook((FishingTreasureBook) treasure);
|
treasureDrop = ItemUtils.createEnchantBook((FishingTreasureBook) treasure);
|
||||||
} else {
|
} else {
|
||||||
treasureDrop = treasure.getDrop().clone(); // Not cloning is bad, m'kay?
|
treasureDrop = treasure.getDrop().clone(); // Not cloning is bad, m'kay?
|
||||||
|
|
||||||
@ -450,37 +449,16 @@ public class FishingManager extends SkillManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(fishingSucceeds) {
|
if(fishingSucceeds) {
|
||||||
fishingCatch.setItemStack(treasureDrop);
|
|
||||||
|
|
||||||
if (Config.getInstance().getFishingExtraFish()) {
|
if (Config.getInstance().getFishingExtraFish()) {
|
||||||
Misc.spawnItem(player.getEyeLocation(), fishingCatch.getItemStack(), ItemSpawnReason.FISHING_EXTRA_FISH);
|
Misc.spawnItem(player.getEyeLocation(), fishingCatch.getItemStack(), ItemSpawnReason.FISHING_EXTRA_FISH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fishingCatch.setItemStack(treasureDrop);
|
||||||
}
|
}
|
||||||
|
|
||||||
applyXpGain(fishXp + treasureXp, XPGainReason.PVE);
|
applyXpGain(fishXp + treasureXp, XPGainReason.PVE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private @NotNull ItemStack createEnchantBook(@NotNull FishingTreasureBook fishingTreasureBook) {
|
|
||||||
ItemStack itemStack = fishingTreasureBook.getDrop().clone();
|
|
||||||
EnchantmentWrapper enchantmentWrapper = getRandomEnchantment(fishingTreasureBook.getLegalEnchantments());
|
|
||||||
ItemMeta itemMeta = itemStack.getItemMeta();
|
|
||||||
|
|
||||||
if(itemMeta == null)
|
|
||||||
return itemStack;
|
|
||||||
|
|
||||||
itemMeta.addEnchant(enchantmentWrapper.getEnchantment(), enchantmentWrapper.getEnchantmentLevel(), ExperienceConfig.getInstance().allowUnsafeEnchantments());
|
|
||||||
itemStack.setItemMeta(itemMeta);
|
|
||||||
return itemStack;
|
|
||||||
}
|
|
||||||
|
|
||||||
private @NotNull EnchantmentWrapper getRandomEnchantment(@NotNull List<EnchantmentWrapper> enchantmentWrappers) {
|
|
||||||
Collections.shuffle(enchantmentWrappers, Misc.getRandom());
|
|
||||||
|
|
||||||
int randomIndex = Misc.getRandom().nextInt(enchantmentWrappers.size());
|
|
||||||
return enchantmentWrappers.get(randomIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle the vanilla XP boost for Fishing
|
* Handle the vanilla XP boost for Fishing
|
||||||
*
|
*
|
||||||
|
@ -32,9 +32,7 @@ import org.bukkit.entity.*;
|
|||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class TamingManager extends SkillManager {
|
public class TamingManager extends SkillManager {
|
||||||
//TODO: Temporary static cache, will be changed in 2.2
|
//TODO: Temporary static cache, will be changed in 2.2
|
||||||
@ -42,8 +40,6 @@ public class TamingManager extends SkillManager {
|
|||||||
private static HashMap<CallOfTheWildType, TamingSummon> cotwSummonDataProperties;
|
private static HashMap<CallOfTheWildType, TamingSummon> cotwSummonDataProperties;
|
||||||
private long lastSummonTimeStamp;
|
private long lastSummonTimeStamp;
|
||||||
|
|
||||||
private HashMap<CallOfTheWildType, List<TrackedTamingEntity>> playerSummonedEntities;
|
|
||||||
|
|
||||||
public TamingManager(@NotNull OnlineMMOPlayer mmoPlayer) {
|
public TamingManager(@NotNull OnlineMMOPlayer mmoPlayer) {
|
||||||
super(mmoPlayer, PrimarySkillType.TAMING);
|
super(mmoPlayer, PrimarySkillType.TAMING);
|
||||||
init();
|
init();
|
||||||
@ -55,20 +51,12 @@ public class TamingManager extends SkillManager {
|
|||||||
lastSummonTimeStamp = 0L;
|
lastSummonTimeStamp = 0L;
|
||||||
|
|
||||||
//Init per-player tracking of summoned entities
|
//Init per-player tracking of summoned entities
|
||||||
initPerPlayerSummonTracking();
|
mcMMO.getTransientEntityTracker().initPlayer(mmoPlayer.getPlayer());
|
||||||
|
|
||||||
//Hacky stuff used as a band-aid
|
//Hacky stuff used as a band-aid
|
||||||
initStaticCaches();
|
initStaticCaches();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initPerPlayerSummonTracking() {
|
|
||||||
playerSummonedEntities = new HashMap<>();
|
|
||||||
|
|
||||||
for(CallOfTheWildType callOfTheWildType : CallOfTheWildType.values()) {
|
|
||||||
playerSummonedEntities.put(callOfTheWildType, new ArrayList<>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initStaticCaches() {
|
private void initStaticCaches() {
|
||||||
//TODO: Temporary static cache, will be changed in 2.2
|
//TODO: Temporary static cache, will be changed in 2.2
|
||||||
//This is shared between instances of TamingManager
|
//This is shared between instances of TamingManager
|
||||||
@ -503,58 +491,12 @@ public class TamingManager extends SkillManager {
|
|||||||
return summoningItems.containsKey(itemStack.getType());
|
return summoningItems.containsKey(itemStack.getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: The way this tracker was written is garbo, I should just rewrite it, I'll save that for a future update
|
private int getAmountCurrentlySummoned(@NotNull CallOfTheWildType callOfTheWildType) {
|
||||||
private int getAmountCurrentlySummoned(CallOfTheWildType callOfTheWildType) {
|
return mcMMO.getTransientEntityTracker().getAmountCurrentlySummoned(getPlayer().getUniqueId(), callOfTheWildType);
|
||||||
//The tracker is unreliable so validate its contents first
|
|
||||||
recalibrateTracker();
|
|
||||||
|
|
||||||
return playerSummonedEntities.get(callOfTheWildType).size();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: The way this tracker was written is garbo, I should just rewrite it, I'll save that for a future update
|
|
||||||
private void addToTracker(@NotNull LivingEntity livingEntity, @NotNull CallOfTheWildType callOfTheWildType) {
|
private void addToTracker(@NotNull LivingEntity livingEntity, @NotNull CallOfTheWildType callOfTheWildType) {
|
||||||
TrackedTamingEntity trackedEntity = new TrackedTamingEntity(livingEntity, callOfTheWildType, this);
|
mcMMO.getTransientEntityTracker().registerEntity(getPlayer().getUniqueId(), new TrackedTamingEntity(livingEntity, callOfTheWildType, getPlayer()));
|
||||||
|
|
||||||
playerSummonedEntities.get(callOfTheWildType).add(trackedEntity);
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: The way this tracker was written is garbo, I should just rewrite it, I'll save that for a future update
|
|
||||||
public List<TrackedTamingEntity> getTrackedEntities(CallOfTheWildType callOfTheWildType) {
|
|
||||||
return playerSummonedEntities.get(callOfTheWildType);
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: The way this tracker was written is garbo, I should just rewrite it, I'll save that for a future update
|
|
||||||
public void removeFromTracker(@NotNull TrackedTamingEntity trackedEntity) {
|
|
||||||
playerSummonedEntities.get(trackedEntity.getCallOfTheWildType()).remove(trackedEntity);
|
|
||||||
|
|
||||||
NotificationManager.sendPlayerInformationChatOnly(getPlayer(), "Taming.Summon.COTW.TimeExpired", StringUtils.getPrettyEntityTypeString(trackedEntity.getLivingEntity().getType()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds a new tracked list by determining which tracked things are still valid
|
|
||||||
*/
|
|
||||||
//TODO: The way this tracker was written is garbo, I should just rewrite it, I'll save that for a future update
|
|
||||||
private void recalibrateTracker() {
|
|
||||||
for(CallOfTheWildType callOfTheWildType : CallOfTheWildType.values()) {
|
|
||||||
ArrayList<TrackedTamingEntity> validEntities = getValidTrackedEntities(callOfTheWildType);
|
|
||||||
playerSummonedEntities.put(callOfTheWildType, validEntities); //Replace the old list with the new list
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: The way this tracker was written is garbo, I should just rewrite it, I'll save that for a future update
|
|
||||||
private @NotNull ArrayList<TrackedTamingEntity> getValidTrackedEntities(@NotNull CallOfTheWildType callOfTheWildType) {
|
|
||||||
ArrayList<TrackedTamingEntity> validTrackedEntities = new ArrayList<>();
|
|
||||||
|
|
||||||
for(TrackedTamingEntity trackedTamingEntity : getTrackedEntities(callOfTheWildType)) {
|
|
||||||
LivingEntity livingEntity = trackedTamingEntity.getLivingEntity();
|
|
||||||
|
|
||||||
//Remove from existence
|
|
||||||
if(livingEntity != null && livingEntity.isValid()) {
|
|
||||||
validTrackedEntities.add(trackedTamingEntity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return validTrackedEntities;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -563,20 +505,6 @@ public class TamingManager extends SkillManager {
|
|||||||
*/
|
*/
|
||||||
//TODO: The way this tracker was written is garbo, I should just rewrite it, I'll save that for a future update
|
//TODO: The way this tracker was written is garbo, I should just rewrite it, I'll save that for a future update
|
||||||
public void cleanupAllSummons() {
|
public void cleanupAllSummons() {
|
||||||
for(List<TrackedTamingEntity> trackedTamingEntities : playerSummonedEntities.values()) {
|
mcMMO.getTransientEntityTracker().cleanupPlayer(getPlayer());
|
||||||
for(TrackedTamingEntity trackedTamingEntity : trackedTamingEntities) {
|
|
||||||
LivingEntity livingEntity = trackedTamingEntity.getLivingEntity();
|
|
||||||
|
|
||||||
//Remove from existence
|
|
||||||
if(livingEntity != null && livingEntity.isValid()) {
|
|
||||||
mcMMO.getCompatibilityManager().getPersistentDataLayer().removeMobFlags(livingEntity);
|
|
||||||
livingEntity.setHealth(0);
|
|
||||||
livingEntity.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Clear the list
|
|
||||||
trackedTamingEntities.clear();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,61 +4,40 @@ import com.gmail.nossr50.config.Config;
|
|||||||
import com.gmail.nossr50.datatypes.skills.subskills.taming.CallOfTheWildType;
|
import com.gmail.nossr50.datatypes.skills.subskills.taming.CallOfTheWildType;
|
||||||
import com.gmail.nossr50.mcMMO;
|
import com.gmail.nossr50.mcMMO;
|
||||||
import com.gmail.nossr50.util.Misc;
|
import com.gmail.nossr50.util.Misc;
|
||||||
import com.gmail.nossr50.util.skills.ParticleEffectUtils;
|
|
||||||
import org.bukkit.Location;
|
|
||||||
import org.bukkit.Sound;
|
|
||||||
import org.bukkit.entity.LivingEntity;
|
import org.bukkit.entity.LivingEntity;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.scheduler.BukkitRunnable;
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public class TrackedTamingEntity extends BukkitRunnable {
|
public class TrackedTamingEntity extends BukkitRunnable {
|
||||||
private final LivingEntity livingEntity;
|
private final @NotNull LivingEntity livingEntity;
|
||||||
private final CallOfTheWildType callOfTheWildType;
|
private final @NotNull CallOfTheWildType callOfTheWildType;
|
||||||
private final UUID id;
|
private final @NotNull Player player;
|
||||||
private int length;
|
|
||||||
private final TamingManager tamingManagerRef;
|
|
||||||
|
|
||||||
protected TrackedTamingEntity(LivingEntity livingEntity, CallOfTheWildType callOfTheWildType, TamingManager tamingManagerRef) {
|
protected TrackedTamingEntity(@NotNull LivingEntity livingEntity, @NotNull CallOfTheWildType callOfTheWildType, @NotNull Player player) {
|
||||||
this.tamingManagerRef = tamingManagerRef;
|
this.player = player;
|
||||||
this.callOfTheWildType = callOfTheWildType;
|
this.callOfTheWildType = callOfTheWildType;
|
||||||
this.livingEntity = livingEntity;
|
this.livingEntity = livingEntity;
|
||||||
this.id = livingEntity.getUniqueId();
|
|
||||||
|
|
||||||
int tamingCOTWLength = Config.getInstance().getTamingCOTWLength(callOfTheWildType.getConfigEntityTypeEntry());
|
int tamingCOTWLength = Config.getInstance().getTamingCOTWLength(callOfTheWildType.getConfigEntityTypeEntry());
|
||||||
|
|
||||||
if (tamingCOTWLength > 0) {
|
if (tamingCOTWLength > 0) {
|
||||||
this.length = tamingCOTWLength * Misc.TICK_CONVERSION_FACTOR;
|
int length = tamingCOTWLength * Misc.TICK_CONVERSION_FACTOR;
|
||||||
this.runTaskLater(mcMMO.p, length);
|
this.runTaskLater(mcMMO.p, length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (livingEntity.isValid()) {
|
mcMMO.getTransientEntityTracker().removeSummon(this.getLivingEntity(), player, true);
|
||||||
Location location = livingEntity.getLocation();
|
|
||||||
location.getWorld().playSound(location, Sound.BLOCK_FIRE_EXTINGUISH, 0.8F, 0.8F);
|
|
||||||
ParticleEffectUtils.playCallOfTheWildEffect(livingEntity);
|
|
||||||
|
|
||||||
if(tamingManagerRef != null)
|
|
||||||
tamingManagerRef.removeFromTracker(this);
|
|
||||||
|
|
||||||
livingEntity.setHealth(0);
|
|
||||||
livingEntity.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.cancel();
|
this.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
public CallOfTheWildType getCallOfTheWildType() {
|
public @NotNull CallOfTheWildType getCallOfTheWildType() {
|
||||||
return callOfTheWildType;
|
return callOfTheWildType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LivingEntity getLivingEntity() {
|
public @NotNull LivingEntity getLivingEntity() {
|
||||||
return livingEntity;
|
return livingEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UUID getID() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -182,11 +182,14 @@ public final class BlockUtils {
|
|||||||
* @return true if the block should affected by Super Breaker, false
|
* @return true if the block should affected by Super Breaker, false
|
||||||
* otherwise
|
* otherwise
|
||||||
*/
|
*/
|
||||||
public static Boolean affectedBySuperBreaker(BlockState blockState) {
|
public static boolean affectedBySuperBreaker(BlockState blockState) {
|
||||||
|
if(mcMMO.getMaterialMapStore().isIntendedToolPickaxe(blockState.getType()))
|
||||||
|
return true;
|
||||||
|
|
||||||
if (ExperienceConfig.getInstance().doesBlockGiveSkillXP(PrimarySkillType.MINING, blockState.getBlockData()))
|
if (ExperienceConfig.getInstance().doesBlockGiveSkillXP(PrimarySkillType.MINING, blockState.getBlockData()))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return isOre(blockState) || mcMMO.getModManager().isCustomMiningBlock(blockState);
|
return mcMMO.getModManager().isCustomMiningBlock(blockState);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2,7 +2,10 @@ package com.gmail.nossr50.util;
|
|||||||
|
|
||||||
import com.gmail.nossr50.config.AdvancedConfig;
|
import com.gmail.nossr50.config.AdvancedConfig;
|
||||||
import com.gmail.nossr50.config.Config;
|
import com.gmail.nossr50.config.Config;
|
||||||
|
import com.gmail.nossr50.config.experience.ExperienceConfig;
|
||||||
import com.gmail.nossr50.config.party.ItemWeightConfig;
|
import com.gmail.nossr50.config.party.ItemWeightConfig;
|
||||||
|
import com.gmail.nossr50.datatypes.treasure.EnchantmentWrapper;
|
||||||
|
import com.gmail.nossr50.datatypes.treasure.FishingTreasureBook;
|
||||||
import com.gmail.nossr50.locale.LocaleLoader;
|
import com.gmail.nossr50.locale.LocaleLoader;
|
||||||
import com.gmail.nossr50.mcMMO;
|
import com.gmail.nossr50.mcMMO;
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
@ -12,9 +15,11 @@ import org.bukkit.entity.Player;
|
|||||||
import org.bukkit.inventory.FurnaceRecipe;
|
import org.bukkit.inventory.FurnaceRecipe;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.inventory.Recipe;
|
import org.bukkit.inventory.Recipe;
|
||||||
|
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 java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.bukkit.Material.AIR;
|
import static org.bukkit.Material.AIR;
|
||||||
@ -581,4 +586,26 @@ public final class ItemUtils {
|
|||||||
public static boolean canBeSuperAbilityDigBoosted(@NotNull ItemStack itemStack) {
|
public static boolean canBeSuperAbilityDigBoosted(@NotNull ItemStack itemStack) {
|
||||||
return isShovel(itemStack) || isPickaxe(itemStack);
|
return isShovel(itemStack) || isPickaxe(itemStack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static @NotNull ItemStack createEnchantBook(@NotNull FishingTreasureBook fishingTreasureBook) {
|
||||||
|
ItemStack itemStack = fishingTreasureBook.getDrop().clone();
|
||||||
|
EnchantmentWrapper enchantmentWrapper = getRandomEnchantment(fishingTreasureBook.getLegalEnchantments());
|
||||||
|
ItemMeta itemMeta = itemStack.getItemMeta();
|
||||||
|
|
||||||
|
if(itemMeta == null) {
|
||||||
|
return itemStack;
|
||||||
|
}
|
||||||
|
|
||||||
|
EnchantmentStorageMeta enchantmentStorageMeta = (EnchantmentStorageMeta) itemMeta;
|
||||||
|
enchantmentStorageMeta.addStoredEnchant(enchantmentWrapper.getEnchantment(), enchantmentWrapper.getEnchantmentLevel(), ExperienceConfig.getInstance().allowUnsafeEnchantments());
|
||||||
|
itemStack.setItemMeta(enchantmentStorageMeta);
|
||||||
|
return itemStack;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @NotNull EnchantmentWrapper getRandomEnchantment(@NotNull List<EnchantmentWrapper> enchantmentWrappers) {
|
||||||
|
Collections.shuffle(enchantmentWrappers, Misc.getRandom());
|
||||||
|
|
||||||
|
int randomIndex = Misc.getRandom().nextInt(enchantmentWrappers.size());
|
||||||
|
return enchantmentWrappers.get(randomIndex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,6 +55,8 @@ public class MaterialMapStore {
|
|||||||
private final @NotNull HashSet<String> enchantables;
|
private final @NotNull HashSet<String> enchantables;
|
||||||
|
|
||||||
private final @NotNull HashSet<String> ores;
|
private final @NotNull HashSet<String> ores;
|
||||||
|
private final @NotNull HashSet<String> intendedToolPickAxe;
|
||||||
|
private final @NotNull HashSet<String> intendedToolShovel;
|
||||||
|
|
||||||
private final @NotNull HashMap<String, Integer> tierValue;
|
private final @NotNull HashMap<String, Integer> tierValue;
|
||||||
|
|
||||||
@ -100,14 +102,16 @@ public class MaterialMapStore {
|
|||||||
enchantables = new HashSet<>();
|
enchantables = new HashSet<>();
|
||||||
|
|
||||||
ores = new HashSet<>();
|
ores = new HashSet<>();
|
||||||
|
intendedToolPickAxe = new HashSet<>();
|
||||||
|
intendedToolShovel = new HashSet<>();
|
||||||
|
|
||||||
tierValue = new HashMap<>();
|
tierValue = new HashMap<>();
|
||||||
|
|
||||||
fillVanillaMaterialRegisters();
|
fillVanillaMaterialRegisters();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fillVanillaMaterialRegisters()
|
private void fillVanillaMaterialRegisters() {
|
||||||
{
|
//The order matters
|
||||||
fillAbilityBlackList();
|
fillAbilityBlackList();
|
||||||
fillToolBlackList();
|
fillToolBlackList();
|
||||||
fillMossyWhiteList();
|
fillMossyWhiteList();
|
||||||
@ -122,6 +126,7 @@ public class MaterialMapStore {
|
|||||||
fillTools();
|
fillTools();
|
||||||
fillEnchantables();
|
fillEnchantables();
|
||||||
fillOres();
|
fillOres();
|
||||||
|
fillIntendedTools();
|
||||||
|
|
||||||
fillTierMap();
|
fillTierMap();
|
||||||
}
|
}
|
||||||
@ -206,6 +211,190 @@ public class MaterialMapStore {
|
|||||||
ores.add("gilded_blackstone");
|
ores.add("gilded_blackstone");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void fillIntendedTools() {
|
||||||
|
intendedToolPickAxe.addAll(ores);
|
||||||
|
|
||||||
|
intendedToolPickAxe.add("ice");
|
||||||
|
intendedToolPickAxe.add("packed_ice");
|
||||||
|
intendedToolPickAxe.add("blue_ice");
|
||||||
|
intendedToolPickAxe.add("frosted_ice");
|
||||||
|
intendedToolPickAxe.add("anvil");
|
||||||
|
intendedToolPickAxe.add("bell");
|
||||||
|
intendedToolPickAxe.add("block_of_redstone");
|
||||||
|
intendedToolPickAxe.add("brewing_stand");
|
||||||
|
intendedToolPickAxe.add("cauldron");
|
||||||
|
intendedToolPickAxe.add("chain");
|
||||||
|
intendedToolPickAxe.add("hopper");
|
||||||
|
intendedToolPickAxe.add("iron_bars");
|
||||||
|
intendedToolPickAxe.add("iron_door");
|
||||||
|
intendedToolPickAxe.add("iron_trapdoor");
|
||||||
|
intendedToolPickAxe.add("lantern");
|
||||||
|
intendedToolPickAxe.add("weighted_pressure_plates");
|
||||||
|
intendedToolPickAxe.add("block_of_iron");
|
||||||
|
intendedToolPickAxe.add("copper_blocks");
|
||||||
|
intendedToolPickAxe.add("cut_copper");
|
||||||
|
intendedToolPickAxe.add("cut_copper_slab");
|
||||||
|
intendedToolPickAxe.add("cut_copper_stairs");
|
||||||
|
intendedToolPickAxe.add("lapis_lazuli_block");
|
||||||
|
intendedToolPickAxe.add("lightning_rod");
|
||||||
|
intendedToolPickAxe.add("block_of_diamond");
|
||||||
|
intendedToolPickAxe.add("block_of_emerald");
|
||||||
|
intendedToolPickAxe.add("block_of_gold");
|
||||||
|
intendedToolPickAxe.add("block_of_netherite");
|
||||||
|
intendedToolPickAxe.add("piston");
|
||||||
|
intendedToolPickAxe.add("sticky_piston");
|
||||||
|
intendedToolPickAxe.add("conduit");
|
||||||
|
intendedToolPickAxe.add("shulker_box");
|
||||||
|
intendedToolPickAxe.add("element_constructor"); //be & ee
|
||||||
|
intendedToolPickAxe.add("compound_creator"); //be & ee
|
||||||
|
intendedToolPickAxe.add("material_reducer"); //be & ee
|
||||||
|
intendedToolPickAxe.add("activator_rail");
|
||||||
|
intendedToolPickAxe.add("detector_rail");
|
||||||
|
intendedToolPickAxe.add("powered_rail");
|
||||||
|
intendedToolPickAxe.add("rail");
|
||||||
|
intendedToolPickAxe.add("andesite");
|
||||||
|
intendedToolPickAxe.add("basalt");
|
||||||
|
intendedToolPickAxe.add("blackstone");
|
||||||
|
intendedToolPickAxe.add("blast_furnace");
|
||||||
|
intendedToolPickAxe.add("block_of_coal");
|
||||||
|
intendedToolPickAxe.add("block_of_quartz");
|
||||||
|
intendedToolPickAxe.add("bricks");
|
||||||
|
intendedToolPickAxe.add("cobblestone");
|
||||||
|
intendedToolPickAxe.add("cobblestone_wall");
|
||||||
|
intendedToolPickAxe.add("concrete");
|
||||||
|
intendedToolPickAxe.add("dark_prismarine");
|
||||||
|
intendedToolPickAxe.add("diorite");
|
||||||
|
intendedToolPickAxe.add("dispenser");
|
||||||
|
intendedToolPickAxe.add("dripstone_block");
|
||||||
|
intendedToolPickAxe.add("dropper");
|
||||||
|
intendedToolPickAxe.add("enchantment_table");
|
||||||
|
intendedToolPickAxe.add("end_stone");
|
||||||
|
intendedToolPickAxe.add("ender_chest");
|
||||||
|
intendedToolPickAxe.add("furnace");
|
||||||
|
intendedToolPickAxe.add("glazed_terracotta");
|
||||||
|
intendedToolPickAxe.add("granite");
|
||||||
|
intendedToolPickAxe.add("grindstone");
|
||||||
|
intendedToolPickAxe.add("heat_block"); //be & ee
|
||||||
|
intendedToolPickAxe.add("lodestone");
|
||||||
|
intendedToolPickAxe.add("mossy_cobblestone");
|
||||||
|
intendedToolPickAxe.add("nether_bricks");
|
||||||
|
intendedToolPickAxe.add("nether_brick_fence");
|
||||||
|
intendedToolPickAxe.add("nether_gold_ore");
|
||||||
|
intendedToolPickAxe.add("nether_quartz_ore");
|
||||||
|
intendedToolPickAxe.add("netherrack");
|
||||||
|
intendedToolPickAxe.add("observer");
|
||||||
|
intendedToolPickAxe.add("prismarine");
|
||||||
|
intendedToolPickAxe.add("prismarine_bricks");
|
||||||
|
intendedToolPickAxe.add("pointed_dripstone");
|
||||||
|
intendedToolPickAxe.add("polished_andesite");
|
||||||
|
intendedToolPickAxe.add("polished_blackstone");
|
||||||
|
intendedToolPickAxe.add("polished_blackstone_bricks");
|
||||||
|
intendedToolPickAxe.add("polished_diorite");
|
||||||
|
intendedToolPickAxe.add("polished_granite");
|
||||||
|
intendedToolPickAxe.add("red_sandstone");
|
||||||
|
intendedToolPickAxe.add("sandstone");
|
||||||
|
intendedToolPickAxe.add("smoker");
|
||||||
|
intendedToolPickAxe.add("spawner");
|
||||||
|
intendedToolPickAxe.add("stonecutter");
|
||||||
|
// intendedToolPickAxe.add("slabs");
|
||||||
|
intendedToolPickAxe.add("colored_terracotta");
|
||||||
|
// intendedToolPickAxe.add("stairs");
|
||||||
|
intendedToolPickAxe.add("smooth_stone");
|
||||||
|
intendedToolPickAxe.add("stone");
|
||||||
|
intendedToolPickAxe.add("stone_bricks");
|
||||||
|
intendedToolPickAxe.add("stone_button");
|
||||||
|
intendedToolPickAxe.add("stone_pressure_plate");
|
||||||
|
intendedToolPickAxe.add("terracotta");
|
||||||
|
intendedToolPickAxe.add("amethyst_bud");
|
||||||
|
intendedToolPickAxe.add("amethyst_cluster");
|
||||||
|
intendedToolPickAxe.add("block_of_amethyst");
|
||||||
|
intendedToolPickAxe.add("budding_amethyst");
|
||||||
|
intendedToolPickAxe.add("ancient_debris");
|
||||||
|
intendedToolPickAxe.add("crying_obsidian");
|
||||||
|
intendedToolPickAxe.add("glowing_obsidian"); //be
|
||||||
|
intendedToolPickAxe.add("obsidian");
|
||||||
|
intendedToolPickAxe.add("respawn_anchor");
|
||||||
|
|
||||||
|
//slabs
|
||||||
|
intendedToolPickAxe.add("petrified_oak_slab");
|
||||||
|
intendedToolPickAxe.add("stone_slab");
|
||||||
|
intendedToolPickAxe.add("smooth_stone_slab");
|
||||||
|
intendedToolPickAxe.add("cobblestone_slab");
|
||||||
|
intendedToolPickAxe.add("mossy_cobblestone_slab");
|
||||||
|
intendedToolPickAxe.add("stone_brick_slab");
|
||||||
|
intendedToolPickAxe.add("mossy_stone_brick_slab");
|
||||||
|
intendedToolPickAxe.add("andesite_slab");
|
||||||
|
intendedToolPickAxe.add("polished_andesite_slab");
|
||||||
|
intendedToolPickAxe.add("diorite_slab");
|
||||||
|
intendedToolPickAxe.add("polished_diorite_slab");
|
||||||
|
intendedToolPickAxe.add("granite_slab");
|
||||||
|
intendedToolPickAxe.add("polished_granite_slab");
|
||||||
|
intendedToolPickAxe.add("sandstone_slab");
|
||||||
|
intendedToolPickAxe.add("cut_sandstone_slab");
|
||||||
|
intendedToolPickAxe.add("smooth_sandstone_slab");
|
||||||
|
intendedToolPickAxe.add("red_sandstone_slab");
|
||||||
|
intendedToolPickAxe.add("cut_red_sandstone_slab");
|
||||||
|
intendedToolPickAxe.add("smooth_red_sandstone_slab");
|
||||||
|
intendedToolPickAxe.add("brick_slab");
|
||||||
|
intendedToolPickAxe.add("prismarine_brick_slab");
|
||||||
|
intendedToolPickAxe.add("dark_prismarine_slab");
|
||||||
|
intendedToolPickAxe.add("nether_brick_slab");
|
||||||
|
intendedToolPickAxe.add("red_netherbrick_slab");
|
||||||
|
intendedToolPickAxe.add("quartz_slab");
|
||||||
|
intendedToolPickAxe.add("smooth_quartz_slab");
|
||||||
|
intendedToolPickAxe.add("purpur_slab");
|
||||||
|
intendedToolPickAxe.add("end_stone_brick_slab");
|
||||||
|
intendedToolPickAxe.add("blackstone_slab");
|
||||||
|
intendedToolPickAxe.add("polished_blackstone_slab");
|
||||||
|
intendedToolPickAxe.add("polished_blackstone_brick_slab");
|
||||||
|
intendedToolPickAxe.add("lightly_weathered_cut_copper_slab");
|
||||||
|
intendedToolPickAxe.add("semi_weathered_cut_copper_slab");
|
||||||
|
intendedToolPickAxe.add("waxed_semi_weathered_cut_copper_slab");
|
||||||
|
intendedToolPickAxe.add("weathered_cut_copper_slab");
|
||||||
|
intendedToolPickAxe.add("waxed_cut_copper_slab");
|
||||||
|
intendedToolPickAxe.add("waxed_lightly_weathered_cut_copper_slab");
|
||||||
|
|
||||||
|
//stairs (not all of these exist, just copied the above list and replaced slab with stairs)
|
||||||
|
intendedToolPickAxe.add("petrified_oak_stairs");
|
||||||
|
intendedToolPickAxe.add("stone_stairs");
|
||||||
|
intendedToolPickAxe.add("smooth_stone_stairs");
|
||||||
|
intendedToolPickAxe.add("cobblestone_stairs");
|
||||||
|
intendedToolPickAxe.add("mossy_cobblestone_stairs");
|
||||||
|
intendedToolPickAxe.add("stone_brick_stairs");
|
||||||
|
intendedToolPickAxe.add("mossy_stone_brick_stairs");
|
||||||
|
intendedToolPickAxe.add("andesite_stairs");
|
||||||
|
intendedToolPickAxe.add("polished_andesite_stairs");
|
||||||
|
intendedToolPickAxe.add("diorite_stairs");
|
||||||
|
intendedToolPickAxe.add("polished_diorite_stairs");
|
||||||
|
intendedToolPickAxe.add("granite_stairs");
|
||||||
|
intendedToolPickAxe.add("polished_granite_stairs");
|
||||||
|
intendedToolPickAxe.add("sandstone_stairs");
|
||||||
|
intendedToolPickAxe.add("cut_sandstone_stairs");
|
||||||
|
intendedToolPickAxe.add("smooth_sandstone_stairs");
|
||||||
|
intendedToolPickAxe.add("red_sandstone_stairs");
|
||||||
|
intendedToolPickAxe.add("cut_red_sandstone_stairs");
|
||||||
|
intendedToolPickAxe.add("smooth_red_sandstone_stairs");
|
||||||
|
intendedToolPickAxe.add("brick_stairs");
|
||||||
|
intendedToolPickAxe.add("prismarine_brick_stairs");
|
||||||
|
intendedToolPickAxe.add("dark_prismarine_stairs");
|
||||||
|
intendedToolPickAxe.add("nether_brick_stairs");
|
||||||
|
intendedToolPickAxe.add("red_netherbrick_stairs");
|
||||||
|
intendedToolPickAxe.add("quartz_stairs");
|
||||||
|
intendedToolPickAxe.add("smooth_quartz_stairs");
|
||||||
|
intendedToolPickAxe.add("purpur_stairs");
|
||||||
|
intendedToolPickAxe.add("end_stone_brick_stairs");
|
||||||
|
intendedToolPickAxe.add("blackstone_stairs");
|
||||||
|
intendedToolPickAxe.add("polished_blackstone_stairs");
|
||||||
|
intendedToolPickAxe.add("polished_blackstone_brick_stairs");
|
||||||
|
intendedToolPickAxe.add("lightly_weathered_cut_copper_stairs");
|
||||||
|
intendedToolPickAxe.add("semi_weathered_cut_copper_stairs");
|
||||||
|
intendedToolPickAxe.add("waxed_semi_weathered_cut_copper_stairs");
|
||||||
|
intendedToolPickAxe.add("weathered_cut_copper_stairs");
|
||||||
|
intendedToolPickAxe.add("waxed_cut_copper_stairs");
|
||||||
|
intendedToolPickAxe.add("waxed_lightly_weathered_cut_copper_stairs");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private void fillArmors() {
|
private void fillArmors() {
|
||||||
fillLeatherArmorWhiteList();
|
fillLeatherArmorWhiteList();
|
||||||
fillIronArmorWhiteList();
|
fillIronArmorWhiteList();
|
||||||
@ -1078,6 +1267,14 @@ public class MaterialMapStore {
|
|||||||
toolBlackList.add("respawn_anchor");
|
toolBlackList.add("respawn_anchor");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isIntendedToolPickaxe(Material material) {
|
||||||
|
return intendedToolPickAxe.contains(material.getKey().getKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isIntendedToolPickaxe(String string) {
|
||||||
|
return intendedToolPickAxe.contains(string);
|
||||||
|
}
|
||||||
|
|
||||||
public @NotNull HashSet<String> getNetheriteArmor() {
|
public @NotNull HashSet<String> getNetheriteArmor() {
|
||||||
return netheriteArmor;
|
return netheriteArmor;
|
||||||
}
|
}
|
||||||
|
316
src/main/java/com/gmail/nossr50/util/TransientEntityTracker.java
Normal file
316
src/main/java/com/gmail/nossr50/util/TransientEntityTracker.java
Normal file
@ -0,0 +1,316 @@
|
|||||||
|
package com.gmail.nossr50.util;
|
||||||
|
|
||||||
|
import com.gmail.nossr50.datatypes.skills.subskills.taming.CallOfTheWildType;
|
||||||
|
import com.gmail.nossr50.mcMMO;
|
||||||
|
import com.gmail.nossr50.skills.taming.TrackedTamingEntity;
|
||||||
|
import com.gmail.nossr50.util.player.NotificationManager;
|
||||||
|
import com.gmail.nossr50.util.skills.ParticleEffectUtils;
|
||||||
|
import com.gmail.nossr50.util.text.StringUtils;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Chunk;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Sound;
|
||||||
|
import org.bukkit.entity.LivingEntity;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class TransientEntityTracker {
|
||||||
|
//These two are updated in step with each other
|
||||||
|
private final @NotNull HashMap<UUID, HashMap<CallOfTheWildType, HashSet<TrackedTamingEntity>>> perPlayerTransientEntityMap;
|
||||||
|
private final @NotNull HashSet<LivingEntity> chunkLookupCache;
|
||||||
|
|
||||||
|
public TransientEntityTracker() {
|
||||||
|
perPlayerTransientEntityMap = new HashMap<>();
|
||||||
|
chunkLookupCache = new HashSet<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized @NotNull HashSet<LivingEntity> getChunkLookupCache() {
|
||||||
|
return chunkLookupCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized @NotNull HashMap<UUID, HashMap<CallOfTheWildType, HashSet<TrackedTamingEntity>>> getPerPlayerTransientEntityMap() {
|
||||||
|
return perPlayerTransientEntityMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void initPlayer(@NotNull Player player) {
|
||||||
|
if (!isPlayerRegistered(player.getUniqueId())) {
|
||||||
|
registerPlayer(player.getUniqueId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a player from the tracker
|
||||||
|
*
|
||||||
|
* @param playerUUID target player
|
||||||
|
*/
|
||||||
|
public synchronized void cleanupPlayer(@NotNull UUID playerUUID) {
|
||||||
|
cleanPlayer(null, playerUUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a player from the tracker
|
||||||
|
*
|
||||||
|
* @param player target player
|
||||||
|
*/
|
||||||
|
public synchronized void cleanupPlayer(@NotNull Player player) {
|
||||||
|
cleanPlayer(player, player.getUniqueId());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a player from the tracker
|
||||||
|
*
|
||||||
|
* @param player target player
|
||||||
|
* @param playerUUID target player UUID
|
||||||
|
*/
|
||||||
|
private void cleanPlayer(@Nullable Player player, @NotNull UUID playerUUID) {
|
||||||
|
cleanupAllSummons(player, player.getUniqueId());
|
||||||
|
removePlayerFromMap(playerUUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removePlayerFromMap(@NotNull UUID playerUUID) {
|
||||||
|
getPerPlayerTransientEntityMap().remove(playerUUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a player has already been registered
|
||||||
|
* Being registered constitutes having necessary values initialized in our per-player map
|
||||||
|
*
|
||||||
|
* @param playerUUID target player
|
||||||
|
* @return true if the player is registered
|
||||||
|
*/
|
||||||
|
private synchronized boolean isPlayerRegistered(@NotNull UUID playerUUID) {
|
||||||
|
return getPerPlayerTransientEntityMap().get(playerUUID) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a player to our tracker, which initializes the necessary values in our per-player map
|
||||||
|
*
|
||||||
|
* @param playerUUID player to register
|
||||||
|
*/
|
||||||
|
private synchronized void registerPlayer(@NotNull UUID playerUUID) {
|
||||||
|
getPerPlayerTransientEntityMap().put(playerUUID, new HashMap<CallOfTheWildType, HashSet<TrackedTamingEntity>>());
|
||||||
|
|
||||||
|
for(CallOfTheWildType callOfTheWildType : CallOfTheWildType.values()) {
|
||||||
|
getPerPlayerTransientEntityMap().get(playerUUID).put(callOfTheWildType, new HashSet<>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the tracked transient entities map for a specific player
|
||||||
|
*
|
||||||
|
* @param playerUUID the target uuid of the player
|
||||||
|
* @return the tracked entities map for the player, null if the player isn't registered
|
||||||
|
*/
|
||||||
|
public synchronized @Nullable HashMap<CallOfTheWildType, HashSet<TrackedTamingEntity>> getPlayerTrackedEntityMap(@NotNull UUID playerUUID) {
|
||||||
|
return getPerPlayerTransientEntityMap().get(playerUUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers an entity to a player
|
||||||
|
* This includes registration to our per-player map and our chunk lookup cache
|
||||||
|
*
|
||||||
|
* @param playerUUID target player's UUID
|
||||||
|
* @param trackedTamingEntity target entity
|
||||||
|
*/
|
||||||
|
public synchronized void registerEntity(@NotNull UUID playerUUID, @NotNull TrackedTamingEntity trackedTamingEntity) {
|
||||||
|
//Add to map entry
|
||||||
|
getTrackedEntities(playerUUID, trackedTamingEntity.getCallOfTheWildType()).add(trackedTamingEntity);
|
||||||
|
|
||||||
|
//Add to cache for chunk lookups
|
||||||
|
addToChunkLookupCache(trackedTamingEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a living entity is a summon
|
||||||
|
*
|
||||||
|
* @param livingEntity target livinig entity
|
||||||
|
* @return true if target living entity is a summon
|
||||||
|
*/
|
||||||
|
public synchronized boolean isTransientSummon(@NotNull LivingEntity livingEntity) {
|
||||||
|
return getChunkLookupCache().contains(livingEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the tracked taming entities for a player
|
||||||
|
* If the player isn't registered this will return null
|
||||||
|
*
|
||||||
|
* @param playerUUID the target uuid of the player
|
||||||
|
* @param callOfTheWildType target type
|
||||||
|
* @return the set of tracked entities for the player, null if the player isn't registered, the set can be empty
|
||||||
|
*/
|
||||||
|
private synchronized @Nullable HashSet<TrackedTamingEntity> getTrackedEntities(@NotNull UUID playerUUID, @NotNull CallOfTheWildType callOfTheWildType) {
|
||||||
|
HashMap<CallOfTheWildType, HashSet<TrackedTamingEntity>> playerEntityMap = getPlayerTrackedEntityMap(playerUUID);
|
||||||
|
|
||||||
|
if(playerEntityMap == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return playerEntityMap.get(callOfTheWildType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an entity to our chunk lookup cache
|
||||||
|
*
|
||||||
|
* @param trackedTamingEntity target tracked taming entity
|
||||||
|
*/
|
||||||
|
private synchronized void addToChunkLookupCache(@NotNull TrackedTamingEntity trackedTamingEntity) {
|
||||||
|
getChunkLookupCache().add(trackedTamingEntity.getLivingEntity());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes an entity from our tracker
|
||||||
|
* This includes removal from our per-player map and our chunk lookup cache
|
||||||
|
*
|
||||||
|
* @param livingEntity target entity
|
||||||
|
*/
|
||||||
|
private void unregisterEntity(@NotNull LivingEntity livingEntity) {
|
||||||
|
chunkLookupCacheCleanup(livingEntity);
|
||||||
|
perPlayerTransientMapCleanup(livingEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes an entity from our chunk lookup cache
|
||||||
|
*
|
||||||
|
* @param livingEntity target entity
|
||||||
|
*/
|
||||||
|
private void chunkLookupCacheCleanup(@NotNull LivingEntity livingEntity) {
|
||||||
|
getChunkLookupCache().remove(livingEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clean a living entity from our tracker
|
||||||
|
* Iterates over all players and their registered entities
|
||||||
|
* Doesn't do any kind of failure checking, if it doesn't find any player with a registered entity nothing bad happens or is reported
|
||||||
|
* However it should never happen like that, so maybe we could consider adding some failure to execute checking in the future
|
||||||
|
*
|
||||||
|
* @param livingEntity
|
||||||
|
*/
|
||||||
|
private void perPlayerTransientMapCleanup(@NotNull LivingEntity livingEntity) {
|
||||||
|
for(UUID uuid : getPerPlayerTransientEntityMap().keySet()) {
|
||||||
|
for(CallOfTheWildType callOfTheWildType : CallOfTheWildType.values()) {
|
||||||
|
|
||||||
|
HashSet<TrackedTamingEntity> trackedEntities = getTrackedEntities(uuid, callOfTheWildType);
|
||||||
|
|
||||||
|
if(trackedEntities == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Iterator<TrackedTamingEntity> iterator = trackedEntities.iterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
if(iterator.next().getLivingEntity().equals(livingEntity)) {
|
||||||
|
iterator.remove();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all transient entities that exist in a specific chunk
|
||||||
|
*
|
||||||
|
* @param chunk the chunk to match
|
||||||
|
* @return a list of transient entities that are located in the provided chunk
|
||||||
|
*/
|
||||||
|
public synchronized @NotNull List<LivingEntity> getAllTransientEntitiesInChunk(@NotNull Chunk chunk) {
|
||||||
|
ArrayList<LivingEntity> matchingEntities = new ArrayList<>();
|
||||||
|
|
||||||
|
for(LivingEntity livingEntity : getChunkLookupCache()) {
|
||||||
|
if(livingEntity.getLocation().getChunk().equals(chunk)) {
|
||||||
|
matchingEntities.add(livingEntity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return matchingEntities;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the amount of a summon currently active for a player
|
||||||
|
*
|
||||||
|
* @param playerUUID target player
|
||||||
|
* @param callOfTheWildType summon type
|
||||||
|
* @return the amount of summons currently active for player of target type
|
||||||
|
*/
|
||||||
|
public synchronized int getAmountCurrentlySummoned(@NotNull UUID playerUUID, @NotNull CallOfTheWildType callOfTheWildType) {
|
||||||
|
HashSet<TrackedTamingEntity> trackedEntities = getTrackedEntities(playerUUID, callOfTheWildType);
|
||||||
|
|
||||||
|
if(trackedEntities == null)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return trackedEntities.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kills a summon and removes its metadata
|
||||||
|
* Then it removes it from the tracker / chunk lookup cache
|
||||||
|
*
|
||||||
|
* @param livingEntity entity to remove
|
||||||
|
* @param player associated player
|
||||||
|
*/
|
||||||
|
public synchronized void removeSummon(@NotNull LivingEntity livingEntity, @Nullable Player player, boolean timeExpired) {
|
||||||
|
//Kill the summon & remove it
|
||||||
|
if(livingEntity.isValid()) {
|
||||||
|
livingEntity.setHealth(0); //Should trigger entity death events
|
||||||
|
livingEntity.remove();
|
||||||
|
|
||||||
|
Location location = livingEntity.getLocation();
|
||||||
|
|
||||||
|
if (location.getWorld() != null) {
|
||||||
|
location.getWorld().playSound(location, Sound.BLOCK_FIRE_EXTINGUISH, 0.8F, 0.8F);
|
||||||
|
ParticleEffectUtils.playCallOfTheWildEffect(livingEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Inform player of summon death
|
||||||
|
if(player != null && player.isOnline()) {
|
||||||
|
if(timeExpired) {
|
||||||
|
NotificationManager.sendPlayerInformationChatOnly(player, "Taming.Summon.COTW.TimeExpired", StringUtils.getPrettyEntityTypeString(livingEntity.getType()));
|
||||||
|
} else {
|
||||||
|
NotificationManager.sendPlayerInformationChatOnly(player, "Taming.Summon.COTW.Removed", StringUtils.getPrettyEntityTypeString(livingEntity.getType()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Remove our metadata
|
||||||
|
mcMMO.getCompatibilityManager().getPersistentDataLayer().removeMobFlags(livingEntity);
|
||||||
|
|
||||||
|
//Clean from trackers
|
||||||
|
unregisterEntity(livingEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all tracked entities from existence if they currently exist
|
||||||
|
* Clear the tracked entity lists afterwards
|
||||||
|
*
|
||||||
|
* @deprecated use {@link #cleanupAllSummons(Player, UUID)} instead
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
private void cleanupAllSummons(@NotNull UUID playerUUID) {
|
||||||
|
cleanupAllSummons(Bukkit.getPlayer(playerUUID), playerUUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kills and cleans up all data related to all summoned entities for a player
|
||||||
|
*
|
||||||
|
* @param player used to send messages, can be null
|
||||||
|
* @param playerUUID used to grab associated data, cannot be null
|
||||||
|
*/
|
||||||
|
private void cleanupAllSummons(@Nullable Player player, @NotNull UUID playerUUID) {
|
||||||
|
for(CallOfTheWildType callOfTheWildType : CallOfTheWildType.values()) {
|
||||||
|
HashSet<TrackedTamingEntity> trackedEntities = getTrackedEntities(playerUUID, callOfTheWildType);
|
||||||
|
|
||||||
|
if(trackedEntities == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImmutableSet<TrackedTamingEntity> immutableSet = ImmutableSet.copyOf(trackedEntities);
|
||||||
|
|
||||||
|
for(TrackedTamingEntity trackedTamingEntity : immutableSet) {
|
||||||
|
//Remove from existence
|
||||||
|
removeSummon(trackedTamingEntity.getLivingEntity(), player, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,32 +2,37 @@ package com.gmail.nossr50.util.blockmeta;
|
|||||||
|
|
||||||
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.Nullable;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.BitSet;
|
import java.util.BitSet;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public class BitSetChunkStore implements ChunkStore, Serializable {
|
public class BitSetChunkStore implements ChunkStore {
|
||||||
private static final long serialVersionUID = -1L;
|
|
||||||
transient private boolean dirty = false;
|
|
||||||
// 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 BitSet store;
|
|
||||||
private static final int CURRENT_VERSION = 8;
|
private static final int CURRENT_VERSION = 8;
|
||||||
private static final int MAGIC_NUMBER = 0xEA5EDEBB;
|
private static final int MAGIC_NUMBER = 0xEA5EDEBB;
|
||||||
private int cx;
|
|
||||||
private int cz;
|
|
||||||
private int worldHeight;
|
|
||||||
private UUID worldUid;
|
|
||||||
|
|
||||||
public BitSetChunkStore(World world, int cx, int cz) {
|
private final int cx;
|
||||||
this.cx = cx;
|
private final int cz;
|
||||||
this.cz = cz;
|
private final int worldHeight;
|
||||||
this.worldUid = world.getUID();
|
private final @NotNull UUID worldUid;
|
||||||
this.worldHeight = world.getMaxHeight();
|
// 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.
|
||||||
this.store = new BitSet(16 * 16 * worldHeight);
|
private final @NotNull BitSet store;
|
||||||
|
|
||||||
|
private transient boolean dirty = false;
|
||||||
|
|
||||||
|
public BitSetChunkStore(@NotNull World world, int cx, int cz) {
|
||||||
|
this(world.getUID(), world.getMaxHeight(), cx, cz);
|
||||||
}
|
}
|
||||||
|
|
||||||
private BitSetChunkStore() {}
|
private BitSetChunkStore(@NotNull UUID worldUid, int worldHeight, int cx, int cz) {
|
||||||
|
this.cx = cx;
|
||||||
|
this.cz = cz;
|
||||||
|
this.worldUid = worldUid;
|
||||||
|
this.worldHeight = worldHeight;
|
||||||
|
this.store = new BitSet(16 * 16 * worldHeight);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isDirty() {
|
public boolean isDirty() {
|
||||||
@ -50,7 +55,7 @@ public class BitSetChunkStore implements ChunkStore, Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UUID getWorldId() {
|
public @NotNull UUID getWorldId() {
|
||||||
return worldUid;
|
return worldUid;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,61 +86,27 @@ public class BitSetChunkStore implements ChunkStore, Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private int coordToIndex(int x, int y, int z) {
|
private int coordToIndex(int x, int y, int z) {
|
||||||
|
return coordToIndex(x, y, z, worldHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int coordToIndex(int x, int y, int z, int worldHeight) {
|
||||||
if (x < 0 || x >= 16 || y < 0 || y >= worldHeight || z < 0 || z >= 16)
|
if (x < 0 || x >= 16 || y < 0 || y >= worldHeight || z < 0 || z >= 16)
|
||||||
throw new IndexOutOfBoundsException();
|
throw new IndexOutOfBoundsException(String.format("x: %d y: %d z: %d World Height: %d", x, y, z, worldHeight));
|
||||||
return (z * 16 + x) + (256 * y);
|
return (z * 16 + x) + (256 * y);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fixWorldHeight() {
|
private static int getWorldHeight(@NotNull UUID worldUid, int storedWorldHeight)
|
||||||
|
{
|
||||||
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;
|
return storedWorldHeight;
|
||||||
|
|
||||||
// Lop off any extra data if the world height has shrunk
|
return world.getMaxHeight();
|
||||||
int currentWorldHeight = world.getMaxHeight();
|
|
||||||
if (currentWorldHeight < worldHeight)
|
|
||||||
{
|
|
||||||
store.clear(coordToIndex(16, currentWorldHeight, 16), store.length());
|
|
||||||
worldHeight = currentWorldHeight;
|
|
||||||
dirty = true;
|
|
||||||
}
|
|
||||||
// If the world height has grown, update the worldHeight variable, but don't bother marking it dirty as unless something else changes we don't need to force a file write;
|
|
||||||
else if (currentWorldHeight > worldHeight)
|
|
||||||
worldHeight = currentWorldHeight;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
private void serialize(@NotNull DataOutputStream out) throws IOException {
|
||||||
private void writeObject(ObjectOutputStream out) throws IOException {
|
|
||||||
throw new UnsupportedOperationException("Serializable support should only be used for legacy deserialization");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
|
||||||
in.readInt(); // Magic number
|
|
||||||
in.readInt(); // Format version
|
|
||||||
long lsb = in.readLong();
|
|
||||||
long msb = in.readLong();
|
|
||||||
worldUid = new UUID(msb, lsb);
|
|
||||||
cx = in.readInt();
|
|
||||||
cz = in.readInt();
|
|
||||||
|
|
||||||
boolean[][][] oldStore = (boolean[][][]) in.readObject();
|
|
||||||
worldHeight = oldStore[0][0].length;
|
|
||||||
store = new BitSet(16 * 16 * worldHeight / 8);
|
|
||||||
for (int x = 0; x < 16; x++) {
|
|
||||||
for (int z = 0; z < 16; z++) {
|
|
||||||
for (int y = 0; y < worldHeight; y++) {
|
|
||||||
store.set(coordToIndex(x, y, z), oldStore[x][z][y]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dirty = true;
|
|
||||||
fixWorldHeight();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void serialize(DataOutputStream out) throws IOException {
|
|
||||||
out.writeInt(MAGIC_NUMBER);
|
out.writeInt(MAGIC_NUMBER);
|
||||||
out.writeInt(CURRENT_VERSION);
|
out.writeInt(CURRENT_VERSION);
|
||||||
|
|
||||||
@ -153,7 +124,7 @@ public class BitSetChunkStore implements ChunkStore, Serializable {
|
|||||||
dirty = false;
|
dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BitSetChunkStore deserialize(DataInputStream in) throws IOException {
|
private static @NotNull BitSetChunkStore deserialize(@NotNull DataInputStream in) throws IOException {
|
||||||
int magic = in.readInt();
|
int magic = in.readInt();
|
||||||
// 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();
|
||||||
@ -161,28 +132,36 @@ public class BitSetChunkStore implements ChunkStore, Serializable {
|
|||||||
if (magic != MAGIC_NUMBER || fileVersionNumber != CURRENT_VERSION)
|
if (magic != MAGIC_NUMBER || fileVersionNumber != CURRENT_VERSION)
|
||||||
throw new IOException();
|
throw new IOException();
|
||||||
|
|
||||||
BitSetChunkStore chunkStore = new BitSetChunkStore();
|
|
||||||
|
|
||||||
long lsb = in.readLong();
|
long lsb = in.readLong();
|
||||||
long msb = in.readLong();
|
long msb = in.readLong();
|
||||||
chunkStore.worldUid = new UUID(msb, lsb);
|
UUID worldUid = new UUID(msb, lsb);
|
||||||
chunkStore.cx = in.readInt();
|
int cx = in.readInt();
|
||||||
chunkStore.cz = in.readInt();
|
int cz = in.readInt();
|
||||||
|
|
||||||
chunkStore.worldHeight = in.readInt();
|
int worldHeight = in.readInt();
|
||||||
byte[] temp = new byte[in.readInt()];
|
byte[] temp = new byte[in.readInt()];
|
||||||
in.readFully(temp);
|
in.readFully(temp);
|
||||||
chunkStore.store = BitSet.valueOf(temp);
|
BitSet stored = BitSet.valueOf(temp);
|
||||||
|
|
||||||
|
int currentWorldHeight = getWorldHeight(worldUid, worldHeight);
|
||||||
|
|
||||||
|
boolean worldHeightShrunk = currentWorldHeight < worldHeight;
|
||||||
|
// Lop off extra data if world height has shrunk
|
||||||
|
if (worldHeightShrunk)
|
||||||
|
stored.clear(coordToIndex(16, currentWorldHeight, 16, worldHeight), stored.length());
|
||||||
|
|
||||||
|
BitSetChunkStore chunkStore = new BitSetChunkStore(worldUid, currentWorldHeight, cx, cz);
|
||||||
|
chunkStore.store.or(stored);
|
||||||
|
chunkStore.dirty = worldHeightShrunk; // In the expanded case there is no reason to re-write it unless the data changes
|
||||||
|
|
||||||
chunkStore.fixWorldHeight();
|
|
||||||
return chunkStore;
|
return chunkStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Serialization {
|
public static class Serialization {
|
||||||
|
|
||||||
public static final short STREAM_MAGIC = (short)0xACDC;
|
public static final short STREAM_MAGIC = (short)0xACDC; // Rock on
|
||||||
|
|
||||||
public static ChunkStore readChunkStore(DataInputStream inputStream) throws IOException {
|
public static @Nullable ChunkStore readChunkStore(@NotNull DataInputStream inputStream) throws IOException {
|
||||||
if (inputStream.markSupported())
|
if (inputStream.markSupported())
|
||||||
inputStream.mark(2);
|
inputStream.mark(2);
|
||||||
short magicNumber = inputStream.readShort();
|
short magicNumber = inputStream.readShort();
|
||||||
@ -196,7 +175,7 @@ public class BitSetChunkStore implements ChunkStore, Serializable {
|
|||||||
{
|
{
|
||||||
// Creates a new stream with the two magic number bytes and then the rest of the original stream... Java is so dumb. I just wanted to look at two bytes.
|
// Creates a new stream with the two magic number bytes and then the rest of the original stream... Java is so dumb. I just wanted to look at two bytes.
|
||||||
PushbackInputStream pushbackInputStream = new PushbackInputStream(inputStream, 2);
|
PushbackInputStream pushbackInputStream = new PushbackInputStream(inputStream, 2);
|
||||||
pushbackInputStream.unread((magicNumber >>> 0) & 0xFF);
|
pushbackInputStream.unread((magicNumber) & 0xFF);
|
||||||
pushbackInputStream.unread((magicNumber >>> 8) & 0xFF);
|
pushbackInputStream.unread((magicNumber >>> 8) & 0xFF);
|
||||||
inputStream = new DataInputStream(pushbackInputStream);
|
inputStream = new DataInputStream(pushbackInputStream);
|
||||||
}
|
}
|
||||||
@ -209,31 +188,85 @@ public class BitSetChunkStore implements ChunkStore, Serializable {
|
|||||||
throw new IOException("Bad Data Format");
|
throw new IOException("Bad Data Format");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void writeChunkStore(DataOutputStream outputStream, ChunkStore chunkStore) throws IOException {
|
public static void writeChunkStore(@NotNull DataOutputStream outputStream, @NotNull ChunkStore chunkStore) throws IOException {
|
||||||
if (!(chunkStore instanceof BitSetChunkStore))
|
if (!(chunkStore instanceof BitSetChunkStore))
|
||||||
throw new InvalidClassException("ChunkStore must be instance of BitSetChunkStore");
|
throw new InvalidClassException("ChunkStore must be instance of BitSetChunkStore");
|
||||||
outputStream.writeShort(STREAM_MAGIC);
|
outputStream.writeShort(STREAM_MAGIC);
|
||||||
((BitSetChunkStore)chunkStore).serialize(outputStream);
|
((BitSetChunkStore)chunkStore).serialize(outputStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handles loading the old serialized classes even though we have changed name/package
|
// Handles loading the old serialized class
|
||||||
private static class LegacyDeserializationInputStream extends ObjectInputStream {
|
private static class LegacyDeserializationInputStream extends ObjectInputStream {
|
||||||
public LegacyDeserializationInputStream(InputStream in) throws IOException {
|
private static class LegacyChunkStoreDeserializer implements Serializable
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = -1L;
|
||||||
|
|
||||||
|
private int cx;
|
||||||
|
private int cz;
|
||||||
|
private int worldHeight;
|
||||||
|
private UUID worldUid;
|
||||||
|
private boolean[][][] store;
|
||||||
|
|
||||||
|
private LegacyChunkStoreDeserializer() {}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
private void writeObject(@NotNull ObjectOutputStream out) throws IOException {
|
||||||
|
throw new UnsupportedOperationException("You goofed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
private void readObject(@NotNull ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||||
|
in.readInt(); // Magic number
|
||||||
|
in.readInt(); // Format version
|
||||||
|
long lsb = in.readLong();
|
||||||
|
long msb = in.readLong();
|
||||||
|
|
||||||
|
worldUid = new UUID(msb, lsb);
|
||||||
|
cx = in.readInt();
|
||||||
|
cz = in.readInt();
|
||||||
|
|
||||||
|
store = (boolean[][][]) in.readObject();
|
||||||
|
worldHeight = store[0][0].length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull BitSetChunkStore convert()
|
||||||
|
{
|
||||||
|
int currentWorldHeight = getWorldHeight(worldUid, worldHeight);
|
||||||
|
|
||||||
|
BitSetChunkStore converted = new BitSetChunkStore(worldUid, currentWorldHeight, cx, cz);
|
||||||
|
|
||||||
|
// Read old data into new chunkstore
|
||||||
|
for (int x = 0; x < 16; x++) {
|
||||||
|
for (int z = 0; z < 16; z++) {
|
||||||
|
for (int y = 0; y < worldHeight && y < currentWorldHeight; y++) {
|
||||||
|
converted.store.set(converted.coordToIndex(x, y, z), store[x][z][y]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Mark dirty so it will be re-written in new format on close
|
||||||
|
converted.dirty = true;
|
||||||
|
return converted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public LegacyDeserializationInputStream(@NotNull InputStream in) throws IOException {
|
||||||
super(in);
|
super(in);
|
||||||
enableResolveObject(true);
|
enableResolveObject(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException {
|
protected @NotNull ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException {
|
||||||
ObjectStreamClass read = super.readClassDescriptor();
|
ObjectStreamClass read = super.readClassDescriptor();
|
||||||
if (read.getName().contentEquals("com.gmail.nossr50.util.blockmeta.chunkmeta.PrimitiveChunkStore"))
|
if (read.getName().contentEquals("com.gmail.nossr50.util.blockmeta.chunkmeta.PrimitiveChunkStore"))
|
||||||
return ObjectStreamClass.lookup(BitSetChunkStore.class);
|
return ObjectStreamClass.lookup(LegacyChunkStoreDeserializer.class);
|
||||||
return read;
|
return read;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChunkStore readLegacyChunkStore(){
|
public @Nullable ChunkStore readLegacyChunkStore(){
|
||||||
try {
|
try {
|
||||||
return (ChunkStore) readObject();
|
LegacyChunkStoreDeserializer deserializer = (LegacyChunkStoreDeserializer)readObject();
|
||||||
|
return deserializer.convert();
|
||||||
} catch (IOException | ClassNotFoundException e) {
|
} catch (IOException | ClassNotFoundException e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -1,126 +1,10 @@
|
|||||||
package com.gmail.nossr50.util.blockmeta;
|
package com.gmail.nossr50.util.blockmeta;
|
||||||
|
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.block.Block;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.bukkit.block.BlockState;
|
|
||||||
|
|
||||||
public interface ChunkManager {
|
public interface ChunkManager extends UserBlockTracker {
|
||||||
void closeAll();
|
void closeAll();
|
||||||
|
void chunkUnloaded(int cx, int cz, @NotNull World world);
|
||||||
/**
|
void unloadWorld(@NotNull World world);
|
||||||
* Saves a given Chunk's Chunklet data
|
|
||||||
*
|
|
||||||
* @param cx Chunk X coordinate that is to be saved
|
|
||||||
* @param cz Chunk Z coordinate that is to be saved
|
|
||||||
* @param world World that the Chunk is in
|
|
||||||
*/
|
|
||||||
void saveChunk(int cx, int cz, World world);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Informs the ChunkletManager a chunk is unloaded
|
|
||||||
*
|
|
||||||
* @param cx Chunk X coordinate that is unloaded
|
|
||||||
* @param cz Chunk Z coordinate that is unloaded
|
|
||||||
* @param world World that the chunk was unloaded in
|
|
||||||
*/
|
|
||||||
void chunkUnloaded(int cx, int cz, World world);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Save all ChunkletStores related to the given world
|
|
||||||
*
|
|
||||||
* @param world World to save
|
|
||||||
*/
|
|
||||||
void saveWorld(World world);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unload all ChunkletStores from memory related to the given world after saving them
|
|
||||||
*
|
|
||||||
* @param world World to unload
|
|
||||||
*/
|
|
||||||
void unloadWorld(World world);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Save all ChunkletStores
|
|
||||||
*/
|
|
||||||
void saveAll();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check to see if a given location is set to true
|
|
||||||
*
|
|
||||||
* @param x X coordinate to check
|
|
||||||
* @param y Y coordinate to check
|
|
||||||
* @param z Z coordinate to check
|
|
||||||
* @param world World to check in
|
|
||||||
* @return true if the given location is set to true, false if otherwise
|
|
||||||
*/
|
|
||||||
boolean isTrue(int x, int y, int z, World world);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check to see if a given block location is set to true
|
|
||||||
*
|
|
||||||
* @param block Block location to check
|
|
||||||
* @return true if the given block location is set to true, false if otherwise
|
|
||||||
*/
|
|
||||||
boolean isTrue(Block block);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check to see if a given BlockState location is set to true
|
|
||||||
*
|
|
||||||
* @param blockState BlockState to check
|
|
||||||
* @return true if the given BlockState location is set to true, false if otherwise
|
|
||||||
*/
|
|
||||||
boolean isTrue(BlockState blockState);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a given location to true, should create stores as necessary if the location does not exist
|
|
||||||
*
|
|
||||||
* @param x X coordinate to set
|
|
||||||
* @param y Y coordinate to set
|
|
||||||
* @param z Z coordinate to set
|
|
||||||
* @param world World to set in
|
|
||||||
*/
|
|
||||||
void setTrue(int x, int y, int z, World world);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a given block location to true, should create stores as necessary if the location does not exist
|
|
||||||
*
|
|
||||||
* @param block Block location to set
|
|
||||||
*/
|
|
||||||
void setTrue(Block block);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a given BlockState location to true, should create stores as necessary if the location does not exist
|
|
||||||
*
|
|
||||||
* @param blockState BlockState location to set
|
|
||||||
*/
|
|
||||||
void setTrue(BlockState blockState);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a given location to false, should not create stores if one does not exist for the given location
|
|
||||||
*
|
|
||||||
* @param x X coordinate to set
|
|
||||||
* @param y Y coordinate to set
|
|
||||||
* @param z Z coordinate to set
|
|
||||||
* @param world World to set in
|
|
||||||
*/
|
|
||||||
void setFalse(int x, int y, int z, World world);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a given block location to false, should not create stores if one does not exist for the given location
|
|
||||||
*
|
|
||||||
* @param block Block location to set
|
|
||||||
*/
|
|
||||||
void setFalse(Block block);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a given BlockState location to false, should not create stores if one does not exist for the given location
|
|
||||||
*
|
|
||||||
* @param blockState BlockState location to set
|
|
||||||
*/
|
|
||||||
void setFalse(BlockState blockState);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete any ChunkletStores that are empty
|
|
||||||
*/
|
|
||||||
void cleanUp();
|
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
package com.gmail.nossr50.util.blockmeta;
|
package com.gmail.nossr50.util.blockmeta;
|
||||||
|
|
||||||
import com.gmail.nossr50.config.HiddenConfig;
|
import com.gmail.nossr50.config.HiddenConfig;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
public class ChunkManagerFactory {
|
public class ChunkManagerFactory {
|
||||||
public static ChunkManager getChunkManager() {
|
public static @NotNull ChunkManager getChunkManager() {
|
||||||
HiddenConfig hConfig = HiddenConfig.getInstance();
|
HiddenConfig hConfig = HiddenConfig.getInstance();
|
||||||
|
|
||||||
if (hConfig.getChunkletsEnabled()) {
|
if (hConfig.getChunkletsEnabled()) {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package com.gmail.nossr50.util.blockmeta;
|
package com.gmail.nossr50.util.blockmeta;
|
||||||
|
|
||||||
import org.bukkit.World;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ public interface ChunkStore {
|
|||||||
*/
|
*/
|
||||||
int getChunkZ();
|
int getChunkZ();
|
||||||
|
|
||||||
UUID getWorldId();
|
@NotNull UUID getWorldId();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks the value at the given coordinates
|
* Checks the value at the given coordinates
|
||||||
|
@ -1,12 +1,16 @@
|
|||||||
package com.gmail.nossr50.util.blockmeta;
|
package com.gmail.nossr50.util.blockmeta;
|
||||||
|
|
||||||
import com.gmail.nossr50.mcMMO;
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.block.Block;
|
import org.bukkit.block.Block;
|
||||||
import org.bukkit.block.BlockState;
|
import org.bukkit.block.BlockState;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.DataInputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class HashChunkManager implements ChunkManager {
|
public class HashChunkManager implements ChunkManager {
|
||||||
@ -21,7 +25,10 @@ public class HashChunkManager implements ChunkManager {
|
|||||||
{
|
{
|
||||||
if (!chunkStore.isDirty())
|
if (!chunkStore.isDirty())
|
||||||
continue;
|
continue;
|
||||||
writeChunkStore(Bukkit.getWorld(chunkStore.getWorldId()), chunkStore);
|
World world = Bukkit.getWorld(chunkStore.getWorldId());
|
||||||
|
if (world == null)
|
||||||
|
continue; // Oh well
|
||||||
|
writeChunkStore(world, chunkStore);
|
||||||
}
|
}
|
||||||
// Clear in memory chunks
|
// Clear in memory chunks
|
||||||
chunkMap.clear();
|
chunkMap.clear();
|
||||||
@ -32,7 +39,7 @@ public class HashChunkManager implements ChunkManager {
|
|||||||
regionMap.clear();
|
regionMap.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized ChunkStore readChunkStore(World world, int cx, int cz) throws IOException {
|
private synchronized @Nullable ChunkStore readChunkStore(@NotNull World world, int cx, int cz) throws IOException {
|
||||||
McMMOSimpleRegionFile rf = getSimpleRegionFile(world, cx, cz, false);
|
McMMOSimpleRegionFile rf = getSimpleRegionFile(world, cx, cz, false);
|
||||||
if (rf == null)
|
if (rf == null)
|
||||||
return null; // If there is no region file, there can't be a chunk
|
return null; // If there is no region file, there can't be a chunk
|
||||||
@ -43,7 +50,7 @@ public class HashChunkManager implements ChunkManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void writeChunkStore(World world, ChunkStore data) {
|
private synchronized void writeChunkStore(@NotNull World world, @NotNull ChunkStore data) {
|
||||||
if (!data.isDirty())
|
if (!data.isDirty())
|
||||||
return; // Don't save unchanged data
|
return; // Don't save unchanged data
|
||||||
try {
|
try {
|
||||||
@ -58,7 +65,7 @@ public class HashChunkManager implements ChunkManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized McMMOSimpleRegionFile getSimpleRegionFile(World world, int cx, int cz, boolean createIfAbsent) {
|
private synchronized @Nullable McMMOSimpleRegionFile getSimpleRegionFile(@NotNull World world, int cx, int cz, boolean createIfAbsent) {
|
||||||
CoordinateKey regionKey = toRegionKey(world.getUID(), cx, cz);
|
CoordinateKey regionKey = toRegionKey(world.getUID(), cx, cz);
|
||||||
|
|
||||||
return regionMap.computeIfAbsent(regionKey, k -> {
|
return regionMap.computeIfAbsent(regionKey, k -> {
|
||||||
@ -73,7 +80,7 @@ public class HashChunkManager implements ChunkManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private ChunkStore loadChunk(int cx, int cz, World world) {
|
private @Nullable ChunkStore loadChunk(int cx, int cz, @NotNull World world) {
|
||||||
try {
|
try {
|
||||||
return readChunkStore(world, cx, cz);
|
return readChunkStore(world, cx, cz);
|
||||||
}
|
}
|
||||||
@ -82,7 +89,7 @@ public class HashChunkManager implements ChunkManager {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void unloadChunk(int cx, int cz, World world) {
|
private void unloadChunk(int cx, int cz, @NotNull World world) {
|
||||||
CoordinateKey chunkKey = toChunkKey(world.getUID(), cx, cz);
|
CoordinateKey chunkKey = toChunkKey(world.getUID(), cx, cz);
|
||||||
ChunkStore chunkStore = chunkMap.remove(chunkKey); // Remove from chunk map
|
ChunkStore chunkStore = chunkMap.remove(chunkKey); // Remove from chunk map
|
||||||
if (chunkStore == null)
|
if (chunkStore == null)
|
||||||
@ -102,56 +109,12 @@ public class HashChunkManager implements ChunkManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void saveChunk(int cx, int cz, World world) {
|
public synchronized void chunkUnloaded(int cx, int cz, @NotNull World world) {
|
||||||
if (world == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
CoordinateKey chunkKey = toChunkKey(world.getUID(), cx, cz);
|
|
||||||
|
|
||||||
ChunkStore out = chunkMap.get(chunkKey);
|
|
||||||
|
|
||||||
if (out == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!out.isDirty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
writeChunkStore(world, out);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized void chunkUnloaded(int cx, int cz, World world) {
|
|
||||||
if (world == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
unloadChunk(cx, cz, world);
|
unloadChunk(cx, cz, world);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void saveWorld(World world) {
|
public synchronized void unloadWorld(@NotNull World world) {
|
||||||
if (world == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
UUID wID = world.getUID();
|
|
||||||
|
|
||||||
// Save all teh chunks
|
|
||||||
for (ChunkStore chunkStore : chunkMap.values()) {
|
|
||||||
if (!chunkStore.isDirty())
|
|
||||||
continue;
|
|
||||||
if (!wID.equals(chunkStore.getWorldId()))
|
|
||||||
continue;
|
|
||||||
try {
|
|
||||||
writeChunkStore(world, chunkStore);
|
|
||||||
}
|
|
||||||
catch (Exception ignore) { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized void unloadWorld(World world) {
|
|
||||||
if (world == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
UUID wID = world.getUID();
|
UUID wID = world.getUID();
|
||||||
|
|
||||||
// Save and remove all the chunks
|
// Save and remove all the chunks
|
||||||
@ -177,18 +140,7 @@ public class HashChunkManager implements ChunkManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private synchronized boolean isTrue(int x, int y, int z, @NotNull World world) {
|
||||||
public synchronized void saveAll() {
|
|
||||||
for (World world : mcMMO.p.getServer().getWorlds()) {
|
|
||||||
saveWorld(world);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized boolean isTrue(int x, int y, int z, World world) {
|
|
||||||
if (world == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
CoordinateKey chunkKey = blockCoordinateToChunkKey(world.getUID(), x, y, z);
|
CoordinateKey chunkKey = blockCoordinateToChunkKey(world.getUID(), x, y, z);
|
||||||
|
|
||||||
// Get chunk, load from file if necessary
|
// Get chunk, load from file if necessary
|
||||||
@ -214,67 +166,36 @@ public class HashChunkManager implements ChunkManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized boolean isTrue(Block block) {
|
public synchronized boolean isTrue(@NotNull Block block) {
|
||||||
if (block == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return isTrue(block.getX(), block.getY(), block.getZ(), block.getWorld());
|
return isTrue(block.getX(), block.getY(), block.getZ(), block.getWorld());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized boolean isTrue(BlockState blockState) {
|
public synchronized boolean isTrue(@NotNull BlockState blockState) {
|
||||||
if (blockState == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return isTrue(blockState.getX(), blockState.getY(), blockState.getZ(), blockState.getWorld());
|
return isTrue(blockState.getX(), blockState.getY(), blockState.getZ(), blockState.getWorld());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void setTrue(int x, int y, int z, World world) {
|
public synchronized void setTrue(@NotNull Block block) {
|
||||||
set(x, y, z, world, true);
|
set(block.getX(), block.getY(), block.getZ(), block.getWorld(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void setTrue(Block block) {
|
public synchronized void setTrue(@NotNull BlockState blockState) {
|
||||||
if (block == null)
|
set(blockState.getX(), blockState.getY(), blockState.getZ(), blockState.getWorld(), true);
|
||||||
return;
|
|
||||||
|
|
||||||
setTrue(block.getX(), block.getY(), block.getZ(), block.getWorld());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void setTrue(BlockState blockState) {
|
public synchronized void setFalse(@NotNull Block block) {
|
||||||
if (blockState == null)
|
set(block.getX(), block.getY(), block.getZ(), block.getWorld(), false);
|
||||||
return;
|
|
||||||
|
|
||||||
setTrue(blockState.getX(), blockState.getY(), blockState.getZ(), blockState.getWorld());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void setFalse(int x, int y, int z, World world) {
|
public synchronized void setFalse(@NotNull BlockState blockState) {
|
||||||
set(x, y, z, world, false);
|
set(blockState.getX(), blockState.getY(), blockState.getZ(), blockState.getWorld(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private synchronized void set(int x, int y, int z, @NotNull World world, boolean value){
|
||||||
public synchronized void setFalse(Block block) {
|
|
||||||
if (block == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
setFalse(block.getX(), block.getY(), block.getZ(), block.getWorld());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized void setFalse(BlockState blockState) {
|
|
||||||
if (blockState == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
setFalse(blockState.getX(), blockState.getY(), blockState.getZ(), blockState.getWorld());
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void set(int x, int y, int z, World world, boolean value){
|
|
||||||
if (world == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
CoordinateKey chunkKey = blockCoordinateToChunkKey(world.getUID(), x, y, z);
|
CoordinateKey chunkKey = blockCoordinateToChunkKey(world.getUID(), x, y, z);
|
||||||
|
|
||||||
// Get/Load/Create chunkstore
|
// Get/Load/Create chunkstore
|
||||||
@ -307,15 +228,15 @@ public class HashChunkManager implements ChunkManager {
|
|||||||
cStore.set(ix, y, iz, value);
|
cStore.set(ix, y, iz, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CoordinateKey blockCoordinateToChunkKey(UUID worldUid, int x, int y, int z) {
|
private CoordinateKey blockCoordinateToChunkKey(@NotNull UUID worldUid, int x, int y, int z) {
|
||||||
return toChunkKey(worldUid, x >> 4, z >> 4);
|
return toChunkKey(worldUid, x >> 4, z >> 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CoordinateKey toChunkKey(UUID worldUid, int cx, int cz){
|
private CoordinateKey toChunkKey(@NotNull UUID worldUid, int cx, int cz){
|
||||||
return new CoordinateKey(worldUid, cx, cz);
|
return new CoordinateKey(worldUid, cx, cz);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CoordinateKey toRegionKey(UUID worldUid, int cx, int cz) {
|
private CoordinateKey toRegionKey(@NotNull UUID worldUid, int cx, int cz) {
|
||||||
// Compute region index (32x32 chunk regions)
|
// Compute region index (32x32 chunk regions)
|
||||||
int rx = cx >> 5;
|
int rx = cx >> 5;
|
||||||
int rz = cz >> 5;
|
int rz = cz >> 5;
|
||||||
@ -323,11 +244,11 @@ public class HashChunkManager implements ChunkManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static final class CoordinateKey {
|
private static final class CoordinateKey {
|
||||||
public final UUID worldID;
|
public final @NotNull UUID worldID;
|
||||||
public final int x;
|
public final int x;
|
||||||
public final int z;
|
public final int z;
|
||||||
|
|
||||||
private CoordinateKey(UUID worldID, int x, int z) {
|
private CoordinateKey(@NotNull UUID worldID, int x, int z) {
|
||||||
this.worldID = worldID;
|
this.worldID = worldID;
|
||||||
this.x = x;
|
this.x = x;
|
||||||
this.z = z;
|
this.z = z;
|
||||||
@ -348,7 +269,4 @@ public class HashChunkManager implements ChunkManager {
|
|||||||
return Objects.hash(worldID, x, z);
|
return Objects.hash(worldID, x, z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized void cleanUp() {}
|
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,9 @@
|
|||||||
*/
|
*/
|
||||||
package com.gmail.nossr50.util.blockmeta;
|
package com.gmail.nossr50.util.blockmeta;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.BitSet;
|
import java.util.BitSet;
|
||||||
import java.util.zip.DeflaterOutputStream;
|
import java.util.zip.DeflaterOutputStream;
|
||||||
@ -54,7 +57,7 @@ public class McMMOSimpleRegionFile {
|
|||||||
private final int segmentMask;
|
private final int segmentMask;
|
||||||
|
|
||||||
// File location
|
// File location
|
||||||
private final File parent;
|
private final @NotNull File parent;
|
||||||
// File access
|
// File access
|
||||||
private final RandomAccessFile file;
|
private final RandomAccessFile file;
|
||||||
|
|
||||||
@ -62,7 +65,7 @@ public class McMMOSimpleRegionFile {
|
|||||||
private final int rx;
|
private final int rx;
|
||||||
private final int rz;
|
private final int rz;
|
||||||
|
|
||||||
public McMMOSimpleRegionFile(File f, int rx, int rz) {
|
public McMMOSimpleRegionFile(@NotNull File f, int rx, int rz) {
|
||||||
this.rx = rx;
|
this.rx = rx;
|
||||||
this.rz = rz;
|
this.rz = rz;
|
||||||
this.parent = f;
|
this.parent = f;
|
||||||
@ -104,7 +107,7 @@ public class McMMOSimpleRegionFile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized DataOutputStream getOutputStream(int x, int z) {
|
public synchronized @NotNull DataOutputStream getOutputStream(int x, int z) {
|
||||||
int index = getChunkIndex(x, z); // Get chunk index
|
int index = getChunkIndex(x, z); // Get chunk index
|
||||||
return new DataOutputStream(new DeflaterOutputStream(new McMMOSimpleChunkBuffer(this, index)));
|
return new DataOutputStream(new DeflaterOutputStream(new McMMOSimpleChunkBuffer(this, index)));
|
||||||
}
|
}
|
||||||
@ -144,7 +147,7 @@ public class McMMOSimpleRegionFile {
|
|||||||
file.writeInt(chunkNumBytes[index]);
|
file.writeInt(chunkNumBytes[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized DataInputStream getInputStream(int x, int z) throws IOException {
|
public synchronized @Nullable DataInputStream getInputStream(int x, int z) throws IOException {
|
||||||
int index = getChunkIndex(x, z); // Get chunk index
|
int index = getChunkIndex(x, z); // Get chunk index
|
||||||
int byteLength = chunkNumBytes[index]; // Get byte length of data
|
int byteLength = chunkNumBytes[index]; // Get byte length of data
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ package com.gmail.nossr50.util.blockmeta;
|
|||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.block.Block;
|
import org.bukkit.block.Block;
|
||||||
import org.bukkit.block.BlockState;
|
import org.bukkit.block.BlockState;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
public class NullChunkManager implements ChunkManager {
|
public class NullChunkManager implements ChunkManager {
|
||||||
|
|
||||||
@ -10,53 +11,30 @@ public class NullChunkManager implements ChunkManager {
|
|||||||
public void closeAll() {}
|
public void closeAll() {}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void saveChunk(int cx, int cz, World world) {}
|
public void chunkUnloaded(int cx, int cz, @NotNull World world) {}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void chunkUnloaded(int cx, int cz, World world) {}
|
public void unloadWorld(@NotNull World world) {}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void saveWorld(World world) {}
|
public boolean isTrue(@NotNull Block block) {
|
||||||
|
|
||||||
@Override
|
|
||||||
public void unloadWorld(World world) {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void saveAll() {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isTrue(int x, int y, int z, World world) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isTrue(Block block) {
|
public boolean isTrue(@NotNull BlockState blockState) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isTrue(BlockState blockState) {
|
public void setTrue(@NotNull Block block) {}
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setTrue(int x, int y, int z, World world) {}
|
public void setTrue(@NotNull BlockState blockState) {}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setTrue(Block block) {}
|
public void setFalse(@NotNull Block block) {}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setTrue(BlockState blockState) {}
|
public void setFalse(@NotNull BlockState blockState) {}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setFalse(int x, int y, int z, World world) {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setFalse(Block block) {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setFalse(BlockState blockState) {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void cleanUp() {}
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,56 @@
|
|||||||
|
package com.gmail.nossr50.util.blockmeta;
|
||||||
|
|
||||||
|
import com.gmail.nossr50.mcMMO;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.block.BlockState;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains blockstore methods that are safe for external plugins to access.
|
||||||
|
* An instance can be retrieved via {@link mcMMO#getPlaceStore() mcMMO.getPlaceStore()}
|
||||||
|
*/
|
||||||
|
public interface UserBlockTracker {
|
||||||
|
/**
|
||||||
|
* Check to see if a given block location is set to true
|
||||||
|
*
|
||||||
|
* @param block Block location to check
|
||||||
|
* @return true if the given block location is set to true, false if otherwise
|
||||||
|
*/
|
||||||
|
boolean isTrue(@NotNull Block block);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check to see if a given BlockState location is set to true
|
||||||
|
*
|
||||||
|
* @param blockState BlockState to check
|
||||||
|
* @return true if the given BlockState location is set to true, false if otherwise
|
||||||
|
*/
|
||||||
|
boolean isTrue(@NotNull BlockState blockState);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a given block location to true
|
||||||
|
*
|
||||||
|
* @param block Block location to set
|
||||||
|
*/
|
||||||
|
void setTrue(@NotNull Block block);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a given BlockState location to true
|
||||||
|
*
|
||||||
|
* @param blockState BlockState location to set
|
||||||
|
*/
|
||||||
|
void setTrue(@NotNull BlockState blockState);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a given block location to false
|
||||||
|
*
|
||||||
|
* @param block Block location to set
|
||||||
|
*/
|
||||||
|
void setFalse(@NotNull Block block);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a given BlockState location to false
|
||||||
|
*
|
||||||
|
* @param blockState BlockState location to set
|
||||||
|
*/
|
||||||
|
void setFalse(@NotNull BlockState blockState);
|
||||||
|
}
|
@ -2,8 +2,12 @@ package com.gmail.nossr50.util.skills;
|
|||||||
|
|
||||||
import com.gmail.nossr50.config.experience.ExperienceConfig;
|
import com.gmail.nossr50.config.experience.ExperienceConfig;
|
||||||
import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
|
import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
|
||||||
|
import com.gmail.nossr50.events.skills.SkillActivationPerkEvent;
|
||||||
import com.gmail.nossr50.mcMMO;
|
import com.gmail.nossr50.mcMMO;
|
||||||
import com.gmail.nossr50.util.Permissions;
|
import com.gmail.nossr50.util.Permissions;
|
||||||
|
import com.gmail.nossr50.util.player.UserManager;
|
||||||
|
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@ -43,7 +47,9 @@ public final class PerksUtils {
|
|||||||
ticks += 4;
|
ticks += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ticks;
|
final SkillActivationPerkEvent skillActivationPerkEvent = new SkillActivationPerkEvent(player, ticks, maxTicks);
|
||||||
|
Bukkit.getPluginManager().callEvent(skillActivationPerkEvent);
|
||||||
|
return skillActivationPerkEvent.getTicks();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static float handleXpPerks(Player player, float xp, PrimarySkillType skill) {
|
public static float handleXpPerks(Player player, float xp, PrimarySkillType skill) {
|
||||||
|
@ -207,50 +207,6 @@ Fishing:
|
|||||||
Amount: 1
|
Amount: 1
|
||||||
XP: 200
|
XP: 200
|
||||||
Rarity: LEGENDARY
|
Rarity: LEGENDARY
|
||||||
MUSIC_DISC_BLOCKS:
|
|
||||||
Amount: 1
|
|
||||||
XP: 200
|
|
||||||
Rarity: UNCOMMON
|
|
||||||
MUSIC_DISC_CHIRP:
|
|
||||||
Amount: 1
|
|
||||||
XP: 200
|
|
||||||
Rarity: UNCOMMON
|
|
||||||
MUSIC_DISC_FAR:
|
|
||||||
Amount: 1
|
|
||||||
XP: 200
|
|
||||||
Rarity: RARE
|
|
||||||
MUSIC_DISC_MALL:
|
|
||||||
Amount: 1
|
|
||||||
XP: 200
|
|
||||||
Rarity: RARE
|
|
||||||
MUSIC_DISC_MELLOHI:
|
|
||||||
Amount: 1
|
|
||||||
XP: 200
|
|
||||||
Rarity: RARE
|
|
||||||
MUSIC_DISC_STAL:
|
|
||||||
Amount: 1
|
|
||||||
XP: 200
|
|
||||||
Rarity: EPIC
|
|
||||||
MUSIC_DISC_STRAD:
|
|
||||||
Amount: 1
|
|
||||||
XP: 200
|
|
||||||
Rarity: EPIC
|
|
||||||
MUSIC_DISC_WARD:
|
|
||||||
Amount: 1
|
|
||||||
XP: 200
|
|
||||||
Rarity: EPIC
|
|
||||||
MUSIC_DISC_11:
|
|
||||||
Amount: 1
|
|
||||||
XP: 200
|
|
||||||
Rarity: LEGENDARY
|
|
||||||
MUSIC_DISC_WAIT:
|
|
||||||
Amount: 1
|
|
||||||
XP: 200
|
|
||||||
Rarity: LEGENDARY
|
|
||||||
MUSIC_DISC_13:
|
|
||||||
Amount: 1
|
|
||||||
XP: 200
|
|
||||||
Rarity: MYTHIC
|
|
||||||
NETHERITE_SWORD:
|
NETHERITE_SWORD:
|
||||||
Amount: 1
|
Amount: 1
|
||||||
XP: 200
|
XP: 200
|
||||||
|
@ -90,7 +90,6 @@ Fishing.SubSkill.Shake.Description=Vyklepni p\u0159edm\u011bty z p\u0159\u00ed\u
|
|||||||
Fishing.SubSkill.FishermansDiet.Name=Ryb\u00e1\u0159\u016fv apetit
|
Fishing.SubSkill.FishermansDiet.Name=Ryb\u00e1\u0159\u016fv apetit
|
||||||
Fishing.SubSkill.FishermansDiet.Description=Zlep\u0161uje dopl\u0148ov\u00e1n\u00ed hladu z naryba\u0159en\u00fdch j\u00eddel
|
Fishing.SubSkill.FishermansDiet.Description=Zlep\u0161uje dopl\u0148ov\u00e1n\u00ed hladu z naryba\u0159en\u00fdch j\u00eddel
|
||||||
Fishing.SubSkill.MasterAngler.Name=Mistr Ryb\u00e1\u0159
|
Fishing.SubSkill.MasterAngler.Name=Mistr Ryb\u00e1\u0159
|
||||||
Fishing.SubSkill.MasterAngler.Description=Zvy\u0161uje \u0161anci zah\u00e1knut\u00ed ryby p\u0159i ryba\u0159en\u00ed
|
|
||||||
Fishing.SubSkill.IceFishing.Name=Ryba\u0159en\u00ed v ledu
|
Fishing.SubSkill.IceFishing.Name=Ryba\u0159en\u00ed v ledu
|
||||||
Fishing.SubSkill.IceFishing.Description=Umo\u017e\u0148uje v\u00e1m ryba\u0159it v ledov\u00fdch prost\u0159ed\u00edch
|
Fishing.SubSkill.IceFishing.Description=Umo\u017e\u0148uje v\u00e1m ryba\u0159it v ledov\u00fdch prost\u0159ed\u00edch
|
||||||
Fishing.Chance.Raining=&9 De\u0161\u0165ov\u00fd bonus
|
Fishing.Chance.Raining=&9 De\u0161\u0165ov\u00fd bonus
|
||||||
|
@ -372,7 +372,6 @@ Fishing.SubSkill.IceFishing.Stat = Eisangeln
|
|||||||
Fishing.SubSkill.MagicHunter.Description = Finde verzauberte Gegenst\u00E4nde
|
Fishing.SubSkill.MagicHunter.Description = Finde verzauberte Gegenst\u00E4nde
|
||||||
Fishing.SubSkill.MagicHunter.Name = Zauber J\u00E4ger
|
Fishing.SubSkill.MagicHunter.Name = Zauber J\u00E4ger
|
||||||
Fishing.SubSkill.MagicHunter.Stat = Zauber J\u00E4ger Chance
|
Fishing.SubSkill.MagicHunter.Stat = Zauber J\u00E4ger Chance
|
||||||
Fishing.SubSkill.MasterAngler.Description = Erh\u00F6ht die Chance des Anbei\u00DFens beim Angeln
|
|
||||||
Fishing.SubSkill.MasterAngler.Name = Superangel
|
Fishing.SubSkill.MasterAngler.Name = Superangel
|
||||||
Fishing.SubSkill.Shake.Description = Rei\u00DFe Gegenst\u00E4nde weg von Lebewesen und Spielern mit deiner Angel
|
Fishing.SubSkill.Shake.Description = Rei\u00DFe Gegenst\u00E4nde weg von Lebewesen und Spielern mit deiner Angel
|
||||||
Fishing.SubSkill.Shake.Name = Rei\u00DFen
|
Fishing.SubSkill.Shake.Name = Rei\u00DFen
|
||||||
|
@ -258,7 +258,7 @@ Fishing.SubSkill.FishermansDiet.Name=Fisherman's Diet
|
|||||||
Fishing.SubSkill.FishermansDiet.Description=Improves hunger restored from fished foods
|
Fishing.SubSkill.FishermansDiet.Description=Improves hunger restored from fished foods
|
||||||
Fishing.SubSkill.FishermansDiet.Stat=Fisherman's Diet:&a Rank {0}
|
Fishing.SubSkill.FishermansDiet.Stat=Fisherman's Diet:&a Rank {0}
|
||||||
Fishing.SubSkill.MasterAngler.Name=Master Angler
|
Fishing.SubSkill.MasterAngler.Name=Master Angler
|
||||||
Fishing.SubSkill.MasterAngler.Description=Fish are caught more frequently
|
Fishing.SubSkill.MasterAngler.Description=Fish are caught more frequently, works better when fishing from a boat.
|
||||||
Fishing.SubSkill.MasterAngler.Stat=Fishing min wait time reduction: &a-{0} seconds
|
Fishing.SubSkill.MasterAngler.Stat=Fishing min wait time reduction: &a-{0} seconds
|
||||||
Fishing.SubSkill.MasterAngler.Stat.Extra=Fishing max wait time reduction: &a-{0} seconds
|
Fishing.SubSkill.MasterAngler.Stat.Extra=Fishing max wait time reduction: &a-{0} seconds
|
||||||
Fishing.SubSkill.IceFishing.Name=Ice Fishing
|
Fishing.SubSkill.IceFishing.Name=Ice Fishing
|
||||||
@ -493,6 +493,7 @@ Taming.Summon.COTW.Success.WithoutLifespan=&a(Call Of The Wild) &7You have summo
|
|||||||
Taming.Summon.COTW.Success.WithLifespan=&a(Call Of The Wild) &7You have summoned a &6{0}&7 and it has a duration of &6{1}&7 seconds.
|
Taming.Summon.COTW.Success.WithLifespan=&a(Call Of The Wild) &7You have summoned a &6{0}&7 and it has a duration of &6{1}&7 seconds.
|
||||||
Taming.Summon.COTW.Limit=&a(Call Of The Wild) &7You can only have &c{0} &7summoned &7{1} pets at the same time.
|
Taming.Summon.COTW.Limit=&a(Call Of The Wild) &7You can only have &c{0} &7summoned &7{1} pets at the same time.
|
||||||
Taming.Summon.COTW.TimeExpired=&a(Call Of The Wild) &7Time is up, your &6{0}&7 departs.
|
Taming.Summon.COTW.TimeExpired=&a(Call Of The Wild) &7Time is up, your &6{0}&7 departs.
|
||||||
|
Taming.Summon.COTW.Removed=&a(Call Of The Wild) &7Your summoned &6{0}&7 has vanished from this world.
|
||||||
Taming.Summon.COTW.BreedingDisallowed=&a(Call Of The Wild) &cYou cannot breed a summoned animal.
|
Taming.Summon.COTW.BreedingDisallowed=&a(Call Of The Wild) &cYou cannot breed a summoned animal.
|
||||||
Taming.Summon.COTW.NeedMoreItems=&a(Call Of The Wild) &7You need &e{0}&7 more &3{1}&7(s)
|
Taming.Summon.COTW.NeedMoreItems=&a(Call Of The Wild) &7You need &e{0}&7 more &3{1}&7(s)
|
||||||
Taming.Summon.Name.Format=&6(COTW) &f{0}'s {1}
|
Taming.Summon.Name.Format=&6(COTW) &f{0}'s {1}
|
||||||
|
@ -91,7 +91,6 @@ Fishing.SubSkill.Shake.Description=Sacudir los items fuera de los monstruos con
|
|||||||
Fishing.SubSkill.FishermansDiet.Name=Dieta del pescador
|
Fishing.SubSkill.FishermansDiet.Name=Dieta del pescador
|
||||||
Fishing.SubSkill.FishermansDiet.Description=Mejora el hambre restaurada a partir de alimentos pescados
|
Fishing.SubSkill.FishermansDiet.Description=Mejora el hambre restaurada a partir de alimentos pescados
|
||||||
Fishing.SubSkill.MasterAngler.Name=Maestro pescador
|
Fishing.SubSkill.MasterAngler.Name=Maestro pescador
|
||||||
Fishing.SubSkill.MasterAngler.Description=Aumenta la probabilidad de ser mordido mientras se pesca
|
|
||||||
Fishing.SubSkill.IceFishing.Name=Pesca de hielo
|
Fishing.SubSkill.IceFishing.Name=Pesca de hielo
|
||||||
Fishing.SubSkill.IceFishing.Description=Te permite pescar en biomas de hielo
|
Fishing.SubSkill.IceFishing.Description=Te permite pescar en biomas de hielo
|
||||||
Fishing.Chance.Raining=&9 Lluvia de Bonus
|
Fishing.Chance.Raining=&9 Lluvia de Bonus
|
||||||
|
@ -251,7 +251,6 @@ Fishing.SubSkill.FishermansDiet.Name=R\u00e9gime de fermier
|
|||||||
Fishing.SubSkill.FishermansDiet.Description=Am\u00e9liore la nutrition des produits de la ferme
|
Fishing.SubSkill.FishermansDiet.Description=Am\u00e9liore la nutrition des produits de la ferme
|
||||||
Fishing.SubSkill.FishermansDiet.Stat=R\u00e9gime de fermier:&a Grade {0}
|
Fishing.SubSkill.FishermansDiet.Stat=R\u00e9gime de fermier:&a Grade {0}
|
||||||
Fishing.SubSkill.MasterAngler.Name=Ma\u00eetre P\u00eacheur
|
Fishing.SubSkill.MasterAngler.Name=Ma\u00eetre P\u00eacheur
|
||||||
Fishing.SubSkill.MasterAngler.Description=Augmente les chances que \u00e7a morde lors de la p\u00eache
|
|
||||||
Fishing.SubSkill.IceFishing.Name=P\u00eache sur Glace
|
Fishing.SubSkill.IceFishing.Name=P\u00eache sur Glace
|
||||||
Fishing.SubSkill.IceFishing.Description=Vous permet de p\u00eacher dans les biomes glac\u00e9s
|
Fishing.SubSkill.IceFishing.Description=Vous permet de p\u00eacher dans les biomes glac\u00e9s
|
||||||
Fishing.SubSkill.IceFishing.Stat=P\u00eache sur Glace
|
Fishing.SubSkill.IceFishing.Stat=P\u00eache sur Glace
|
||||||
|
@ -251,7 +251,6 @@ Fishing.SubSkill.FishermansDiet.Name=Horg\u00E1szok Di\u00E9t\u00E1ja
|
|||||||
Fishing.SubSkill.FishermansDiet.Description=N\u00F6veli a kihal\u00E1szott \u00E9telek t\u00E1p\u00E9rt\u00E9k\u00E9t
|
Fishing.SubSkill.FishermansDiet.Description=N\u00F6veli a kihal\u00E1szott \u00E9telek t\u00E1p\u00E9rt\u00E9k\u00E9t
|
||||||
Fishing.SubSkill.FishermansDiet.Stat=Horg\u00E1szok Di\u00E9t\u00E1ja:&a Szint {0}
|
Fishing.SubSkill.FishermansDiet.Stat=Horg\u00E1szok Di\u00E9t\u00E1ja:&a Szint {0}
|
||||||
Fishing.SubSkill.MasterAngler.Name=Mester Horg\u00E1sz
|
Fishing.SubSkill.MasterAngler.Name=Mester Horg\u00E1sz
|
||||||
Fishing.SubSkill.MasterAngler.Description=N\u00F6veli a Kap\u00E1s es\u00E9ly\u00E9t horg\u00E1szat k\u00F6zben
|
|
||||||
Fishing.SubSkill.IceFishing.Name=J\u00E9g Horg\u00E1szat
|
Fishing.SubSkill.IceFishing.Name=J\u00E9g Horg\u00E1szat
|
||||||
Fishing.SubSkill.IceFishing.Description=Lehet\u0151v\u00E9 teszi sz\u00E1modra, hogy fagyos t\u00E1jakon is horg\u00E1szhass
|
Fishing.SubSkill.IceFishing.Description=Lehet\u0151v\u00E9 teszi sz\u00E1modra, hogy fagyos t\u00E1jakon is horg\u00E1szhass
|
||||||
Fishing.SubSkill.IceFishing.Stat=J\u00E9g Horg\u00E1szat
|
Fishing.SubSkill.IceFishing.Stat=J\u00E9g Horg\u00E1szat
|
||||||
|
@ -258,7 +258,6 @@ Fishing.SubSkill.FishermansDiet.Name=Dieta del Pescatore
|
|||||||
Fishing.SubSkill.FishermansDiet.Description=Aumenta la fame recuperata tramite cibi pescati
|
Fishing.SubSkill.FishermansDiet.Description=Aumenta la fame recuperata tramite cibi pescati
|
||||||
Fishing.SubSkill.FishermansDiet.Stat=Dieta del Pescatore:&a Grado {0}
|
Fishing.SubSkill.FishermansDiet.Stat=Dieta del Pescatore:&a Grado {0}
|
||||||
Fishing.SubSkill.MasterAngler.Name=Pescatore Provetto
|
Fishing.SubSkill.MasterAngler.Name=Pescatore Provetto
|
||||||
Fishing.SubSkill.MasterAngler.Description=Migliora la possibilit\u00E0 di ottenere un morso durante la pesca
|
|
||||||
Fishing.SubSkill.IceFishing.Name=Pesca sul Ghiaccio
|
Fishing.SubSkill.IceFishing.Name=Pesca sul Ghiaccio
|
||||||
Fishing.SubSkill.IceFishing.Description=Ti permette di pescare in biomi ghiacciati
|
Fishing.SubSkill.IceFishing.Description=Ti permette di pescare in biomi ghiacciati
|
||||||
Fishing.SubSkill.IceFishing.Stat=Pesca sul Ghiaccio
|
Fishing.SubSkill.IceFishing.Stat=Pesca sul Ghiaccio
|
||||||
|
@ -241,7 +241,6 @@ Fishing.SubSkill.FishermansDiet.Name=\u6f01\u5e2b\u306e\u98df\u4e8b
|
|||||||
Fishing.SubSkill.FishermansDiet.Description=\u9b5a\u4ecb\u985e\u304b\u3089\u56de\u5fa9\u3059\u308b\u6e80\u8179\u5ea6\u3092\u6539\u5584\u3059\u308b\u3002
|
Fishing.SubSkill.FishermansDiet.Description=\u9b5a\u4ecb\u985e\u304b\u3089\u56de\u5fa9\u3059\u308b\u6e80\u8179\u5ea6\u3092\u6539\u5584\u3059\u308b\u3002
|
||||||
Fishing.SubSkill.FishermansDiet.Stat=\u6f01\u5e2b\u306e\u98df\u4e8b:&a \u30e9\u30f3\u30af {0}
|
Fishing.SubSkill.FishermansDiet.Stat=\u6f01\u5e2b\u306e\u98df\u4e8b:&a \u30e9\u30f3\u30af {0}
|
||||||
Fishing.SubSkill.MasterAngler.Name=\u30de\u30b9\u30bf\u30fc\u30a2\u30f3\u30b0\u30e9\u30fc
|
Fishing.SubSkill.MasterAngler.Name=\u30de\u30b9\u30bf\u30fc\u30a2\u30f3\u30b0\u30e9\u30fc
|
||||||
Fishing.SubSkill.MasterAngler.Description=\u91e3\u308c\u308b\u78ba\u7387\u304c\u4e0a\u304c\u308a\u307e\u3059\u3002
|
|
||||||
Fishing.SubSkill.IceFishing.Name=\u7a74\u91e3\u308a
|
Fishing.SubSkill.IceFishing.Name=\u7a74\u91e3\u308a
|
||||||
Fishing.SubSkill.IceFishing.Description=\u5bd2\u3044\u30d0\u30a4\u30aa\u30fc\u30e0\u3067\u306e\u91e3\u308a\u304c\u3067\u304d\u308b\u3088\u3046\u306b\u306a\u308b\u3002
|
Fishing.SubSkill.IceFishing.Description=\u5bd2\u3044\u30d0\u30a4\u30aa\u30fc\u30e0\u3067\u306e\u91e3\u308a\u304c\u3067\u304d\u308b\u3088\u3046\u306b\u306a\u308b\u3002
|
||||||
Fishing.SubSkill.IceFishing.Stat=\u7a74\u91e3\u308a
|
Fishing.SubSkill.IceFishing.Stat=\u7a74\u91e3\u308a
|
||||||
|
@ -132,7 +132,6 @@ Fishing.SubSkill.Shake.Description=\uC544\uC774\uD15C\uC744 \uBAB9\uC774\uB098 \
|
|||||||
Fishing.SubSkill.FishermansDiet.Name=\uC5B4\uBD80\uC758 \uB2E4\uC774\uC5B4\uD2B8
|
Fishing.SubSkill.FishermansDiet.Name=\uC5B4\uBD80\uC758 \uB2E4\uC774\uC5B4\uD2B8
|
||||||
Fishing.SubSkill.FishermansDiet.Description=\uC5B4\uB958 \uC74C\uC2DD \uD5C8\uAE30 \uD68C\uBCF5 \uC99D\uAC00
|
Fishing.SubSkill.FishermansDiet.Description=\uC5B4\uB958 \uC74C\uC2DD \uD5C8\uAE30 \uD68C\uBCF5 \uC99D\uAC00
|
||||||
Fishing.SubSkill.MasterAngler.Name=\uB09A\uC2DC\uAFBC \uC7A5\uC778
|
Fishing.SubSkill.MasterAngler.Name=\uB09A\uC2DC\uAFBC \uC7A5\uC778
|
||||||
Fishing.SubSkill.MasterAngler.Description=\uB09A\uC2DC\uC911 \uC785\uC9C8 \uD655\uB960 \uC99D\uAC00
|
|
||||||
Fishing.SubSkill.IceFishing.Name=\uC5BC\uC74C \uB09A\uC2DC
|
Fishing.SubSkill.IceFishing.Name=\uC5BC\uC74C \uB09A\uC2DC
|
||||||
Fishing.SubSkill.IceFishing.Description=\uC5BC\uC74C\uC774 \uB36E\uD600\uC788\uB294 \uD658\uACBD\uC5D0\uC11C \uB09A\uC2DC \uAC00\uB2A5
|
Fishing.SubSkill.IceFishing.Description=\uC5BC\uC74C\uC774 \uB36E\uD600\uC788\uB294 \uD658\uACBD\uC5D0\uC11C \uB09A\uC2DC \uAC00\uB2A5
|
||||||
Fishing.Chance.Raining=&9 \uBE44 \uD2B9\uD61C
|
Fishing.Chance.Raining=&9 \uBE44 \uD2B9\uD61C
|
||||||
|
@ -251,7 +251,6 @@ Fishing.SubSkill.FishermansDiet.Name=Fisherman's Diet
|
|||||||
Fishing.SubSkill.FishermansDiet.Description=Improves hunger restored from fished foods
|
Fishing.SubSkill.FishermansDiet.Description=Improves hunger restored from fished foods
|
||||||
Fishing.SubSkill.FishermansDiet.Stat=Fisherman's Diet:&a Rank {0}
|
Fishing.SubSkill.FishermansDiet.Stat=Fisherman's Diet:&a Rank {0}
|
||||||
Fishing.SubSkill.MasterAngler.Name=Master Angler
|
Fishing.SubSkill.MasterAngler.Name=Master Angler
|
||||||
Fishing.SubSkill.MasterAngler.Description=Improves chance of getting a bite while fishing
|
|
||||||
Fishing.SubSkill.IceFishing.Name=Ice Fishing
|
Fishing.SubSkill.IceFishing.Name=Ice Fishing
|
||||||
Fishing.SubSkill.IceFishing.Description=Allows you to fish in icy biomes
|
Fishing.SubSkill.IceFishing.Description=Allows you to fish in icy biomes
|
||||||
Fishing.SubSkill.IceFishing.Stat=Ice Fishing
|
Fishing.SubSkill.IceFishing.Stat=Ice Fishing
|
||||||
|
@ -71,7 +71,6 @@ Fishing.SubSkill.Shake.Description=Schud items af van mobs w/ hengel
|
|||||||
Fishing.SubSkill.FishermansDiet.Name=Visserman\'s dieet
|
Fishing.SubSkill.FishermansDiet.Name=Visserman\'s dieet
|
||||||
Fishing.SubSkill.FishermansDiet.Description=Verbetert de honger hersteld vanaf geviste voedingsmiddelen
|
Fishing.SubSkill.FishermansDiet.Description=Verbetert de honger hersteld vanaf geviste voedingsmiddelen
|
||||||
Fishing.SubSkill.MasterAngler.Name=Meester Hengelaar
|
Fishing.SubSkill.MasterAngler.Name=Meester Hengelaar
|
||||||
Fishing.SubSkill.MasterAngler.Description=Verbetert de kans op het bijten tijdens het vissen
|
|
||||||
Fishing.SubSkill.IceFishing.Name=Ijs Vissen
|
Fishing.SubSkill.IceFishing.Name=Ijs Vissen
|
||||||
Fishing.SubSkill.IceFishing.Description=Stelt je in staat om te vissen in de ijzige biomen
|
Fishing.SubSkill.IceFishing.Description=Stelt je in staat om te vissen in de ijzige biomen
|
||||||
Fishing.Chance.Raining=&9 Regen Bonus
|
Fishing.Chance.Raining=&9 Regen Bonus
|
||||||
|
@ -89,7 +89,6 @@ Fishing.SubSkill.Shake.Name=Potrz\u0105\u015bni\u0119cie (przeciwko jednostkom)
|
|||||||
Fishing.SubSkill.Shake.Description=Okradaj potwory z przedmiot\u00f3w u\u017cywaj\u0105c w\u0119dki.
|
Fishing.SubSkill.Shake.Description=Okradaj potwory z przedmiot\u00f3w u\u017cywaj\u0105c w\u0119dki.
|
||||||
Fishing.SubSkill.FishermansDiet.Name=Dieta Rybaka
|
Fishing.SubSkill.FishermansDiet.Name=Dieta Rybaka
|
||||||
Fishing.SubSkill.FishermansDiet.Description=Zwi\u0119ksza nasycenie posi\u0142k\u00f3w (ryby)
|
Fishing.SubSkill.FishermansDiet.Description=Zwi\u0119ksza nasycenie posi\u0142k\u00f3w (ryby)
|
||||||
Fishing.SubSkill.MasterAngler.Description=Zwieksza szanse na zlapanie ryby na haczyk
|
|
||||||
Fishing.SubSkill.IceFishing.Name=Lodowe lowienie ryb
|
Fishing.SubSkill.IceFishing.Name=Lodowe lowienie ryb
|
||||||
Fishing.SubSkill.IceFishing.Description=Pozwala na lowienie ryb w zimowych biomach
|
Fishing.SubSkill.IceFishing.Description=Pozwala na lowienie ryb w zimowych biomach
|
||||||
Fishing.Chance.Raining=&9 Bonus od Deszczu
|
Fishing.Chance.Raining=&9 Bonus od Deszczu
|
||||||
|
@ -199,7 +199,6 @@ Fishing.SubSkill.FishermansDiet.Name=\u0420\u044b\u0431\u0430\u0446\u043a\u0430\
|
|||||||
Fishing.SubSkill.FishermansDiet.Description=\u0423\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u0435\u0442 \u0443\u0442\u043e\u043b\u0435\u043d\u0438\u0435 \u0433\u043e\u043b\u043e\u0434\u0430 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0440\u044b\u0431\u0430\u0446\u043a\u043e\u0439 \u0435\u0434\u044b
|
Fishing.SubSkill.FishermansDiet.Description=\u0423\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u0435\u0442 \u0443\u0442\u043e\u043b\u0435\u043d\u0438\u0435 \u0433\u043e\u043b\u043e\u0434\u0430 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0440\u044b\u0431\u0430\u0446\u043a\u043e\u0439 \u0435\u0434\u044b
|
||||||
Fishing.SubSkill.FishermansDiet.Stat=\u0420\u044b\u0431\u0430\u0446\u043a\u0430\u044f \u0414\u0438\u0435\u0442\u0430:&a \u0420\u0430\u043d\u0433 {0}
|
Fishing.SubSkill.FishermansDiet.Stat=\u0420\u044b\u0431\u0430\u0446\u043a\u0430\u044f \u0414\u0438\u0435\u0442\u0430:&a \u0420\u0430\u043d\u0433 {0}
|
||||||
Fishing.SubSkill.MasterAngler.Name=\u041c\u0430\u0441\u0442\u0435\u0440 \u0420\u044b\u0431\u043e\u043b\u043e\u0432
|
Fishing.SubSkill.MasterAngler.Name=\u041c\u0430\u0441\u0442\u0435\u0440 \u0420\u044b\u0431\u043e\u043b\u043e\u0432
|
||||||
Fishing.SubSkill.MasterAngler.Description=\u0423\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u0435\u0442 \u0448\u0430\u043d\u0441 \u043f\u043e\u043a\u043b\u0435\u0432\u043a\u0438 \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0440\u044b\u0431\u0430\u043b\u043a\u0438
|
|
||||||
Fishing.SubSkill.IceFishing.Name=\u041f\u043e\u0434\u043b\u0435\u0434\u043d\u0430\u044f \u0420\u044b\u0431\u0430\u043b\u043a\u0430
|
Fishing.SubSkill.IceFishing.Name=\u041f\u043e\u0434\u043b\u0435\u0434\u043d\u0430\u044f \u0420\u044b\u0431\u0430\u043b\u043a\u0430
|
||||||
Fishing.SubSkill.IceFishing.Description=\u041f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0432\u0430\u043c \u0440\u044b\u0431\u0430\u0447\u0438\u0442\u044c \u0432 \u0441\u043d\u0435\u0436\u043d\u044b\u0445 \u0431\u0438\u043e\u043c\u0430\u0445
|
Fishing.SubSkill.IceFishing.Description=\u041f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0432\u0430\u043c \u0440\u044b\u0431\u0430\u0447\u0438\u0442\u044c \u0432 \u0441\u043d\u0435\u0436\u043d\u044b\u0445 \u0431\u0438\u043e\u043c\u0430\u0445
|
||||||
Fishing.SubSkill.IceFishing.Stat=\u041f\u043e\u0434\u043b\u0435\u0434\u043d\u0430\u044f \u0420\u044b\u0431\u0430\u043b\u043a\u0430
|
Fishing.SubSkill.IceFishing.Stat=\u041f\u043e\u0434\u043b\u0435\u0434\u043d\u0430\u044f \u0420\u044b\u0431\u0430\u043b\u043a\u0430
|
||||||
|
@ -90,7 +90,6 @@ Fishing.SubSkill.Shake.Description=\u0e40\u0e02\u0e22\u0e48\u0e32\u0e40\u0e2d\u0
|
|||||||
Fishing.SubSkill.FishermansDiet.Name=Fisherman\'s Diet
|
Fishing.SubSkill.FishermansDiet.Name=Fisherman\'s Diet
|
||||||
Fishing.SubSkill.FishermansDiet.Description=\u0e40\u0e1e\u0e34\u0e48\u0e21\u0e04\u0e27\u0e32\u0e21\u0e2d\u0e34\u0e48\u0e21\u0e08\u0e32\u0e01\u0e01\u0e32\u0e23\u0e01\u0e34\u0e19\u0e1b\u0e25\u0e32
|
Fishing.SubSkill.FishermansDiet.Description=\u0e40\u0e1e\u0e34\u0e48\u0e21\u0e04\u0e27\u0e32\u0e21\u0e2d\u0e34\u0e48\u0e21\u0e08\u0e32\u0e01\u0e01\u0e32\u0e23\u0e01\u0e34\u0e19\u0e1b\u0e25\u0e32
|
||||||
Fishing.SubSkill.MasterAngler.Name=Master Angler
|
Fishing.SubSkill.MasterAngler.Name=Master Angler
|
||||||
Fishing.SubSkill.MasterAngler.Description=\u0e40\u0e1e\u0e34\u0e48\u0e21\u0e42\u0e2d\u0e01\u0e32\u0e2a\u0e44\u0e14\u0e49\u0e23\u0e31\u0e1a\u0e1b\u0e25\u0e32\u0e21\u0e32\u0e01\u0e02\u0e36\u0e49\u0e19\u0e08\u0e32\u0e01\u0e01\u0e32\u0e23\u0e15\u0e01\u0e1b\u0e25\u0e32
|
|
||||||
Fishing.SubSkill.IceFishing.Name=Ice Fishing
|
Fishing.SubSkill.IceFishing.Name=Ice Fishing
|
||||||
Fishing.SubSkill.IceFishing.Description=\u0e2d\u0e19\u0e38\u0e0d\u0e32\u0e15\u0e34\u0e43\u0e2b\u0e49\u0e15\u0e01\u0e1b\u0e25\u0e32\u0e43\u0e19\u0e19\u0e49\u0e33\u0e41\u0e02\u0e47\u0e07
|
Fishing.SubSkill.IceFishing.Description=\u0e2d\u0e19\u0e38\u0e0d\u0e32\u0e15\u0e34\u0e43\u0e2b\u0e49\u0e15\u0e01\u0e1b\u0e25\u0e32\u0e43\u0e19\u0e19\u0e49\u0e33\u0e41\u0e02\u0e47\u0e07
|
||||||
Fishing.Chance.Raining=&9 Rain Bonus
|
Fishing.Chance.Raining=&9 Rain Bonus
|
||||||
|
@ -251,7 +251,6 @@ Fishing.SubSkill.FishermansDiet.Name=\u6e14\u592b\u7684\u98df\u8c31
|
|||||||
Fishing.SubSkill.FishermansDiet.Description=\u63d0\u9ad8\u9c7c\u7c7b\u98df\u7269\u6062\u590d\u7684\u9971\u98df\u5ea6
|
Fishing.SubSkill.FishermansDiet.Description=\u63d0\u9ad8\u9c7c\u7c7b\u98df\u7269\u6062\u590d\u7684\u9971\u98df\u5ea6
|
||||||
Fishing.SubSkill.FishermansDiet.Stat=\u6e14\u592b\u7684\u98df\u8c31:&a \u7b49\u7ea7 {0}
|
Fishing.SubSkill.FishermansDiet.Stat=\u6e14\u592b\u7684\u98df\u8c31:&a \u7b49\u7ea7 {0}
|
||||||
Fishing.SubSkill.MasterAngler.Name=\u9493\u9c7c\u5927\u5e08
|
Fishing.SubSkill.MasterAngler.Name=\u9493\u9c7c\u5927\u5e08
|
||||||
Fishing.SubSkill.MasterAngler.Description=\u63d0\u9ad8\u9493\u9c7c\u54ac\u94a9\u51e0\u7387
|
|
||||||
Fishing.SubSkill.IceFishing.Name=\u51b0\u9493
|
Fishing.SubSkill.IceFishing.Name=\u51b0\u9493
|
||||||
Fishing.SubSkill.IceFishing.Description=\u5141\u8bb8\u4f60\u5728\u51b0\u51b7\u7684\u73af\u5883\u4e0b\u9493\u9c7c
|
Fishing.SubSkill.IceFishing.Description=\u5141\u8bb8\u4f60\u5728\u51b0\u51b7\u7684\u73af\u5883\u4e0b\u9493\u9c7c
|
||||||
Fishing.SubSkill.IceFishing.Stat=\u51b0\u9493
|
Fishing.SubSkill.IceFishing.Stat=\u51b0\u9493
|
||||||
|
@ -93,7 +93,6 @@ Fishing.SubSkill.Shake.Description=\u7528\u91e3\u7aff\u628a\u602a\u7269\u7684\u7
|
|||||||
Fishing.SubSkill.FishermansDiet.Name=\u6f01\u4eba\u4fbf\u7576
|
Fishing.SubSkill.FishermansDiet.Name=\u6f01\u4eba\u4fbf\u7576
|
||||||
Fishing.SubSkill.FishermansDiet.Description=\u98df\u7528\u9b5a\u98df\u54c1\u6642\u984d\u5916\u6062\u5fa9\u98fd\u98df\u5ea6
|
Fishing.SubSkill.FishermansDiet.Description=\u98df\u7528\u9b5a\u98df\u54c1\u6642\u984d\u5916\u6062\u5fa9\u98fd\u98df\u5ea6
|
||||||
Fishing.SubSkill.MasterAngler.Name=\u5782\u91e3\u5927\u5e2b
|
Fishing.SubSkill.MasterAngler.Name=\u5782\u91e3\u5927\u5e2b
|
||||||
Fishing.SubSkill.MasterAngler.Description=\u589e\u52a0\u5728\u91e3\u9b5a\u6642\u4e0a\u9264\u7684\u6a5f\u7387
|
|
||||||
Fishing.SubSkill.IceFishing.Name=\u51b0\u91e3
|
Fishing.SubSkill.IceFishing.Name=\u51b0\u91e3
|
||||||
Fishing.SubSkill.IceFishing.Description=\u5141\u8a31\u4f60\u5728\u51b0\u5929\u96ea\u5730\u88e1\u91e3\u9b5a
|
Fishing.SubSkill.IceFishing.Description=\u5141\u8a31\u4f60\u5728\u51b0\u5929\u96ea\u5730\u88e1\u91e3\u9b5a
|
||||||
Fishing.Chance.Raining=&9 \u5927\u91cf\u734e\u52f5
|
Fishing.Chance.Raining=&9 \u5927\u91cf\u734e\u52f5
|
||||||
|
@ -2,6 +2,9 @@ import com.gmail.nossr50.util.blockmeta.*;
|
|||||||
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;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.junit.*;
|
import org.junit.*;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
@ -140,16 +143,27 @@ public class ChunkStoreTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testRegressionChunkMirrorBug() {
|
public void testRegressionChunkMirrorBug() {
|
||||||
ChunkManager chunkManager = new HashChunkManager();
|
ChunkManager chunkManager = new HashChunkManager();
|
||||||
chunkManager.setTrue(15,0,15, mockWorld);
|
Block mockBlockA = mock(Block.class);
|
||||||
chunkManager.setFalse(-15, 0, -15, mockWorld);
|
Mockito.when(mockBlockA.getX()).thenReturn(15);
|
||||||
Assert.assertTrue(chunkManager.isTrue(15, 0, 15, mockWorld));
|
Mockito.when(mockBlockA.getZ()).thenReturn(15);
|
||||||
|
Mockito.when(mockBlockA.getY()).thenReturn(0);
|
||||||
|
Mockito.when(mockBlockA.getWorld()).thenReturn(mockWorld);
|
||||||
|
Block mockBlockB = mock(Block.class);
|
||||||
|
Mockito.when(mockBlockB.getX()).thenReturn(-15);
|
||||||
|
Mockito.when(mockBlockB.getZ()).thenReturn(-15);
|
||||||
|
Mockito.when(mockBlockB.getY()).thenReturn(0);
|
||||||
|
Mockito.when(mockBlockB.getWorld()).thenReturn(mockWorld);
|
||||||
|
|
||||||
|
chunkManager.setTrue(mockBlockA);
|
||||||
|
chunkManager.setFalse(mockBlockB);
|
||||||
|
Assert.assertTrue(chunkManager.isTrue(mockBlockA));
|
||||||
}
|
}
|
||||||
|
|
||||||
private interface Delegate {
|
private interface Delegate {
|
||||||
void run();
|
void run();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertThrows(Delegate delegate, Class<?> clazz) {
|
private void assertThrows(@NotNull Delegate delegate, @NotNull Class<?> clazz) {
|
||||||
try {
|
try {
|
||||||
delegate.run();
|
delegate.run();
|
||||||
Assert.fail(); // We didn't throw
|
Assert.fail(); // We didn't throw
|
||||||
@ -170,7 +184,7 @@ public class ChunkStoreTest {
|
|||||||
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 void recursiveDelete(File directoryToBeDeleted) {
|
private static void recursiveDelete(@NotNull File directoryToBeDeleted) {
|
||||||
if (directoryToBeDeleted.isDirectory()) {
|
if (directoryToBeDeleted.isDirectory()) {
|
||||||
for (File file : directoryToBeDeleted.listFiles()) {
|
for (File file : directoryToBeDeleted.listFiles()) {
|
||||||
recursiveDelete(file);
|
recursiveDelete(file);
|
||||||
@ -179,7 +193,7 @@ public class ChunkStoreTest {
|
|||||||
directoryToBeDeleted.delete();
|
directoryToBeDeleted.delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] serializeChunkstore(ChunkStore chunkStore) throws IOException {
|
private static byte[] serializeChunkstore(@NotNull ChunkStore chunkStore) throws IOException {
|
||||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||||
if (chunkStore instanceof BitSetChunkStore)
|
if (chunkStore instanceof BitSetChunkStore)
|
||||||
BitSetChunkStore.Serialization.writeChunkStore(new DataOutputStream(byteArrayOutputStream), chunkStore);
|
BitSetChunkStore.Serialization.writeChunkStore(new DataOutputStream(byteArrayOutputStream), chunkStore);
|
||||||
@ -188,18 +202,17 @@ public class ChunkStoreTest {
|
|||||||
return byteArrayOutputStream.toByteArray();
|
return byteArrayOutputStream.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static class LegacyChunkStore implements ChunkStore, Serializable {
|
public static class LegacyChunkStore implements ChunkStore, Serializable {
|
||||||
private static final long serialVersionUID = -1L;
|
private static final long serialVersionUID = -1L;
|
||||||
transient private boolean dirty = false;
|
transient private boolean dirty = false;
|
||||||
public boolean[][][] store;
|
public boolean[][][] store;
|
||||||
private static final int CURRENT_VERSION = 7;
|
private static final int CURRENT_VERSION = 7;
|
||||||
private static final int MAGIC_NUMBER = 0xEA5EDEBB;
|
private static final int MAGIC_NUMBER = 0xEA5EDEBB;
|
||||||
private int cx;
|
private final int cx;
|
||||||
private int cz;
|
private final int cz;
|
||||||
private UUID worldUid;
|
private final @NotNull UUID worldUid;
|
||||||
|
|
||||||
public LegacyChunkStore(World world, int cx, int cz) {
|
public LegacyChunkStore(@NotNull World world, int cx, int cz) {
|
||||||
this.cx = cx;
|
this.cx = cx;
|
||||||
this.cz = cz;
|
this.cz = cz;
|
||||||
this.worldUid = world.getUID();
|
this.worldUid = world.getUID();
|
||||||
@ -227,7 +240,7 @@ public class ChunkStoreTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UUID getWorldId() {
|
public @NotNull UUID getWorldId() {
|
||||||
return worldUid;
|
return worldUid;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,7 +287,7 @@ public class ChunkStoreTest {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeObject(ObjectOutputStream out) throws IOException {
|
private void writeObject(@NotNull ObjectOutputStream out) throws IOException {
|
||||||
out.writeInt(MAGIC_NUMBER);
|
out.writeInt(MAGIC_NUMBER);
|
||||||
out.writeInt(CURRENT_VERSION);
|
out.writeInt(CURRENT_VERSION);
|
||||||
|
|
||||||
@ -287,18 +300,18 @@ public class ChunkStoreTest {
|
|||||||
dirty = false;
|
dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
private void readObject(@NotNull ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class UnitTestObjectOutputStream extends ObjectOutputStream {
|
private static class UnitTestObjectOutputStream extends ObjectOutputStream {
|
||||||
public UnitTestObjectOutputStream(OutputStream outputStream) throws IOException {
|
public UnitTestObjectOutputStream(@NotNull OutputStream outputStream) throws IOException {
|
||||||
super(outputStream);
|
super(outputStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeUTF(String str) throws IOException {
|
public void writeUTF(@NotNull String str) throws IOException {
|
||||||
// Pretend to be the old class
|
// Pretend to be the old class
|
||||||
if (str.equals(LegacyChunkStore.class.getName()))
|
if (str.equals(LegacyChunkStore.class.getName()))
|
||||||
str = "com.gmail.nossr50.util.blockmeta.chunkmeta.PrimitiveChunkStore";
|
str = "com.gmail.nossr50.util.blockmeta.chunkmeta.PrimitiveChunkStore";
|
||||||
|
Loading…
Reference in New Issue
Block a user