mirror of
https://github.com/mcMMO-Dev/mcMMO.git
synced 2026-02-18 01:42:32 +01:00
Compare commits
96 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b0681c10b9 | ||
|
|
1bf0cd1d15 | ||
|
|
212b42c8b9 | ||
|
|
9c4ff30ce7 | ||
|
|
d7510b83c8 | ||
|
|
9a9e0cc7de | ||
|
|
a8a90ee815 | ||
|
|
7859660ece | ||
|
|
b93dafee63 | ||
|
|
a1a61e9d4a | ||
|
|
464d6bdd35 | ||
|
|
2c613d5b99 | ||
|
|
d1f683b8a5 | ||
|
|
f4bb8ccb7d | ||
|
|
00364afd8f | ||
|
|
f5f07f7016 | ||
|
|
2bdeeb2d6e | ||
|
|
f023529d37 | ||
|
|
b8d37cb223 | ||
|
|
88ed14fe5c | ||
|
|
cd30771775 | ||
|
|
00a5bc5cf3 | ||
|
|
a17d58fe32 | ||
|
|
c21286dbc3 | ||
|
|
7fc99630e0 | ||
|
|
69a5cd1017 | ||
|
|
3129acfc19 | ||
|
|
c3dd777e44 | ||
|
|
c5120b9c72 | ||
|
|
91a18fe7a2 | ||
|
|
62f5185a1b | ||
|
|
f4cb83319e | ||
|
|
c7b3b7a826 | ||
|
|
01fb245da3 | ||
|
|
83e072dad1 | ||
|
|
eb5ac80714 | ||
|
|
b57cc7bd59 | ||
|
|
d532164cd6 | ||
|
|
61ae4826d1 | ||
|
|
be4e62fe9d | ||
|
|
d9346ab260 | ||
|
|
87c4f318a4 | ||
|
|
30b87e8035 | ||
|
|
26a85846fc | ||
|
|
cd40507609 | ||
|
|
a9ea2e0137 | ||
|
|
6964f7adfc | ||
|
|
70231b6ae0 | ||
|
|
9354831729 | ||
|
|
ab7a83b37e | ||
|
|
8dfa8c20f3 | ||
|
|
67499eeff7 | ||
|
|
d43ff6263f | ||
|
|
058dc8c611 | ||
|
|
8871964be0 | ||
|
|
42aa426991 | ||
|
|
7cee94e0b8 | ||
|
|
fa96a6beec | ||
|
|
efc0edf3ef | ||
|
|
f1d785777c | ||
|
|
db0168205d | ||
|
|
2a20ed95fa | ||
|
|
11f1889f1f | ||
|
|
703b5b2f3f | ||
|
|
58a15e61dd | ||
|
|
896f57f0b4 | ||
|
|
34ae64706e | ||
|
|
43fe92fe3f | ||
|
|
31513d52d7 | ||
|
|
70a16fe344 | ||
|
|
4570ffb8f5 | ||
|
|
22f6ed324d | ||
|
|
e29484e14b | ||
|
|
7e21fdd862 | ||
|
|
01e69cdf5e | ||
|
|
9ad7840236 | ||
|
|
e97ec36094 | ||
|
|
ef318eeaec | ||
|
|
3314b18318 | ||
|
|
5f04ecfdd4 | ||
|
|
91d294acff | ||
|
|
283cdeed6c | ||
|
|
a283fce4ec | ||
|
|
f8d525d797 | ||
|
|
80dabad10e | ||
|
|
8181989e98 | ||
|
|
0f7bf13834 | ||
|
|
c1d6e79a41 | ||
|
|
6f073250f4 | ||
|
|
c084ccde40 | ||
|
|
b73a06b9ab | ||
|
|
740c1131ea | ||
|
|
0a798aec30 | ||
|
|
9089e70155 | ||
|
|
f532630d1b | ||
|
|
7b47d32a96 |
@@ -8,7 +8,12 @@ Key:
|
||||
- Removal
|
||||
|
||||
Version 1.3.11
|
||||
= Fixed bug where mcMMO would ignore other block-protection plugins for various abilities
|
||||
! Changed axes to start with 1 durability damage instead of 5, gain 1 durability damage every 50 levels instead of 30, and only have a 25% chance on hit to damage armor (per armor piece)
|
||||
+ Added compatibility with bow-wielding NPCs from Citizens/NPC mods
|
||||
+ Added compatibility for pvp-prevention plugins for Serrated Strikes
|
||||
= Fixed bug where mcMMO could throw NPE errors if trees cut down were from a custom mod and had an id of 17
|
||||
= Fixed dupe bug where mcMMO would ignore other block-protection plugins for various abilities
|
||||
= Fixed NPE with hardcore mode's vampirism
|
||||
|
||||
Version 1.3.10
|
||||
+ Added 1.3.1 compatibility
|
||||
|
||||
9
pom.xml
Normal file → Executable file
9
pom.xml
Normal file → Executable file
@@ -2,7 +2,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.gmail.nossr50.mcMMO</groupId>
|
||||
<artifactId>mcMMO</artifactId>
|
||||
<version>1.3.11</version>
|
||||
<version>1.3.12</version>
|
||||
<name>mcMMO</name>
|
||||
<url>https://github.com/mcMMO-Dev/mcMMO</url>
|
||||
<issueManagement>
|
||||
@@ -121,6 +121,13 @@
|
||||
<type>jar</type>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bukkit</groupId>
|
||||
<artifactId>craftbukkit</artifactId>
|
||||
<version>LATEST</version>
|
||||
<type>jar</type>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.getspout</groupId>
|
||||
<artifactId>spoutpluginapi</artifactId>
|
||||
|
||||
@@ -51,6 +51,11 @@ public class CommandHelper {
|
||||
if (Skills.hasGatheringSkills(inspect)) {
|
||||
PlayerProfile profile = Users.getProfile(inspect);
|
||||
|
||||
if (profile == null) {
|
||||
display.sendMessage(LocaleLoader.getString("Commands.DoesNotExist"));
|
||||
return;
|
||||
}
|
||||
|
||||
display.sendMessage(LocaleLoader.getString("Stats.Header.Gathering"));
|
||||
|
||||
if (Permissions.getInstance().excavation(inspect)) {
|
||||
@@ -89,6 +94,11 @@ public class CommandHelper {
|
||||
if (Skills.hasCombatSkills(inspect)) {
|
||||
PlayerProfile profile = Users.getProfile(inspect);
|
||||
|
||||
if (profile == null) {
|
||||
display.sendMessage(LocaleLoader.getString("Commands.DoesNotExist"));
|
||||
return;
|
||||
}
|
||||
|
||||
display.sendMessage(LocaleLoader.getString("Stats.Header.Combat"));
|
||||
|
||||
if (Permissions.getInstance().axes(inspect)) {
|
||||
@@ -126,6 +136,12 @@ public class CommandHelper {
|
||||
public static void printMiscSkills(Player inspect, CommandSender display) {
|
||||
if (Skills.hasMiscSkills(inspect)) {
|
||||
PlayerProfile profile = Users.getProfile(inspect);
|
||||
|
||||
if (profile == null) {
|
||||
display.sendMessage(LocaleLoader.getString("Commands.DoesNotExist"));
|
||||
return;
|
||||
}
|
||||
|
||||
display.sendMessage(LocaleLoader.getString("Stats.Header.Misc"));
|
||||
|
||||
if (Permissions.getInstance().acrobatics(inspect)) {
|
||||
|
||||
@@ -46,6 +46,11 @@ public abstract class SkillCommand implements CommandExecutor {
|
||||
player = (Player) sender;
|
||||
profile = Users.getProfile(player);
|
||||
|
||||
if (profile == null) {
|
||||
sender.sendMessage(LocaleLoader.getString("Commands.DoesNotExist"));
|
||||
return true;
|
||||
}
|
||||
|
||||
skillValue = profile.getSkillLevel(skill);
|
||||
dataCalculations();
|
||||
permissionsCheck();
|
||||
|
||||
@@ -72,6 +72,11 @@ public class AddlevelsCommand implements CommandExecutor{
|
||||
String playerName = modifiedPlayer.getName();
|
||||
profile = Users.getProfile(modifiedPlayer);
|
||||
|
||||
if (profile == null) {
|
||||
sender.sendMessage(LocaleLoader.getString("Commands.DoesNotExist"));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!profile.isLoaded()) {
|
||||
sender.sendMessage(LocaleLoader.getString("Commands.DoesNotExist"));
|
||||
return true;
|
||||
|
||||
@@ -84,6 +84,11 @@ public class AddxpCommand implements CommandExecutor {
|
||||
String playerName = modifiedPlayer.getName();
|
||||
McMMOPlayer mcMMOPlayer = Users.getPlayer(modifiedPlayer);
|
||||
PlayerProfile profile = Users.getProfile(modifiedPlayer);
|
||||
|
||||
if (profile == null) {
|
||||
sender.sendMessage(LocaleLoader.getString("Commands.DoesNotExist"));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!profile.isLoaded()) {
|
||||
sender.sendMessage(LocaleLoader.getString("Commands.DoesNotExist"));
|
||||
|
||||
@@ -51,6 +51,11 @@ public class InspectCommand implements CommandExecutor {
|
||||
|
||||
PlayerProfile profile = new PlayerProfile(args[0], false); //Temporary Profile
|
||||
|
||||
if (profile == null) {
|
||||
sender.sendMessage(LocaleLoader.getString("Commands.DoesNotExist"));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!profile.isLoaded()) {
|
||||
sender.sendMessage(LocaleLoader.getString("Commands.DoesNotExist"));
|
||||
return true;
|
||||
|
||||
@@ -88,6 +88,11 @@ public class MmoeditCommand implements CommandExecutor {
|
||||
if (mcmmoPlayer != null) {
|
||||
profile = mcmmoPlayer.getProfile();
|
||||
|
||||
if (profile == null) {
|
||||
sender.sendMessage(LocaleLoader.getString("Commands.DoesNotExist"));
|
||||
return true;
|
||||
}
|
||||
|
||||
profile.modifySkill(skill, newValue);
|
||||
mcmmoPlayer.getPlayer().sendMessage(ChatColor.GREEN + "Your level in " + skillName + " was set to " + newValue + "!"); //TODO: Needs more locale.
|
||||
sender.sendMessage(ChatColor.RED + skillName + " has been modified for " + args[0] + "."); //TODO: Use locale
|
||||
@@ -95,6 +100,11 @@ public class MmoeditCommand implements CommandExecutor {
|
||||
else {
|
||||
profile = new PlayerProfile(args[0], false); //Temporary Profile
|
||||
|
||||
if (profile == null) {
|
||||
sender.sendMessage(LocaleLoader.getString("Commands.DoesNotExist"));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!profile.isLoaded()) {
|
||||
sender.sendMessage(LocaleLoader.getString("Commands.DoesNotExist"));
|
||||
return true;
|
||||
|
||||
@@ -45,6 +45,12 @@ public class SkillResetCommand implements CommandExecutor {
|
||||
|
||||
//reset the values in the hash table and persist them
|
||||
PlayerProfile profile = Users.getProfile((Player)sender);
|
||||
|
||||
if (profile == null) {
|
||||
sender.sendMessage(LocaleLoader.getString("Commands.DoesNotExist"));
|
||||
return true;
|
||||
}
|
||||
|
||||
profile.resetSkill(skillType);
|
||||
profile.save();
|
||||
|
||||
|
||||
@@ -24,6 +24,11 @@ public class McabilityCommand implements CommandExecutor {
|
||||
|
||||
PlayerProfile profile = Users.getProfile((Player) sender);
|
||||
|
||||
if (profile == null) {
|
||||
sender.sendMessage(LocaleLoader.getString("Commands.DoesNotExist"));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (profile.getAbilityUse()) {
|
||||
sender.sendMessage(LocaleLoader.getString("Commands.Ability.Off"));
|
||||
}
|
||||
|
||||
@@ -24,6 +24,11 @@ public class McgodCommand implements CommandExecutor {
|
||||
|
||||
PlayerProfile profile = Users.getProfile((Player) sender);
|
||||
|
||||
if (profile == null) {
|
||||
sender.sendMessage(LocaleLoader.getString("Commands.DoesNotExist"));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (profile.getGodMode()) {
|
||||
sender.sendMessage(LocaleLoader.getString("Commands.GodMode.Disabled"));
|
||||
}
|
||||
|
||||
@@ -47,6 +47,11 @@ public class McrefreshCommand implements CommandExecutor {
|
||||
profile = Users.getProfile(player);
|
||||
String playerName = player.getName();
|
||||
|
||||
if (profile == null) {
|
||||
sender.sendMessage(LocaleLoader.getString("Commands.DoesNotExist"));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!profile.isLoaded()) {
|
||||
sender.sendMessage(LocaleLoader.getString("Commands.DoesNotExist"));
|
||||
return true;
|
||||
|
||||
@@ -72,6 +72,7 @@ public class PtpCommand implements CommandExecutor {
|
||||
player.teleport(target);
|
||||
player.sendMessage(LocaleLoader.getString("Party.Teleport.Player", new Object[] { target.getName() }));
|
||||
target.sendMessage(LocaleLoader.getString("Party.Teleport.Target", new Object[] { player.getName() }));
|
||||
profile.setRecentlyHurt(System.currentTimeMillis());
|
||||
}
|
||||
else {
|
||||
player.sendMessage(LocaleLoader.getString("Party.NotInYourParty", new Object[] { target.getName() }));
|
||||
|
||||
@@ -23,7 +23,7 @@ public class AxesCommand extends SkillCommand {
|
||||
|
||||
@Override
|
||||
protected void dataCalculations() {
|
||||
impactDamage = String.valueOf(5 + ((int) skillValue / 30));
|
||||
impactDamage = String.valueOf(1 + ((int) skillValue / 50));
|
||||
skullSplitterLength = String.valueOf(2 + ((int) skillValue / 50));
|
||||
greaterImpactDamage = "2";
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.gmail.nossr50.commands.skills;
|
||||
|
||||
import com.gmail.nossr50.commands.SkillCommand;
|
||||
import com.gmail.nossr50.config.Config;
|
||||
import com.gmail.nossr50.datatypes.SkillType;
|
||||
import com.gmail.nossr50.locale.LocaleLoader;
|
||||
import com.gmail.nossr50.skills.gathering.Fishing;
|
||||
@@ -8,6 +9,7 @@ import com.gmail.nossr50.skills.gathering.Fishing;
|
||||
public class FishingCommand extends SkillCommand {
|
||||
private int lootTier;
|
||||
private String magicChance;
|
||||
private String shakeChance;
|
||||
|
||||
private boolean canTreasureHunt;
|
||||
private boolean canMagicHunt;
|
||||
@@ -21,6 +23,11 @@ public class FishingCommand extends SkillCommand {
|
||||
protected void dataCalculations() {
|
||||
lootTier = Fishing.getFishingLootTier(profile);
|
||||
magicChance = percent.format((float) lootTier / 15);
|
||||
int dropChance = Fishing.getShakeChance(lootTier);
|
||||
if (player.hasPermission("mcmmo.perks.lucky.fishing")) {
|
||||
dropChance = (int) (dropChance * 1.25);
|
||||
}
|
||||
shakeChance = String.valueOf(dropChance);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -66,12 +73,11 @@ public class FishingCommand extends SkillCommand {
|
||||
}
|
||||
|
||||
if (canShake) {
|
||||
//TODO: Do we really need to display this twice? Not like there are any associated stats.
|
||||
if (skillValue < 150) {
|
||||
player.sendMessage(LocaleLoader.getString("Ability.Generic.Template.Lock", new Object[] { LocaleLoader.getString("Fishing.Ability.Locked.0") }));
|
||||
}
|
||||
else {
|
||||
player.sendMessage(LocaleLoader.getString("Fishing.Ability.Shake"));
|
||||
player.sendMessage(LocaleLoader.getString("Fishing.Ability.Shake", new Object[] { shakeChance }));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,6 +152,13 @@ public class Config extends ConfigLoader {
|
||||
public int getFishingTierLevelsTier3() { return config.getInt("Fishing.Tier_Levels.Tier3", 400); }
|
||||
public int getFishingTierLevelsTier4() { return config.getInt("Fishing.Tier_Levels.Tier4", 600); }
|
||||
public int getFishingTierLevelsTier5() { return config.getInt("Fishing.Tier_Levels.Tier5", 800); }
|
||||
|
||||
/* Shake */
|
||||
public int getShakeChanceRank1() { return config.getInt("Shake.Chance.Rank_1", 25); }
|
||||
public int getShakeChanceRank2() { return config.getInt("Shake.Chance.Rank_2", 40); }
|
||||
public int getShakeChanceRank3() { return config.getInt("Shake.Chance.Rank_3", 55); }
|
||||
public int getShakeChanceRank4() { return config.getInt("Shake.Chance.Rank_4", 60); }
|
||||
public int getShakeChanceRank5() { return config.getInt("Shake.Chance.Rank_5", 75); }
|
||||
|
||||
/* Herbalism */
|
||||
public int getHerbalismXPSugarCane() { return config.getInt("Experience.Herbalism.Sugar_Cane", 30); }
|
||||
@@ -164,8 +171,12 @@ public class Config extends ConfigLoader {
|
||||
public int getHerbalismXPNetherWart() { return config.getInt("Experience.Herbalism.Nether_Wart", 50); }
|
||||
public int getHerbalismXPLilyPads() { return config.getInt("Experience.Herbalism.Lily_Pads", 100); }
|
||||
public int getHerbalismXPVines() { return config.getInt("Experience.Herbalism.Vines", 10); }
|
||||
public int getHerbalismXPCocoa() { return config.getInt("Experience.Herbalism.Cocoa", 30); }
|
||||
public int getHerbalismXPCarrot() { return config.getInt("Experience.Herbalism.Carrot", 50); }
|
||||
public int getHerbalismXPPotato() { return config.getInt("Experience.Herbalism.Potato", 50); }
|
||||
|
||||
public boolean getHerbalismGreenThumbCobbleToMossy() { return config.getBoolean("Skills.Herbalism.Green_Thumb.Cobble_To_Mossy", true); }
|
||||
public boolean getHerbalismGreenThumbCobbleWallToMossyWall() { return config.getBoolean("Skills.Herbalism.Green_Thumb.CobbleWall_To_MossyWall", true); }
|
||||
public boolean getHerbalismGreenThumbSmoothbrickToMossy() { return config.getBoolean("Skills.Herbalism.Green_Thumb.SmoothBrick_To_MossyBrick", true); }
|
||||
public boolean getHerbalismGreenThumbDirtToGrass() { return config.getBoolean("Skills.Herbalism.Green_Thumb.Dirt_To_Grass", true); }
|
||||
|
||||
@@ -181,6 +192,9 @@ public class Config extends ConfigLoader {
|
||||
public boolean getVinesDoubleDropsEnabled() { return config.getBoolean("Double_Drops.Herbalism.Vines", true); }
|
||||
public boolean getWaterLiliesDoubleDropsEnabled() { return config.getBoolean("Double_Drops.Herbalism.Water_Lilies", true); }
|
||||
public boolean getYellowFlowersDoubleDropsEnabled() { return config.getBoolean("Double_Drops.Herbalism.Yellow_Flowers", true); }
|
||||
public boolean getCocoaDoubleDropsEnabled() { return config.getBoolean("Double_Drops.Herbalism.Cocoa", true); }
|
||||
public boolean getCarrotDoubleDropsEnabled() { return config.getBoolean("Double_Drops.Herbalism.Carrot", true); }
|
||||
public boolean getPotatoDoubleDropsEnabled() { return config.getBoolean("Double_Drops.Herbalism.Potato", true); }
|
||||
|
||||
public boolean herbalismDoubleDropsDisabled() {
|
||||
ConfigurationSection section = config.getConfigurationSection("Double_Drops.Herbalism");
|
||||
@@ -215,6 +229,7 @@ public class Config extends ConfigLoader {
|
||||
public int getMiningXPSandstone() { return config.getInt("Experience.Mining.Sandstone", 30); }
|
||||
public int getMiningXPEndStone() { return config.getInt("Experience.Mining.End_Stone", 150); }
|
||||
public int getMiningXPMossyStone() { return config.getInt("Experience.Mining.Moss_Stone", 30); }
|
||||
public int getMiningXPEmeraldOre() { return config.getInt("Experience.Mining.Emerald", 1000); }
|
||||
|
||||
public boolean getCoalDoubleDropsEnabled() { return config.getBoolean("Double_Drops.Mining.Coal", true); }
|
||||
public boolean getDiamondDoubleDropsEnabled() { return config.getBoolean("Double_Drops.Mining.Diamond", true); }
|
||||
@@ -229,6 +244,7 @@ public class Config extends ConfigLoader {
|
||||
public boolean getRedstoneDoubleDropsEnabled() { return config.getBoolean("Double_Drops.Mining.Redstone", true); }
|
||||
public boolean getSandstoneDoubleDropsEnabled() { return config.getBoolean("Double_Drops.Mining.Sandstone", true); }
|
||||
public boolean getStoneDoubleDropsEnabled() { return config.getBoolean("Double_Drops.Mining.Stone", true); }
|
||||
public boolean getEmeraldDoubleDropsEnabled() { return config.getBoolean("Double_Drops.Mining.Emerald", true); }
|
||||
|
||||
public boolean miningDoubleDropsDisabled() {
|
||||
ConfigurationSection section = config.getConfigurationSection("Double_Drops.Mining");
|
||||
@@ -291,6 +307,10 @@ public class Config extends ConfigLoader {
|
||||
return disabled;
|
||||
}
|
||||
|
||||
/* AFK Leveling */
|
||||
public boolean getAcrobaticsAFKDisabled() { return config.getBoolean("Skills.Acrobatics.Prevent_AFK_Leveling", true); }
|
||||
public boolean getHerbalismAFKDisabled() { return config.getBoolean("Skills.Herbalism.Prevent_AFK_Leveling", true); }
|
||||
|
||||
/* Arcane Forging */
|
||||
public boolean getArcaneForgingDowngradeEnabled() { return config.getBoolean("Arcane_Forging.Downgrades.Enabled", true); }
|
||||
public int getArcaneForgingDowngradeChanceRank1() { return config.getInt("Arcane_Forging.Downgrades.Chance.Rank_1", 75); }
|
||||
|
||||
@@ -9,6 +9,7 @@ public class HiddenConfig {
|
||||
private static String fileName;
|
||||
private static YamlConfiguration config;
|
||||
private static boolean chunkletsEnabled;
|
||||
private static int conversionRate;
|
||||
|
||||
public HiddenConfig(String fileName) {
|
||||
HiddenConfig.fileName = fileName;
|
||||
@@ -27,10 +28,15 @@ public class HiddenConfig {
|
||||
if (mcMMO.p.getResource(fileName) != null) {
|
||||
config = YamlConfiguration.loadConfiguration(mcMMO.p.getResource(fileName));
|
||||
chunkletsEnabled = config.getBoolean("Options.Chunklets", true);
|
||||
conversionRate = config.getInt("Options.ConversionRate", 1);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getChunkletsEnabled() {
|
||||
return chunkletsEnabled;
|
||||
}
|
||||
|
||||
public int getConversionRate() {
|
||||
return conversionRate;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,10 @@ public class CustomArmorConfig extends ConfigLoader{
|
||||
|
||||
private void loadArmor(String armorType, List<Integer> idList) {
|
||||
ConfigurationSection armorSection = config.getConfigurationSection(armorType);
|
||||
|
||||
if(armorSection == null)
|
||||
return;
|
||||
|
||||
Set<String> armorConfigSet = armorSection.getKeys(false);
|
||||
Iterator<String> iterator = armorConfigSet.iterator();
|
||||
|
||||
|
||||
@@ -48,6 +48,10 @@ public class CustomBlocksConfig extends ConfigLoader {
|
||||
|
||||
private void loadBlocks(String skillType, List<ItemStack> blockList) {
|
||||
ConfigurationSection skillSection = config.getConfigurationSection(skillType);
|
||||
|
||||
if(skillSection == null)
|
||||
return;
|
||||
|
||||
Set<String> skillConfigSet = skillSection.getKeys(false);
|
||||
Iterator<String> iterator = skillConfigSet.iterator();
|
||||
|
||||
|
||||
@@ -53,6 +53,10 @@ public class CustomToolsConfig extends ConfigLoader {
|
||||
|
||||
private void loadTool(String toolType, List<Integer> idList) {
|
||||
ConfigurationSection toolSection = config.getConfigurationSection(toolType);
|
||||
|
||||
if(toolSection == null)
|
||||
return;
|
||||
|
||||
Set<String> toolConfigSet = toolSection.getKeys(false);
|
||||
Iterator<String> iterator = toolConfigSet.iterator();
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ public class PlayerProfile {
|
||||
private boolean abilityUse = true;
|
||||
|
||||
/* Timestamps */
|
||||
private int recentlyHurt;
|
||||
private long recentlyHurt;
|
||||
private int respawnATS;
|
||||
|
||||
/* mySQL STUFF */
|
||||
@@ -826,11 +826,11 @@ public class PlayerProfile {
|
||||
* Recently Hurt
|
||||
*/
|
||||
|
||||
public int getRecentlyHurt() {
|
||||
public long getRecentlyHurt() {
|
||||
return recentlyHurt;
|
||||
}
|
||||
|
||||
public void setRecentlyHurt(int value) {
|
||||
public void setRecentlyHurt(long value) {
|
||||
recentlyHurt = value;
|
||||
}
|
||||
|
||||
|
||||
@@ -58,11 +58,15 @@ public class BlockListener implements Listener {
|
||||
public void onBlockPistonExtend(BlockPistonExtendEvent event) {
|
||||
List<Block> blocks = event.getBlocks();
|
||||
BlockFace direction = event.getDirection();
|
||||
// Block that would be air after piston is finished
|
||||
Block futureEmptyBlock = event.getBlock().getRelative(direction);
|
||||
|
||||
for (Block b : blocks) {
|
||||
if (mcMMO.placeStore.isTrue(b)) {
|
||||
b.getRelative(direction).setMetadata("pistonTrack", new FixedMetadataValue(plugin, true));
|
||||
mcMMO.placeStore.setFalse(b);
|
||||
if (b.equals(futureEmptyBlock)) {
|
||||
mcMMO.placeStore.setFalse(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,11 +78,14 @@ public class BlockListener implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Monitor BlockPhysics events.
|
||||
*
|
||||
* @param event The event to monitor
|
||||
*/
|
||||
// Disabled until a better patch can be applied. This does nothing but flag the wrong block.
|
||||
/*
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onBlockPhysics(BlockPhysicsEvent event) {
|
||||
//TODO: Figure out how to REMOVE metadata from the location the sand/gravel fell from.
|
||||
@@ -92,6 +99,7 @@ public class BlockListener implements Listener {
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Monitor BlockPistonRetract events.
|
||||
@@ -119,6 +127,8 @@ public class BlockListener implements Listener {
|
||||
Player player = event.getPlayer();
|
||||
int id = block.getTypeId();
|
||||
Material type = block.getType();
|
||||
|
||||
if(player.hasMetadata("NPC")) return; // Check if this player is a Citizens NPC
|
||||
|
||||
/* Code to prevent issues with placed falling Sand/Gravel not being tracked */
|
||||
if (type.equals(Material.SAND) || type.equals(Material.GRAVEL)) {
|
||||
@@ -158,6 +168,9 @@ public class BlockListener implements Listener {
|
||||
}
|
||||
|
||||
Player player = event.getPlayer();
|
||||
|
||||
if(player.hasMetadata("NPC")) return; // Check if this player is a Citizens NPC
|
||||
|
||||
PlayerProfile profile = Users.getProfile(player);
|
||||
|
||||
if (profile == null) {
|
||||
@@ -268,8 +281,11 @@ public class BlockListener implements Listener {
|
||||
final int LEAF_BLOWER_LEVEL = 100;
|
||||
|
||||
Player player = event.getPlayer();
|
||||
|
||||
if(player.hasMetadata("NPC")) return; // Check if this player is a Citizens NPC
|
||||
|
||||
PlayerProfile profile = Users.getProfile(player);
|
||||
|
||||
|
||||
if (profile == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -63,6 +63,8 @@ public class EntityListener implements Listener {
|
||||
|
||||
Entity attacker = event.getDamager();
|
||||
Entity defender = event.getEntity();
|
||||
|
||||
if(attacker.hasMetadata("NPC") || defender.hasMetadata("NPC")) return; // Check if either players is are Citizens NPCs
|
||||
|
||||
if (attacker instanceof Projectile) {
|
||||
attacker = ((Projectile) attacker).getShooter();
|
||||
@@ -114,6 +116,8 @@ public class EntityListener implements Listener {
|
||||
Entity entity = event.getEntity();
|
||||
DamageCause cause = event.getCause();
|
||||
|
||||
if(entity.hasMetadata("NPC")) return; // Check if this player is a Citizens NPC
|
||||
|
||||
if (!(entity instanceof LivingEntity)) {
|
||||
return;
|
||||
}
|
||||
@@ -171,6 +175,8 @@ public class EntityListener implements Listener {
|
||||
@EventHandler (priority = EventPriority.MONITOR)
|
||||
public void onEntityDeath(EntityDeathEvent event) {
|
||||
LivingEntity entity = event.getEntity();
|
||||
|
||||
if(entity.hasMetadata("NPC")) return; // Check if this player is a Citizens NPC
|
||||
|
||||
entity.setFireTicks(0);
|
||||
BleedTimer.remove(entity);
|
||||
@@ -199,7 +205,9 @@ public class EntityListener implements Listener {
|
||||
@EventHandler (priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onExplosionPrime(ExplosionPrimeEvent event) {
|
||||
Entity entity = event.getEntity();
|
||||
|
||||
|
||||
if(entity.hasMetadata("NPC")) return; // Check if this player is a Citizens NPC
|
||||
|
||||
if (entity instanceof TNTPrimed) {
|
||||
int id = entity.getEntityId();
|
||||
|
||||
@@ -222,7 +230,11 @@ public class EntityListener implements Listener {
|
||||
public void onEnitityExplode(EntityExplodeEvent event) {
|
||||
Entity entity = event.getEntity();
|
||||
|
||||
if (event.getEntity() instanceof TNTPrimed) {
|
||||
if(entity == null) return;
|
||||
|
||||
if(entity.hasMetadata("NPC")) return; // Check if this player is a Citizens NPC
|
||||
|
||||
if (entity instanceof TNTPrimed) {
|
||||
int id = entity.getEntityId();
|
||||
|
||||
if (plugin.tntIsTracked(id)) {
|
||||
@@ -242,6 +254,9 @@ public class EntityListener implements Listener {
|
||||
public void onFoodLevelChange(FoodLevelChangeEvent event) {
|
||||
if (event.getEntity() instanceof Player) {
|
||||
Player player = (Player) event.getEntity();
|
||||
|
||||
if(player.hasMetadata("NPC")) return; // Check if this player is a Citizens NPC
|
||||
|
||||
PlayerProfile profile = Users.getProfile(player);
|
||||
int currentFoodLevel = player.getFoodLevel();
|
||||
int newFoodLevel = event.getFoodLevel();
|
||||
@@ -284,6 +299,35 @@ public class EntityListener implements Listener {
|
||||
rankChange = 200;
|
||||
break;
|
||||
|
||||
case CARROT_ITEM:
|
||||
/* CARROT RESTORES 2 HUNGER - RESTORES 4 1/2 HUNGER @ 1000 */
|
||||
rankChange = 200;
|
||||
break;
|
||||
|
||||
case POTATO_ITEM:
|
||||
/* POTATO RESTORES 1/2 HUNGER - RESTORES 2 HUNGER @ 1000 */
|
||||
rankChange = 400;
|
||||
break;
|
||||
|
||||
case BAKED_POTATO:
|
||||
/* BAKED POTATO RESTORES 3 HUNGER - RESTORES 5 1/2 HUNGER @ 1000 */
|
||||
rankChange = 200;
|
||||
break;
|
||||
|
||||
case POISONOUS_POTATO:
|
||||
/* POISONOUS POTATO RESTORES 1 HUNGER - RESTORES 2 1/2 HUNGER @ 1000 */
|
||||
rankChange = 400;
|
||||
break;
|
||||
|
||||
case GOLDEN_CARROT:
|
||||
/* GOLDEN CARROT RESTORES 3 HUNGER - RESTORES 5 1/2 HUNGER @ 1000 */
|
||||
rankChange = 200;
|
||||
break;
|
||||
|
||||
case PUMPKIN_PIE:
|
||||
/* PUMPKIN PIE RESTORES 4 HUNGER - RESTORES 6 1/2 HUNGER @ 1000 */
|
||||
rankChange = 200;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
@@ -314,7 +358,9 @@ public class EntityListener implements Listener {
|
||||
@EventHandler (priority = EventPriority.MONITOR)
|
||||
public void onEntityTame(EntityTameEvent event) {
|
||||
Player player = (Player) event.getOwner();
|
||||
|
||||
|
||||
if(player.hasMetadata("NPC")) return; // Check if this player is a Citizens NPC
|
||||
|
||||
if (Permissions.getInstance().taming(player) && !event.getEntity().hasMetadata("mcmmoSummoned")) {
|
||||
PlayerProfile profile = Users.getProfile(player);
|
||||
EntityType type = event.getEntityType();
|
||||
|
||||
@@ -20,9 +20,11 @@ public class HardcoreListener implements Listener {
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerDeath(PlayerDeathEvent event) {
|
||||
Player player = event.getEntity(); //Note this returns a Player object for this subevent
|
||||
|
||||
if(player.hasMetadata("NPC")) return; // Check if this player is a Citizens NPC
|
||||
|
||||
if (!Permissions.getInstance().hardcoremodeBypass(player)) {
|
||||
if (Config.getInstance().getHardcoreVampirismEnabled()) {
|
||||
if (player.getKiller() != null && Config.getInstance().getHardcoreVampirismEnabled()) {
|
||||
Hardcore.invokeVampirism(player.getKiller(), player);
|
||||
}
|
||||
|
||||
|
||||
@@ -58,6 +58,9 @@ public class PlayerListener implements Listener {
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onPlayerWorldChangeEvent(PlayerChangedWorldEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
|
||||
if(player.hasMetadata("NPC")) return; // Check if this player is a Citizens NPC
|
||||
|
||||
PlayerProfile profile = Users.getProfile(player);
|
||||
|
||||
if (profile == null) {
|
||||
@@ -87,6 +90,8 @@ public class PlayerListener implements Listener {
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onPlayerFish(PlayerFishEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
|
||||
if(player.hasMetadata("NPC")) return; // Check if this player is a Citizens NPC
|
||||
|
||||
if (Permissions.getInstance().fishing(player)) {
|
||||
State state = event.getState();
|
||||
@@ -119,6 +124,9 @@ public class PlayerListener implements Listener {
|
||||
*/
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onPlayerPickupItem(PlayerPickupItemEvent event) {
|
||||
|
||||
if(event.getPlayer().hasMetadata("NPC")) return; // Check if this player is a Citizens NPC
|
||||
|
||||
PlayerProfile profile = Users.getProfile(event.getPlayer());
|
||||
|
||||
if (profile == null) {
|
||||
@@ -137,6 +145,7 @@ public class PlayerListener implements Listener {
|
||||
*/
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onPlayerLogin(PlayerLoginEvent event) {
|
||||
if(event.getPlayer().hasMetadata("NPC")) return; // Check if this player is a Citizens NPC
|
||||
Users.addUser(event.getPlayer()).getProfile().actualizeRespawnATS();
|
||||
}
|
||||
|
||||
@@ -148,6 +157,8 @@ public class PlayerListener implements Listener {
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
|
||||
if(player.hasMetadata("NPC")) return; // Check if this player is a Citizens NPC
|
||||
|
||||
/* GARBAGE COLLECTION */
|
||||
|
||||
@@ -163,6 +174,8 @@ public class PlayerListener implements Listener {
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
|
||||
if(player.hasMetadata("NPC")) return; // Check if this player is a Citizens NPC
|
||||
|
||||
//TODO: Locale ALL the things.
|
||||
if (Config.getInstance().getMOTDEnabled() && Permissions.getInstance().motd(player)) {
|
||||
@@ -205,6 +218,7 @@ public class PlayerListener implements Listener {
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onPlayerRespawn(PlayerRespawnEvent event) {
|
||||
if(event.getPlayer().hasMetadata("NPC")) return; // Check if this player is a Citizens NPC
|
||||
PlayerProfile profile = Users.getProfile(event.getPlayer());
|
||||
|
||||
if (profile != null) {
|
||||
@@ -220,6 +234,7 @@ public class PlayerListener implements Listener {
|
||||
@EventHandler(priority = EventPriority.LOW)
|
||||
public void onPlayerInteract(PlayerInteractEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
if(player.hasMetadata("NPC")) return; // Check if this player is a Citizens NPC
|
||||
Action action = event.getAction();
|
||||
Block block = event.getClickedBlock();
|
||||
ItemStack inHand = player.getItemInHand();
|
||||
@@ -331,6 +346,9 @@ public class PlayerListener implements Listener {
|
||||
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
|
||||
public void onPlayerChat(AsyncPlayerChatEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
|
||||
if(player.hasMetadata("NPC")) return; // Check if this player is a Citizens NPC
|
||||
|
||||
PlayerProfile profile = Users.getProfile(player);
|
||||
|
||||
if (profile == null) {
|
||||
|
||||
@@ -1,23 +1,38 @@
|
||||
package com.gmail.nossr50.listeners;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.world.ChunkLoadEvent;
|
||||
import org.bukkit.event.world.ChunkUnloadEvent;
|
||||
import org.bukkit.event.world.WorldLoadEvent;
|
||||
import org.bukkit.event.world.WorldInitEvent;
|
||||
import org.bukkit.event.world.WorldSaveEvent;
|
||||
import org.bukkit.event.world.WorldUnloadEvent;
|
||||
import org.bukkit.World;
|
||||
|
||||
import com.gmail.nossr50.mcMMO;
|
||||
import com.gmail.nossr50.runnables.blockstoreconversion.BlockStoreConversionMain;
|
||||
import com.gmail.nossr50.util.blockmeta.chunkmeta.HashChunkManager;
|
||||
|
||||
public class WorldListener implements Listener {
|
||||
ArrayList<BlockStoreConversionMain> converters = new ArrayList<BlockStoreConversionMain>();
|
||||
|
||||
@EventHandler
|
||||
public void onWorldLoad(WorldLoadEvent event) {
|
||||
public void onWorldInit(WorldInitEvent event) {
|
||||
File dataDir = new File(event.getWorld().getWorldFolder(), "mcmmo_data");
|
||||
if(!dataDir.exists()) {
|
||||
dataDir.mkdir();
|
||||
return;
|
||||
}
|
||||
|
||||
if(mcMMO.p == null)
|
||||
return;
|
||||
|
||||
mcMMO.p.getLogger().info("Converting block storage for " + event.getWorld().getName() + " to a new format.");
|
||||
BlockStoreConversionMain converter = new BlockStoreConversionMain(event.getWorld());
|
||||
converter.run();
|
||||
converters.add(converter);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
|
||||
@@ -14,6 +14,7 @@ import org.bukkit.plugin.PluginDescriptionFile;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
import org.bukkit.World;
|
||||
|
||||
import com.gmail.nossr50.commands.general.AddlevelsCommand;
|
||||
import com.gmail.nossr50.commands.general.AddxpCommand;
|
||||
@@ -78,8 +79,9 @@ import com.gmail.nossr50.util.Leaderboard;
|
||||
import com.gmail.nossr50.util.Metrics;
|
||||
import com.gmail.nossr50.util.Metrics.Graph;
|
||||
import com.gmail.nossr50.util.Users;
|
||||
import com.gmail.nossr50.util.blockmeta.ChunkletManager;
|
||||
import com.gmail.nossr50.util.blockmeta.ChunkletManagerFactory;
|
||||
import com.gmail.nossr50.util.blockmeta.chunkmeta.ChunkManager;
|
||||
import com.gmail.nossr50.util.blockmeta.chunkmeta.ChunkManagerFactory;
|
||||
|
||||
|
||||
public class mcMMO extends JavaPlugin {
|
||||
|
||||
@@ -95,7 +97,7 @@ public class mcMMO extends JavaPlugin {
|
||||
private static Database database;
|
||||
public static mcMMO p;
|
||||
|
||||
public static ChunkletManager placeStore;
|
||||
public static ChunkManager placeStore;
|
||||
public static RepairManager repairManager;
|
||||
|
||||
/* Jar Stuff */
|
||||
@@ -223,7 +225,7 @@ public class mcMMO extends JavaPlugin {
|
||||
}
|
||||
|
||||
// Get our ChunkletManager
|
||||
placeStore = ChunkletManagerFactory.getChunkletManager();
|
||||
placeStore = ChunkManagerFactory.getChunkManager();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,33 +11,74 @@ import com.gmail.nossr50.datatypes.SkillType;
|
||||
public class GreenThumbTimer implements Runnable {
|
||||
private Block block;
|
||||
private PlayerProfile profile;
|
||||
private Material type;
|
||||
|
||||
public GreenThumbTimer(Block block, PlayerProfile profile) {
|
||||
public GreenThumbTimer(Block block, PlayerProfile profile, Material material) {
|
||||
this.block = block;
|
||||
this.profile = profile;
|
||||
this.type = material;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
block.setType(Material.CROPS);
|
||||
if(this.block.getType() != this.type)
|
||||
this.block.setType(this.type);
|
||||
|
||||
//This replants the wheat at a certain stage in development based on Herbalism Skill
|
||||
if (!profile.getAbilityMode(AbilityType.GREEN_TERRA)) {
|
||||
if (profile.getSkillLevel(SkillType.HERBALISM) >= 600) {
|
||||
block.setData(CropState.MEDIUM.getData());
|
||||
}
|
||||
else if (profile.getSkillLevel(SkillType.HERBALISM) >= 400) {
|
||||
block.setData(CropState.SMALL.getData());
|
||||
}
|
||||
else if (profile.getSkillLevel(SkillType.HERBALISM) >= 200) {
|
||||
block.setData(CropState.VERY_SMALL.getData());
|
||||
switch(this.type) {
|
||||
case CROPS:
|
||||
case CARROT:
|
||||
case POTATO:
|
||||
//This replants the wheat at a certain stage in development based on Herbalism Skill
|
||||
if (!this.profile.getAbilityMode(AbilityType.GREEN_TERRA)) {
|
||||
if (this.profile.getSkillLevel(SkillType.HERBALISM) >= 600) {
|
||||
this.block.setData(CropState.MEDIUM.getData());
|
||||
}
|
||||
else if (this.profile.getSkillLevel(SkillType.HERBALISM) >= 400) {
|
||||
this.block.setData(CropState.SMALL.getData());
|
||||
}
|
||||
else if (this.profile.getSkillLevel(SkillType.HERBALISM) >= 200) {
|
||||
this.block.setData(CropState.VERY_SMALL.getData());
|
||||
}
|
||||
else {
|
||||
this.block.setData(CropState.GERMINATED.getData());
|
||||
}
|
||||
}
|
||||
else {
|
||||
block.setData(CropState.GERMINATED.getData());
|
||||
this.block.setData(CropState.MEDIUM.getData());
|
||||
}
|
||||
}
|
||||
else {
|
||||
block.setData(CropState.MEDIUM.getData());
|
||||
break;
|
||||
case NETHER_WARTS:
|
||||
if (!this.profile.getAbilityMode(AbilityType.GREEN_TERRA)) {
|
||||
if (this.profile.getSkillLevel(SkillType.HERBALISM) >= 600) {
|
||||
this.block.setData((byte) 2);
|
||||
}
|
||||
else if (this.profile.getSkillLevel(SkillType.HERBALISM) >= 400) {
|
||||
this.block.setData((byte) 1);
|
||||
}
|
||||
else {
|
||||
this.block.setData((byte) 0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.block.setData((byte) 2);
|
||||
}
|
||||
break;
|
||||
case COCOA:
|
||||
if (!this.profile.getAbilityMode(AbilityType.GREEN_TERRA)) {
|
||||
if (this.profile.getSkillLevel(SkillType.HERBALISM) >= 600) {
|
||||
this.block.setData((byte) ((this.block.getData() ^ ((byte) 0xc)) | ((byte) 4)));
|
||||
}
|
||||
else if (this.profile.getSkillLevel(SkillType.HERBALISM) >= 400) {
|
||||
this.block.setData((byte) ((this.block.getData() ^ ((byte) 0xc)) | ((byte) 4)));
|
||||
}
|
||||
else {
|
||||
this.block.setData((byte) (this.block.getData() ^ ((byte) 0xc)));
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.block.setData((byte) ((this.block.getData() ^ ((byte) 0xc)) | ((byte) 4)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,15 +15,12 @@ public class SQLReconnect implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (!Database.isConnected()) {
|
||||
Database.connect();
|
||||
if (Database.isConnected()) {
|
||||
Users.saveAll(); //Save all profiles
|
||||
Users.clearAll(); //Clear the profiles
|
||||
if (Database.checkConnected()) {
|
||||
Users.saveAll(); //Save all profiles
|
||||
Users.clearAll(); //Clear the profiles
|
||||
|
||||
for (Player player : plugin.getServer().getOnlinePlayers()) {
|
||||
Users.addUser(player); //Add in new profiles, forcing them to 'load' again from MySQL
|
||||
}
|
||||
for (Player player : plugin.getServer().getOnlinePlayers()) {
|
||||
Users.addUser(player); //Add in new profiles, forcing them to 'load' again from MySQL
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
package com.gmail.nossr50.runnables.blockstoreconversion;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.Runnable;
|
||||
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
|
||||
import com.gmail.nossr50.config.HiddenConfig;
|
||||
import com.gmail.nossr50.mcMMO;
|
||||
|
||||
public class BlockStoreConversionMain implements Runnable {
|
||||
private int taskID, i;
|
||||
private org.bukkit.World world;
|
||||
BukkitScheduler scheduler;
|
||||
File dataDir;
|
||||
File[] xDirs;
|
||||
BlockStoreConversionXDirectory[] converters;
|
||||
|
||||
public BlockStoreConversionMain(org.bukkit.World world) {
|
||||
this.taskID = -1;
|
||||
this.world = world;
|
||||
this.scheduler = mcMMO.p.getServer().getScheduler();
|
||||
this.dataDir = new File(this.world.getWorldFolder(), "mcmmo_data");
|
||||
this.converters = new BlockStoreConversionXDirectory[HiddenConfig.getInstance().getConversionRate()];
|
||||
}
|
||||
|
||||
public void start() {
|
||||
if(this.taskID >= 0)
|
||||
return;
|
||||
|
||||
this.taskID = this.scheduler.scheduleSyncDelayedTask(mcMMO.p, this, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
if(!this.dataDir.exists()) {
|
||||
softStop();
|
||||
return;
|
||||
}
|
||||
|
||||
if(!this.dataDir.isDirectory()) {
|
||||
this.dataDir.delete();
|
||||
softStop();
|
||||
return;
|
||||
}
|
||||
|
||||
if(this.dataDir.listFiles().length <= 0) {
|
||||
this.dataDir.delete();
|
||||
softStop();
|
||||
return;
|
||||
}
|
||||
|
||||
this.xDirs = this.dataDir.listFiles();
|
||||
|
||||
for (this.i = 0; (this.i < HiddenConfig.getInstance().getConversionRate()) && (this.i < this.xDirs.length); this.i++) {
|
||||
if(this.converters[this.i] == null)
|
||||
this.converters[this.i] = new BlockStoreConversionXDirectory();
|
||||
|
||||
this.converters[this.i].start(this.world, this.xDirs[this.i]);
|
||||
}
|
||||
|
||||
softStop();
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
if(this.taskID < 0)
|
||||
return;
|
||||
|
||||
this.scheduler.cancelTask(this.taskID);
|
||||
this.taskID = -1;
|
||||
}
|
||||
|
||||
public void softStop() {
|
||||
stop();
|
||||
|
||||
if(this.dataDir.exists() || this.dataDir.isDirectory()) {
|
||||
start();
|
||||
return;
|
||||
}
|
||||
|
||||
mcMMO.p.getLogger().info("Finished converting the storage for " + world.getName() + ".");
|
||||
|
||||
this.dataDir = null;
|
||||
this.xDirs = null;
|
||||
this.world = null;
|
||||
this.scheduler = null;
|
||||
this.converters = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package com.gmail.nossr50.runnables.blockstoreconversion;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.Runnable;
|
||||
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
|
||||
import com.gmail.nossr50.config.HiddenConfig;
|
||||
import com.gmail.nossr50.mcMMO;
|
||||
|
||||
public class BlockStoreConversionXDirectory implements Runnable {
|
||||
private int taskID, i;
|
||||
private org.bukkit.World world;
|
||||
BukkitScheduler scheduler;
|
||||
File dataDir;
|
||||
File[] zDirs;
|
||||
BlockStoreConversionZDirectory[] converters;
|
||||
|
||||
public BlockStoreConversionXDirectory() {
|
||||
this.taskID = -1;
|
||||
}
|
||||
|
||||
public void start(org.bukkit.World world, File dataDir) {
|
||||
this.world = world;
|
||||
this.scheduler = mcMMO.p.getServer().getScheduler();
|
||||
this.converters = new BlockStoreConversionZDirectory[HiddenConfig.getInstance().getConversionRate()];
|
||||
this.dataDir = dataDir;
|
||||
|
||||
if(this.taskID >= 0)
|
||||
return;
|
||||
|
||||
this.taskID = this.scheduler.scheduleSyncDelayedTask(mcMMO.p, this, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
if(!this.dataDir.exists()) {
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
if(!this.dataDir.isDirectory()) {
|
||||
this.dataDir.delete();
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
if(this.dataDir.listFiles().length <= 0) {
|
||||
this.dataDir.delete();
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
this.zDirs = this.dataDir.listFiles();
|
||||
|
||||
for (this.i = 0; (this.i < HiddenConfig.getInstance().getConversionRate()) && (this.i < this.zDirs.length); this.i++) {
|
||||
if(this.converters[this.i] == null)
|
||||
this.converters[this.i] = new BlockStoreConversionZDirectory();
|
||||
|
||||
this.converters[this.i].start(this.world, this.dataDir, this.zDirs[this.i]);
|
||||
}
|
||||
|
||||
stop();
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
if(this.taskID < 0)
|
||||
return;
|
||||
|
||||
this.scheduler.cancelTask(this.taskID);
|
||||
this.taskID = -1;
|
||||
|
||||
this.dataDir = null;
|
||||
this.zDirs = null;
|
||||
this.world = null;
|
||||
this.scheduler = null;
|
||||
this.converters = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
package com.gmail.nossr50.runnables.blockstoreconversion;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.Runnable;
|
||||
import java.lang.String;
|
||||
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
|
||||
import com.gmail.nossr50.mcMMO;
|
||||
import com.gmail.nossr50.util.blockmeta.ChunkletStore;
|
||||
import com.gmail.nossr50.util.blockmeta.PrimitiveChunkletStore;
|
||||
import com.gmail.nossr50.util.blockmeta.PrimitiveExChunkletStore;
|
||||
import com.gmail.nossr50.util.blockmeta.chunkmeta.PrimitiveChunkStore;
|
||||
import com.gmail.nossr50.util.blockmeta.HashChunkletManager;
|
||||
import com.gmail.nossr50.util.blockmeta.chunkmeta.HashChunkManager;
|
||||
|
||||
public class BlockStoreConversionZDirectory implements Runnable {
|
||||
public int taskID, cx, cz, x, y, z, y2, xPos, zPos, cxPos, czPos;
|
||||
private String cxs, czs, chunkletName, chunkName;
|
||||
private org.bukkit.World world;
|
||||
private BukkitScheduler scheduler;
|
||||
private File xDir, dataDir;
|
||||
private HashChunkletManager manager;
|
||||
private HashChunkManager newManager;
|
||||
private ChunkletStore tempChunklet;
|
||||
private PrimitiveChunkletStore primitiveChunklet = null;
|
||||
private PrimitiveExChunkletStore primitiveExChunklet = null;
|
||||
private PrimitiveChunkStore currentChunk;
|
||||
private boolean[] oldArray, newArray;
|
||||
|
||||
public BlockStoreConversionZDirectory() {
|
||||
this.taskID = -1;
|
||||
}
|
||||
|
||||
public void start(org.bukkit.World world, File xDir, File dataDir) {
|
||||
this.world = world;
|
||||
this.scheduler = mcMMO.p.getServer().getScheduler();
|
||||
this.manager = new HashChunkletManager();
|
||||
this.newManager = (HashChunkManager) mcMMO.p.placeStore;
|
||||
this.dataDir = dataDir;
|
||||
this.xDir = xDir;
|
||||
|
||||
if(this.taskID >= 0)
|
||||
return;
|
||||
|
||||
this.taskID = this.scheduler.scheduleSyncDelayedTask(mcMMO.p, this, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
if(!this.dataDir.exists()) {
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
if(!this.dataDir.isDirectory()) {
|
||||
this.dataDir.delete();
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
if(this.dataDir.listFiles().length <= 0) {
|
||||
this.dataDir.delete();
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
this.cxs = this.xDir.getName();
|
||||
this.czs = this.dataDir.getName();
|
||||
this.cx = 0;
|
||||
this.cz = 0;
|
||||
|
||||
try {
|
||||
this.cx = Integer.parseInt(this.cxs);
|
||||
this.cz = Integer.parseInt(this.czs);
|
||||
}
|
||||
catch(Exception e) {
|
||||
this.dataDir.delete();
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
this.manager.loadChunk(this.cx, this.cz, this.world);
|
||||
|
||||
for(this.y = 0; this.y < (this.world.getMaxHeight() / 64); this.y++) {
|
||||
this.chunkletName = this.world.getName() + "," + this.cx + "," + this.cz + "," + this.y;
|
||||
this.tempChunklet = this.manager.store.get(this.chunkletName);
|
||||
if(this.tempChunklet instanceof PrimitiveChunkletStore)
|
||||
this.primitiveChunklet = (PrimitiveChunkletStore) this.tempChunklet;
|
||||
else if(this.tempChunklet instanceof PrimitiveExChunkletStore)
|
||||
this.primitiveExChunklet = (PrimitiveExChunkletStore) this.tempChunklet;
|
||||
if(this.tempChunklet == null) {
|
||||
continue;
|
||||
} else {
|
||||
this.chunkName = this.world.getName() + "," + this.cx + "," + this.cz;
|
||||
this.currentChunk = (PrimitiveChunkStore) this.newManager.store.get(this.chunkName);
|
||||
|
||||
if(this.currentChunk != null) {
|
||||
this.xPos = this.cx * 16;
|
||||
this.zPos = this.cz * 16;
|
||||
|
||||
for(this.x = 0; this.x < 16; this.x++) {
|
||||
for(this.z = 0; this.z < 16; this.z++) {
|
||||
this.cxPos = this.xPos + this.x;
|
||||
this.czPos = this.zPos + this.z;
|
||||
|
||||
for(this.y2 = (64 * this.y); this.y2 < (64 * this.y + 64); this.y2++) {
|
||||
try {
|
||||
if(!this.manager.isTrue(this.cxPos, this.y2, this.czPos, this.world))
|
||||
continue;
|
||||
|
||||
this.newManager.setTrue(this.cxPos, this.y2, this.czPos, this.world);
|
||||
}
|
||||
catch(Exception e) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
this.newManager.setTrue(this.cx * 16, 0, this.cz * 16, this.world);
|
||||
this.newManager.setFalse(this.cx * 16, 0, this.cz * 16, this.world);
|
||||
this.currentChunk = (PrimitiveChunkStore) this.newManager.store.get(this.chunkName);
|
||||
|
||||
for(this.x = 0; this.x < 16; this.x++) {
|
||||
for(this.z = 0; this.z < 16; this.z++) {
|
||||
if(this.primitiveChunklet != null)
|
||||
this.oldArray = this.primitiveChunklet.store[x][z];
|
||||
if(this.primitiveExChunklet != null)
|
||||
this.oldArray = this.primitiveExChunklet.store[x][z];
|
||||
else
|
||||
return;
|
||||
this.newArray = this.currentChunk.store[x][z];
|
||||
if(this.oldArray.length < 64)
|
||||
return;
|
||||
else if(this.newArray.length < ((this.y * 64) + 64))
|
||||
return;
|
||||
System.arraycopy(this.oldArray, 0, this.newArray, (this.y * 64), 64);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.manager.unloadChunk(this.cx, this.cz, this.world);
|
||||
this.newManager.unloadChunk(this.cx, this.cz, this.world);
|
||||
|
||||
for(File yFile : dataDir.listFiles()) {
|
||||
if(!yFile.exists())
|
||||
continue;
|
||||
|
||||
yFile.delete();
|
||||
}
|
||||
|
||||
stop();
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
if(this.taskID < 0)
|
||||
return;
|
||||
|
||||
this.scheduler.cancelTask(taskID);
|
||||
this.taskID = -1;
|
||||
|
||||
this.cxs = null;
|
||||
this.czs = null;
|
||||
this.chunkletName = null;
|
||||
this.chunkName = null;
|
||||
this.manager = null;
|
||||
this.xDir = null;
|
||||
this.dataDir = null;
|
||||
this.tempChunklet = null;
|
||||
this.primitiveChunklet = null;
|
||||
this.primitiveExChunklet = null;
|
||||
this.currentChunk = null;
|
||||
}
|
||||
}
|
||||
@@ -51,6 +51,9 @@ public abstract class AcrobaticsEventHandler {
|
||||
* @return true if the damage is fatal, false otherwise
|
||||
*/
|
||||
protected boolean isFatal(int damage) {
|
||||
if(player == null)
|
||||
return true;
|
||||
|
||||
if (player.getHealth() - damage < 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.gmail.nossr50.skills.acrobatics;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.entity.EntityDamageEvent;
|
||||
|
||||
import com.gmail.nossr50.config.Config;
|
||||
import com.gmail.nossr50.datatypes.PlayerProfile;
|
||||
import com.gmail.nossr50.datatypes.SkillType;
|
||||
import com.gmail.nossr50.util.Permissions;
|
||||
@@ -26,10 +27,16 @@ public class AcrobaticsManager {
|
||||
* @param event The event to check
|
||||
*/
|
||||
public void rollCheck(EntityDamageEvent event) {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
if (!permissionInstance.roll(player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(Config.getInstance().getAcrobaticsAFKDisabled() && player.isInsideVehicle())
|
||||
return;
|
||||
|
||||
RollEventHandler eventHandler = new RollEventHandler(this, event);
|
||||
|
||||
int randomChance = 1000;
|
||||
@@ -54,6 +61,9 @@ public class AcrobaticsManager {
|
||||
* @param event The event to check
|
||||
*/
|
||||
public void dodgeCheck(EntityDamageEvent event) {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
if (!permissionInstance.dodge(player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -39,11 +39,17 @@ public class DodgeEventHandler extends AcrobaticsEventHandler {
|
||||
|
||||
@Override
|
||||
protected void sendAbilityMessage() {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
player.sendMessage(LocaleLoader.getString("Acrobatics.Combat.Proc"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processXPGain(int xp) {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
PlayerProfile profile = manager.getProfile();
|
||||
|
||||
if (System.currentTimeMillis() >= profile.getRespawnATS() + 5) {
|
||||
|
||||
@@ -56,6 +56,9 @@ public class RollEventHandler extends AcrobaticsEventHandler {
|
||||
|
||||
@Override
|
||||
protected void sendAbilityMessage() {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
if (isGraceful) {
|
||||
player.sendMessage(LocaleLoader.getString("Acrobatics.Ability.Proc"));
|
||||
}
|
||||
@@ -67,6 +70,9 @@ public class RollEventHandler extends AcrobaticsEventHandler {
|
||||
|
||||
@Override
|
||||
protected void processXPGain(int xpGain) {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
Skills.xpProcessing(player, manager.getProfile(), SkillType.ACROBATICS, xpGain);
|
||||
}
|
||||
|
||||
@@ -74,6 +80,9 @@ public class RollEventHandler extends AcrobaticsEventHandler {
|
||||
* Check if this is a graceful roll.
|
||||
*/
|
||||
private void isGracefulRoll() {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
if (Permissions.getInstance().gracefulRoll(player)) {
|
||||
this.isGraceful = player.isSneaking();
|
||||
}
|
||||
|
||||
@@ -18,6 +18,11 @@ public class ArcheryManager {
|
||||
public ArcheryManager (Player player) {
|
||||
this.player = player;
|
||||
this.profile = Users.getProfile(player);
|
||||
|
||||
//Compatibility with Citizens, Citizens NPCs won't create a profile so we'll check for it here
|
||||
if(this.profile == null)
|
||||
return;
|
||||
|
||||
this.skillLevel = profile.getSkillLevel(SkillType.ARCHERY);
|
||||
this.permissionsInstance = Permissions.getInstance();
|
||||
}
|
||||
@@ -28,6 +33,12 @@ public class ArcheryManager {
|
||||
* @param livingEntity Entity damaged by the arrow
|
||||
*/
|
||||
public void trackArrows(LivingEntity livingEntity) {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
if(permissionsInstance == null)
|
||||
return;
|
||||
|
||||
if (!permissionsInstance.trackArrows(player)) {
|
||||
return;
|
||||
}
|
||||
@@ -52,6 +63,12 @@ public class ArcheryManager {
|
||||
* @param event The event to modify
|
||||
*/
|
||||
public void dazeCheck(Player defender, EntityDamageEvent event) {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
if(permissionsInstance == null)
|
||||
return;
|
||||
|
||||
if (!permissionsInstance.daze(player)) {
|
||||
return;
|
||||
}
|
||||
@@ -76,6 +93,12 @@ public class ArcheryManager {
|
||||
* @param event The event to modify.
|
||||
*/
|
||||
public void bonusDamage(EntityDamageEvent event) {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
if(permissionsInstance == null)
|
||||
return;
|
||||
|
||||
if (!permissionsInstance.archeryBonus(player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,9 @@ public class Axes {
|
||||
* @param event The event to modify
|
||||
*/
|
||||
public static void axesBonus(Player attacker, EntityDamageByEntityEvent event) {
|
||||
if(attacker == null)
|
||||
return;
|
||||
|
||||
final int MAX_BONUS = 4;
|
||||
|
||||
/* Add 1 DMG for every 50 skill levels */
|
||||
@@ -49,6 +52,9 @@ public class Axes {
|
||||
* @param event The event to modify
|
||||
*/
|
||||
public static void axeCriticalCheck(Player attacker, EntityDamageByEntityEvent event) {
|
||||
if(attacker == null)
|
||||
return;
|
||||
|
||||
Entity entity = event.getEntity();
|
||||
|
||||
if (entity instanceof Tameable) {
|
||||
@@ -102,7 +108,10 @@ public class Axes {
|
||||
* @param target The defending entity
|
||||
* @param event The event to modify
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public static void impact(Player attacker, LivingEntity target, EntityDamageByEntityEvent event) {
|
||||
if(attacker == null)
|
||||
return;
|
||||
|
||||
/*
|
||||
* TODO: Finish this skill. The idea is you will greatly damage an opponents armor.
|
||||
@@ -110,17 +119,18 @@ public class Axes {
|
||||
*/
|
||||
if (target instanceof Player) {
|
||||
Player targetPlayer = (Player) target;
|
||||
short durabilityDamage = 5; //Start with 5 durability damage
|
||||
short durabilityDamage = 1; //Start with 1 durability damage
|
||||
|
||||
/* Every 30 Skill Levels you gain 1 durability damage */
|
||||
durabilityDamage += Users.getProfile(attacker).getSkillLevel(SkillType.AXES)/30;
|
||||
durabilityDamage += Users.getProfile(attacker).getSkillLevel(SkillType.AXES)/50;
|
||||
|
||||
if (!hasArmor(targetPlayer)) {
|
||||
applyGreaterImpact(attacker, target, event);
|
||||
}
|
||||
else {
|
||||
for (ItemStack armor : targetPlayer.getInventory().getArmorContents()) {
|
||||
armor.setDurability((short) (armor.getDurability() + durabilityDamage)); //Damage armor piece
|
||||
if(Math.random() * 100 > 75)
|
||||
armor.setDurability((short) (armor.getDurability() + durabilityDamage)); //Damage armor piece
|
||||
}
|
||||
targetPlayer.updateInventory();
|
||||
}
|
||||
@@ -138,6 +148,9 @@ public class Axes {
|
||||
* @param event The event to modify
|
||||
*/
|
||||
private static void applyGreaterImpact(Player attacker, LivingEntity target, EntityDamageByEntityEvent event) {
|
||||
if(attacker == null)
|
||||
return;
|
||||
|
||||
final int GREATER_IMPACT_CHANCE = 25;
|
||||
final double GREATER_IMPACT_MULTIPLIER = 1.5;
|
||||
|
||||
@@ -165,6 +178,9 @@ public class Axes {
|
||||
* @return true if the player has armor, false otherwise
|
||||
*/
|
||||
private static boolean hasArmor(Player player) {
|
||||
if(player == null)
|
||||
return false;
|
||||
|
||||
PlayerInventory inventory = player.getInventory();
|
||||
|
||||
if (inventory.getBoots() != null || inventory.getChestplate() != null || inventory.getHelmet() != null || inventory.getLeggings() != null) {
|
||||
|
||||
@@ -82,6 +82,9 @@ public class BlastMining {
|
||||
* @param event Event whose explosion is being processed
|
||||
*/
|
||||
public static void dropProcessing(Player player, EntityExplodeEvent event) {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
final int RANK_1_LEVEL = 125;
|
||||
final int RANK_2_LEVEL = 250;
|
||||
final int RANK_3_LEVEL = 375;
|
||||
@@ -172,6 +175,9 @@ public class BlastMining {
|
||||
* @param event Event whose explosion radius is being changed
|
||||
*/
|
||||
public static void biggerBombs(Player player, ExplosionPrimeEvent event) {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
final int RANK_1_LEVEL = 250;
|
||||
final int RANK_2_LEVEL = 500;
|
||||
final int RANK_3_LEVEL = 750;
|
||||
@@ -210,6 +216,9 @@ public class BlastMining {
|
||||
* @param event Event whose explosion damage is being reduced
|
||||
*/
|
||||
public static void demolitionsExpertise(Player player, EntityDamageEvent event) {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
final int RANK_1_LEVEL = 500;
|
||||
final int RANK_2_LEVEL = 750;
|
||||
final int RANK_3_LEVEL = 1000;
|
||||
@@ -242,6 +251,9 @@ public class BlastMining {
|
||||
* @param plugin mcMMO plugin instance
|
||||
*/
|
||||
public static void detonate(PlayerInteractEvent event, Player player, mcMMO plugin) {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
PlayerProfile profile = Users.getProfile(player);
|
||||
|
||||
if (profile.getSkillLevel(SkillType.MINING) < 125)
|
||||
|
||||
@@ -37,6 +37,9 @@ public class Excavation {
|
||||
* @param player The player who broke the block
|
||||
*/
|
||||
public static void excavationProcCheck(Block block, Player player) {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
Material type = block.getType();
|
||||
Location location = block.getLocation();
|
||||
|
||||
@@ -122,9 +125,12 @@ public class Excavation {
|
||||
* @param block The block to check
|
||||
*/
|
||||
public static void gigaDrillBreaker(Player player, Block block) {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
Skills.abilityDurabilityLoss(player.getItemInHand(), Config.getInstance().getAbilityToolDamage());
|
||||
|
||||
if (!mcMMO.placeStore.isTrue(block) || !Misc.blockBreakSimulate(block, player, true)) {
|
||||
if (!mcMMO.placeStore.isTrue(block) && !Misc.blockBreakSimulate(block, player, true)) {
|
||||
FakePlayerAnimationEvent armswing = new FakePlayerAnimationEvent(player);
|
||||
mcMMO.p.getServer().getPluginManager().callEvent(armswing);
|
||||
|
||||
|
||||
360
src/main/java/com/gmail/nossr50/skills/gathering/Fishing.java
Normal file → Executable file
360
src/main/java/com/gmail/nossr50/skills/gathering/Fishing.java
Normal file → Executable file
@@ -17,6 +17,8 @@ import org.bukkit.event.player.PlayerFishEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.material.Wool;
|
||||
|
||||
import org.bukkit.craftbukkit.entity.CraftSkeleton;
|
||||
|
||||
import com.gmail.nossr50.config.Config;
|
||||
import com.gmail.nossr50.config.TreasuresConfig;
|
||||
import com.gmail.nossr50.datatypes.PlayerProfile;
|
||||
@@ -70,6 +72,9 @@ public class Fishing {
|
||||
* @param event The event to modify
|
||||
*/
|
||||
private static void getFishingResults(Player player, PlayerFishEvent event) {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
PlayerProfile profile = Users.getProfile(player);
|
||||
List<FishingTreasure> rewards = new ArrayList<FishingTreasure>();
|
||||
Item theCatch = (Item) event.getCaught();
|
||||
@@ -133,6 +138,9 @@ public class Fishing {
|
||||
*/
|
||||
public static void processResults(PlayerFishEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
PlayerProfile profile = Users.getProfile(player);
|
||||
|
||||
getFishingResults(player, event);
|
||||
@@ -145,7 +153,7 @@ public class Fishing {
|
||||
|
||||
player.sendMessage(LocaleLoader.getString("Fishing.ItemFound"));
|
||||
|
||||
if (ItemChecks.isArmor(fishingResults) || ItemChecks.isTool(fishingResults)) {
|
||||
if (ItemChecks.isEnchantable(fishingResults)) {
|
||||
int randomChance = 100;
|
||||
|
||||
if (player.hasPermission("mcmmo.perks.lucky.fishing")) {
|
||||
@@ -158,9 +166,8 @@ public class Fishing {
|
||||
Map<Enchantment, Integer> resultEnchantments = fishingResults.getEnchantments();
|
||||
|
||||
for (Enchantment oldEnchant : resultEnchantments.keySet()) {
|
||||
if (oldEnchant.conflictsWith(newEnchant)) {
|
||||
return;
|
||||
}
|
||||
if (oldEnchant.conflictsWith(newEnchant))
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Actual chance to have an enchantment is related to your fishing skill */
|
||||
@@ -172,6 +179,9 @@ public class Fishing {
|
||||
randomEnchantLevel = newEnchant.getStartLevel();
|
||||
}
|
||||
|
||||
if(randomEnchantLevel >= 1000)
|
||||
continue;
|
||||
|
||||
fishingResults.addEnchantment(newEnchant, randomEnchantLevel);
|
||||
}
|
||||
}
|
||||
@@ -194,163 +204,251 @@ public class Fishing {
|
||||
int randomChance = 100;
|
||||
|
||||
if (event.getPlayer().hasPermission("mcmmo.perks.lucky.fishing")) {
|
||||
randomChance = (int) (randomChance * 0.75);
|
||||
randomChance = (int) (randomChance * 1.25);
|
||||
}
|
||||
|
||||
final int DROP_NUMBER = random.nextInt(randomChance);
|
||||
final Player player = event.getPlayer();
|
||||
final PlayerProfile profile = Users.getProfile(player);
|
||||
int lootTier = getFishingLootTier(profile);
|
||||
|
||||
int dropChance = getShakeChance(lootTier);
|
||||
|
||||
if (event.getPlayer().hasPermission("mcmmo.perks.lucky.fishing")) {
|
||||
dropChance = (int) (dropChance * 1.25); //With lucky perk on max level tier, its 100%
|
||||
}
|
||||
|
||||
final int DROP_CHANCE = random.nextInt(100);
|
||||
final int DROP_NUMBER = random.nextInt(randomChance) + 1;
|
||||
|
||||
LivingEntity le = (LivingEntity) event.getCaught();
|
||||
EntityType type = le.getType();
|
||||
Location location = le.getLocation();
|
||||
|
||||
switch (type) {
|
||||
case BLAZE:
|
||||
Misc.dropItem(location, new ItemStack(Material.BLAZE_ROD));
|
||||
break;
|
||||
if (DROP_CHANCE < dropChance) {
|
||||
|
||||
case CAVE_SPIDER:
|
||||
if (DROP_NUMBER > 50) {
|
||||
Misc.dropItem(location, new ItemStack(Material.SPIDER_EYE));
|
||||
}
|
||||
else {
|
||||
Misc.dropItem(location, new ItemStack(Material.STRING));
|
||||
}
|
||||
break;
|
||||
switch (type) {
|
||||
case BLAZE:
|
||||
Misc.dropItem(location, new ItemStack(Material.BLAZE_ROD));
|
||||
break;
|
||||
|
||||
case CHICKEN:
|
||||
if (DROP_NUMBER > 66) {
|
||||
Misc.dropItem(location, new ItemStack(Material.FEATHER));
|
||||
}
|
||||
else if (DROP_NUMBER > 33) {
|
||||
Misc.dropItem(location, new ItemStack(Material.RAW_CHICKEN));
|
||||
}
|
||||
else {
|
||||
Misc.dropItem(location, new ItemStack(Material.EGG));
|
||||
}
|
||||
break;
|
||||
case CAVE_SPIDER:
|
||||
if (DROP_NUMBER > 50) {
|
||||
Misc.dropItem(location, new ItemStack(Material.SPIDER_EYE));
|
||||
} else {
|
||||
Misc.dropItem(location, new ItemStack(Material.STRING));
|
||||
}
|
||||
break;
|
||||
|
||||
case COW:
|
||||
if (DROP_NUMBER > 99) {
|
||||
Misc.dropItem(location, new ItemStack(Material.MILK_BUCKET));
|
||||
}
|
||||
else if (DROP_NUMBER > 50) {
|
||||
Misc.dropItem(location, new ItemStack(Material.LEATHER));
|
||||
}
|
||||
else {
|
||||
Misc.dropItem(location, new ItemStack(Material.RAW_BEEF));
|
||||
}
|
||||
break;
|
||||
case CHICKEN:
|
||||
if (DROP_NUMBER > 66) {
|
||||
Misc.dropItem(location, new ItemStack(Material.FEATHER));
|
||||
} else if (DROP_NUMBER > 33) {
|
||||
Misc.dropItem(location, new ItemStack(Material.RAW_CHICKEN));
|
||||
} else {
|
||||
Misc.dropItem(location, new ItemStack(Material.EGG));
|
||||
}
|
||||
break;
|
||||
|
||||
case CREEPER:
|
||||
Misc.dropItem(location, new ItemStack(Material.SULPHUR));
|
||||
break;
|
||||
case COW:
|
||||
if (DROP_NUMBER > 99) {
|
||||
Misc.dropItem(location, new ItemStack(Material.MILK_BUCKET));
|
||||
} else if (DROP_NUMBER > 50) {
|
||||
Misc.dropItem(location, new ItemStack(Material.LEATHER));
|
||||
} else {
|
||||
Misc.dropItem(location, new ItemStack(Material.RAW_BEEF));
|
||||
}
|
||||
break;
|
||||
|
||||
case ENDERMAN:
|
||||
Misc.dropItem(location, new ItemStack(Material.ENDER_PEARL));
|
||||
break;
|
||||
case CREEPER:
|
||||
if (DROP_NUMBER > 99) {
|
||||
Misc.dropItem(location, new ItemStack(Material.SKULL_ITEM, 1, (short) 4));
|
||||
} else {
|
||||
Misc.dropItem(location, new ItemStack(Material.SULPHUR));
|
||||
}
|
||||
break;
|
||||
|
||||
case GHAST:
|
||||
if (DROP_NUMBER > 50) {
|
||||
Misc.dropItem(location, new ItemStack(Material.SULPHUR));
|
||||
}
|
||||
else {
|
||||
Misc.dropItem(location, new ItemStack(Material.GHAST_TEAR));
|
||||
}
|
||||
break;
|
||||
case ENDERMAN:
|
||||
Misc.dropItem(location, new ItemStack(Material.ENDER_PEARL));
|
||||
break;
|
||||
|
||||
case MAGMA_CUBE:
|
||||
Misc.dropItem(location, new ItemStack(Material.MAGMA_CREAM));
|
||||
break;
|
||||
case GHAST:
|
||||
if (DROP_NUMBER > 50) {
|
||||
Misc.dropItem(location, new ItemStack(Material.SULPHUR));
|
||||
} else {
|
||||
Misc.dropItem(location, new ItemStack(Material.GHAST_TEAR));
|
||||
}
|
||||
break;
|
||||
|
||||
case MUSHROOM_COW:
|
||||
if (DROP_NUMBER > 99) {
|
||||
Misc.dropItem(location, new ItemStack(Material.MILK_BUCKET));
|
||||
}
|
||||
else if (DROP_NUMBER > 98) {
|
||||
Misc.dropItem(location, new ItemStack(Material.MUSHROOM_SOUP));
|
||||
}
|
||||
else if (DROP_NUMBER > 66) {
|
||||
Misc.dropItem(location, new ItemStack(Material.LEATHER));
|
||||
}
|
||||
else if (DROP_NUMBER > 33) {
|
||||
Misc.dropItem(location, new ItemStack(Material.RAW_BEEF));
|
||||
}
|
||||
else {
|
||||
Misc.dropItems(location, new ItemStack(Material.RED_MUSHROOM), 3);
|
||||
}
|
||||
break;
|
||||
case IRON_GOLEM:
|
||||
if (DROP_NUMBER > 99) {
|
||||
Misc.dropItem(location, new ItemStack(Material.PUMPKIN));
|
||||
} else if (DROP_NUMBER > 90) {
|
||||
Misc.dropItem(location, new ItemStack(Material.IRON_INGOT));
|
||||
} else {
|
||||
Misc.dropItem(location, new ItemStack(Material.RED_ROSE));
|
||||
}
|
||||
break;
|
||||
|
||||
case PIG:
|
||||
Misc.dropItem(location, new ItemStack(Material.PORK));
|
||||
break;
|
||||
case MAGMA_CUBE:
|
||||
Misc.dropItem(location, new ItemStack(Material.MAGMA_CREAM));
|
||||
break;
|
||||
|
||||
case PIG_ZOMBIE:
|
||||
if (DROP_NUMBER > 50) {
|
||||
Misc.dropItem(location, new ItemStack(Material.ROTTEN_FLESH));
|
||||
}
|
||||
else {
|
||||
Misc.dropItem(location, new ItemStack(Material.GOLD_NUGGET));
|
||||
}
|
||||
break;
|
||||
case MUSHROOM_COW:
|
||||
if (DROP_NUMBER > 99) {
|
||||
Misc.dropItem(location, new ItemStack(Material.MILK_BUCKET));
|
||||
} else if (DROP_NUMBER > 98) {
|
||||
Misc.dropItem(location, new ItemStack(Material.MUSHROOM_SOUP));
|
||||
} else if (DROP_NUMBER > 66) {
|
||||
Misc.dropItem(location, new ItemStack(Material.LEATHER));
|
||||
} else if (DROP_NUMBER > 33) {
|
||||
Misc.dropItem(location, new ItemStack(Material.RAW_BEEF));
|
||||
} else {
|
||||
Misc.dropItems(location, new ItemStack(Material.RED_MUSHROOM), 3);
|
||||
}
|
||||
break;
|
||||
|
||||
case SHEEP:
|
||||
Sheep sheep = (Sheep) le;
|
||||
case PIG:
|
||||
Misc.dropItem(location, new ItemStack(Material.PORK));
|
||||
break;
|
||||
|
||||
if (!sheep.isSheared()) {
|
||||
Wool wool = new Wool();
|
||||
wool.setColor(sheep.getColor());
|
||||
case PIG_ZOMBIE:
|
||||
if (DROP_NUMBER > 50) {
|
||||
Misc.dropItem(location, new ItemStack(Material.ROTTEN_FLESH));
|
||||
} else {
|
||||
Misc.dropItem(location, new ItemStack(Material.GOLD_NUGGET));
|
||||
}
|
||||
break;
|
||||
|
||||
ItemStack theWool = wool.toItemStack();
|
||||
theWool.setAmount(1 + random.nextInt(6));
|
||||
case SHEEP:
|
||||
final Sheep sheep = (Sheep) le;
|
||||
|
||||
Misc.dropItem(location, theWool);
|
||||
sheep.setSheared(true);
|
||||
}
|
||||
break;
|
||||
if (!sheep.isSheared()) {
|
||||
final Wool wool = new Wool();
|
||||
wool.setColor(sheep.getColor());
|
||||
|
||||
case SKELETON:
|
||||
if (DROP_NUMBER > 50) {
|
||||
Misc.dropItem(location, new ItemStack(Material.BONE));
|
||||
}
|
||||
else {
|
||||
Misc.dropItems(location, new ItemStack(Material.ARROW), 3);
|
||||
}
|
||||
break;
|
||||
final ItemStack theWool = wool.toItemStack();
|
||||
theWool.setAmount(1 + random.nextInt(6));
|
||||
|
||||
case SLIME:
|
||||
Misc.dropItem(location, new ItemStack(Material.SLIME_BALL));
|
||||
break;
|
||||
Misc.dropItem(location, theWool);
|
||||
sheep.setSheared(true);
|
||||
}
|
||||
break;
|
||||
|
||||
case SNOWMAN:
|
||||
if (DROP_NUMBER > 99) {
|
||||
Misc.dropItem(location, new ItemStack(Material.PUMPKIN));
|
||||
}
|
||||
else {
|
||||
Misc.dropItems(location, new ItemStack(Material.SNOW_BALL), 5);
|
||||
}
|
||||
break;
|
||||
case SKELETON:
|
||||
if (((CraftSkeleton) le).getHandle().getSkeletonType() == 1) {
|
||||
if (DROP_NUMBER > 97) {
|
||||
Misc.dropItem(location, new ItemStack(Material.SKULL_ITEM, 1, (short) 1));
|
||||
} else if (DROP_NUMBER > 50) {
|
||||
Misc.dropItem(location, new ItemStack(Material.BONE));
|
||||
} else {
|
||||
Misc.dropItems(location, new ItemStack(Material.COAL), 3);
|
||||
}
|
||||
} else {
|
||||
if (DROP_NUMBER > 99) {
|
||||
Misc.dropItem(location, new ItemStack(Material.SKULL_ITEM));
|
||||
} else if (DROP_NUMBER > 50) {
|
||||
Misc.dropItem(location, new ItemStack(Material.BONE));
|
||||
} else {
|
||||
Misc.dropItems(location, new ItemStack(Material.ARROW), 3);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SPIDER:
|
||||
if (DROP_NUMBER > 50) {
|
||||
Misc.dropItem(location, new ItemStack(Material.SPIDER_EYE));
|
||||
}
|
||||
else {
|
||||
Misc.dropItem(location, new ItemStack(Material.STRING));
|
||||
}
|
||||
break;
|
||||
case SLIME:
|
||||
Misc.dropItem(location, new ItemStack(Material.SLIME_BALL));
|
||||
break;
|
||||
|
||||
case SQUID:
|
||||
Misc.dropItem(location, new ItemStack(Material.INK_SACK, 1, (short) 0, (byte) 0x0));
|
||||
break;
|
||||
case SNOWMAN:
|
||||
if (DROP_NUMBER > 99) {
|
||||
Misc.dropItem(location, new ItemStack(Material.PUMPKIN));
|
||||
} else {
|
||||
Misc.dropItems(location, new ItemStack(Material.SNOW_BALL), 5);
|
||||
}
|
||||
break;
|
||||
|
||||
case ZOMBIE:
|
||||
Misc.dropItem(location, new ItemStack(Material.ROTTEN_FLESH));
|
||||
break;
|
||||
case SPIDER:
|
||||
if (DROP_NUMBER > 50) {
|
||||
Misc.dropItem(location, new ItemStack(Material.SPIDER_EYE));
|
||||
} else {
|
||||
Misc.dropItem(location, new ItemStack(Material.STRING));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
case SQUID:
|
||||
Misc.dropItem(location, new ItemStack(Material.INK_SACK, 1, (short) 0, (byte) 0x0));
|
||||
break;
|
||||
|
||||
case WITCH:
|
||||
final int DROP_NUMBER_2 = random.nextInt(randomChance) + 1;
|
||||
if (DROP_NUMBER > 97) {
|
||||
if (DROP_NUMBER_2 > 66) {
|
||||
Misc.dropItem(location, new ItemStack(Material.POTION, 1, (short) 8197));
|
||||
} else if (DROP_NUMBER_2 > 33) {
|
||||
Misc.dropItem(location, new ItemStack(Material.POTION, 1, (short) 8195));
|
||||
} else {
|
||||
Misc.dropItem(location, new ItemStack(Material.POTION, 1, (short) 8194));
|
||||
}
|
||||
} else {
|
||||
if (DROP_NUMBER_2 > 88) {
|
||||
Misc.dropItem(location, new ItemStack(Material.GLASS_BOTTLE));
|
||||
} else if (DROP_NUMBER_2 > 75) {
|
||||
Misc.dropItem(location, new ItemStack(Material.GLOWSTONE_DUST));
|
||||
} else if (DROP_NUMBER_2 > 63) {
|
||||
Misc.dropItem(location, new ItemStack(Material.SULPHUR));
|
||||
} else if (DROP_NUMBER_2 > 50) {
|
||||
Misc.dropItem(location, new ItemStack(Material.REDSTONE));
|
||||
} else if (DROP_NUMBER_2 > 38) {
|
||||
Misc.dropItem(location, new ItemStack(Material.SPIDER_EYE));
|
||||
} else if (DROP_NUMBER_2 > 25) {
|
||||
Misc.dropItem(location, new ItemStack(Material.STICK));
|
||||
} else if (DROP_NUMBER_2 > 13) {
|
||||
Misc.dropItem(location, new ItemStack(Material.SUGAR));
|
||||
} else {
|
||||
Misc.dropItem(location, new ItemStack(Material.POTION));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ZOMBIE:
|
||||
if (DROP_NUMBER > 99) {
|
||||
Misc.dropItem(location, new ItemStack(Material.SKULL_ITEM, 1, (short) 2));
|
||||
} else {
|
||||
Misc.dropItem(location, new ItemStack(Material.ROTTEN_FLESH));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Combat.dealDamage(le, 1);
|
||||
}
|
||||
/**
|
||||
* Gets chance of shake success.
|
||||
*
|
||||
* @param rank Treasure hunter rank
|
||||
* @return The chance of a successful shake
|
||||
*/
|
||||
public static int getShakeChance(int lootTier) {
|
||||
switch (lootTier) {
|
||||
case 1:
|
||||
return Config.getInstance().getShakeChanceRank1();
|
||||
|
||||
case 2:
|
||||
return Config.getInstance().getShakeChanceRank2();
|
||||
|
||||
case 3:
|
||||
return Config.getInstance().getShakeChanceRank3();
|
||||
|
||||
case 4:
|
||||
return Config.getInstance().getShakeChanceRank4();
|
||||
|
||||
case 5:
|
||||
return Config.getInstance().getShakeChanceRank5();
|
||||
|
||||
default:
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,11 @@ public class Herbalism {
|
||||
}
|
||||
else if (Config.getInstance().getHerbalismGreenThumbCobbleToMossy() && type == Material.COBBLESTONE) {
|
||||
block.setType(Material.MOSSY_COBBLESTONE);
|
||||
// Don't award double drops to mossified cobblestone
|
||||
mcMMO.placeStore.setTrue(block);
|
||||
}
|
||||
else if (Config.getInstance().getHerbalismGreenThumbCobbleWallToMossyWall() && type == Material.COBBLE_WALL) {
|
||||
block.setData((byte) 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -75,6 +80,9 @@ public class Herbalism {
|
||||
* @param plugin mcMMO plugin instance
|
||||
*/
|
||||
public static void herbalismProcCheck(final Block block, Player player, BlockBreakEvent event, mcMMO plugin) {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
final PlayerProfile profile = Users.getProfile(player);
|
||||
final int MAX_BONUS_LEVEL = 1000;
|
||||
|
||||
@@ -144,6 +152,10 @@ public class Herbalism {
|
||||
if (data == (byte) 0x3) {
|
||||
mat = Material.NETHER_STALK;
|
||||
xp = Config.getInstance().getHerbalismXPNetherWart();
|
||||
|
||||
if (Permissions.getInstance().greenThumbNetherwart(player)) {
|
||||
greenThumbWheat(block, player, event, plugin);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -191,6 +203,41 @@ public class Herbalism {
|
||||
xp = Config.getInstance().getHerbalismXPLilyPads();
|
||||
}
|
||||
break;
|
||||
|
||||
case COCOA:
|
||||
if ((((byte) data) & 0x8) == 0x8) {
|
||||
mat = Material.COCOA;
|
||||
xp = Config.getInstance().getHerbalismXPCocoa();
|
||||
|
||||
|
||||
if (Permissions.getInstance().greenThumbCocoa(player)) {
|
||||
greenThumbWheat(block, player, event, plugin);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CARROT:
|
||||
if (data == CropState.RIPE.getData()) {
|
||||
mat = Material.CARROT;
|
||||
xp = Config.getInstance().getHerbalismXPCarrot();
|
||||
|
||||
|
||||
if (Permissions.getInstance().greenThumbCarrots(player)) {
|
||||
greenThumbWheat(block, player, event, plugin);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case POTATO:
|
||||
if (data == CropState.RIPE.getData()) {
|
||||
mat = Material.POTATO;
|
||||
xp = Config.getInstance().getHerbalismXPPotato();
|
||||
|
||||
if (Permissions.getInstance().greenThumbPotatoes(player)) {
|
||||
greenThumbWheat(block, player, event, plugin);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (Config.getInstance().getBlockModsEnabled() && CustomBlocksConfig.getInstance().customHerbalismBlocks.contains(new ItemStack(block.getTypeId(), 1, (short) 0, block.getData()))) {
|
||||
@@ -211,7 +258,19 @@ public class Herbalism {
|
||||
is = new ItemStack(ModChecks.getCustomBlock(block).getItemDrop());
|
||||
}
|
||||
else {
|
||||
is = new ItemStack(mat);
|
||||
if (mat == Material.COCOA) {
|
||||
is = new ItemStack(Material.INK_SACK, 1, (short) 3);
|
||||
}
|
||||
else if (mat == Material.CARROT) {
|
||||
is = new ItemStack(Material.CARROT_ITEM, 1, (short) 0);
|
||||
}
|
||||
else if (mat == Material.POTATO) {
|
||||
is = new ItemStack(Material.POTATO_ITEM, 1, (short) 0);
|
||||
}
|
||||
|
||||
else {
|
||||
is = new ItemStack(mat);
|
||||
}
|
||||
}
|
||||
|
||||
if (herbLevel > MAX_BONUS_LEVEL || random.nextInt(randomChance) <= herbLevel) {
|
||||
@@ -285,6 +344,24 @@ public class Herbalism {
|
||||
Misc.dropItem(location, is);
|
||||
}
|
||||
break;
|
||||
|
||||
case COCOA:
|
||||
if (configInstance.getCocoaDoubleDropsEnabled()) {
|
||||
Misc.dropItem(location, is);
|
||||
}
|
||||
break;
|
||||
|
||||
case CARROT:
|
||||
if (configInstance.getCarrotDoubleDropsEnabled()) {
|
||||
Misc.dropItem(location, is);
|
||||
}
|
||||
break;
|
||||
|
||||
case POTATO:
|
||||
if (configInstance.getPotatoDoubleDropsEnabled()) {
|
||||
Misc.dropItem(location, is);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (customPlant) {
|
||||
@@ -307,6 +384,9 @@ public class Herbalism {
|
||||
}
|
||||
}
|
||||
|
||||
if(Config.getInstance().getHerbalismAFKDisabled() && player.isInsideVehicle())
|
||||
return;
|
||||
|
||||
Skills.xpProcessing(player, profile, SkillType.HERBALISM, xp);
|
||||
}
|
||||
|
||||
@@ -324,8 +404,28 @@ public class Herbalism {
|
||||
PlayerProfile profile = Users.getProfile(player);
|
||||
int herbLevel = profile.getSkillLevel(SkillType.HERBALISM);
|
||||
PlayerInventory inventory = player.getInventory();
|
||||
boolean hasSeeds = inventory.contains(Material.SEEDS);
|
||||
boolean hasSeeds = false;
|
||||
Location location = block.getLocation();
|
||||
Material type = block.getType();
|
||||
|
||||
switch(type) {
|
||||
case CROPS:
|
||||
hasSeeds = inventory.contains(Material.SEEDS);
|
||||
break;
|
||||
case COCOA:
|
||||
// Broken: Requires an update to bukkit to enable seaching for variable-sized ItemStacks.
|
||||
hasSeeds = inventory.contains(new ItemStack(Material.INK_SACK, 1, (short) 3), 1);
|
||||
break;
|
||||
case CARROT:
|
||||
hasSeeds = inventory.contains(Material.CARROT_ITEM);
|
||||
break;
|
||||
case POTATO:
|
||||
hasSeeds = inventory.contains(Material.POTATO_ITEM);
|
||||
break;
|
||||
case NETHER_WARTS:
|
||||
hasSeeds = inventory.contains(Material.NETHER_STALK);
|
||||
break;
|
||||
}
|
||||
|
||||
int randomChance = 1500;
|
||||
|
||||
@@ -336,12 +436,35 @@ public class Herbalism {
|
||||
if (hasSeeds && profile.getAbilityMode(AbilityType.GREEN_TERRA) || hasSeeds && (herbLevel > MAX_BONUS_LEVEL || random.nextInt(randomChance) <= herbLevel)) {
|
||||
event.setCancelled(true);
|
||||
|
||||
Misc.dropItem(location, new ItemStack(Material.WHEAT));
|
||||
Misc.randomDropItems(location, new ItemStack(Material.SEEDS), 50, 3);
|
||||
switch(type) {
|
||||
case CROPS:
|
||||
Misc.dropItem(location, new ItemStack(Material.WHEAT));
|
||||
Misc.randomDropItems(location, new ItemStack(Material.SEEDS), 50, 3);
|
||||
inventory.removeItem(new ItemStack(Material.SEEDS));
|
||||
break;
|
||||
case COCOA:
|
||||
Misc.dropItem(location, new ItemStack(Material.INK_SACK, 3, (short) 3));
|
||||
inventory.removeItem(new ItemStack(Material.INK_SACK, 1, (short) 3));
|
||||
break;
|
||||
case CARROT:
|
||||
Misc.dropItem(location, new ItemStack(Material.CARROT_ITEM));
|
||||
Misc.randomDropItems(location, new ItemStack(Material.CARROT_ITEM), 50, 3);
|
||||
inventory.removeItem(new ItemStack(Material.POTATO_ITEM));
|
||||
break;
|
||||
case POTATO:
|
||||
Misc.dropItem(location, new ItemStack(Material.POTATO_ITEM));
|
||||
Misc.randomDropItems(location, new ItemStack(Material.POTATO_ITEM), 50, 3);
|
||||
Misc.randomDropItem(location, new ItemStack(Material.POISONOUS_POTATO), 2);
|
||||
inventory.removeItem(new ItemStack(Material.POTATO_ITEM));
|
||||
break;
|
||||
case NETHER_WARTS:
|
||||
Misc.dropItem(location, new ItemStack(Material.NETHER_STALK, 2));
|
||||
Misc.randomDropItems(location, new ItemStack(Material.NETHER_STALK), 50, 2);
|
||||
inventory.removeItem(new ItemStack(Material.NETHER_STALK));
|
||||
break;
|
||||
}
|
||||
|
||||
plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new GreenThumbTimer(block, profile), 1);
|
||||
|
||||
inventory.removeItem(new ItemStack(Material.SEEDS));
|
||||
plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new GreenThumbTimer(block, profile, type), 1);
|
||||
player.updateInventory(); // Needed until replacement available
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,6 +85,12 @@ public class Mining {
|
||||
Misc.dropItem(location, item);
|
||||
}
|
||||
break;
|
||||
|
||||
case EMERALD_ORE:
|
||||
if (configInstance.getEmeraldDoubleDropsEnabled()) {
|
||||
Misc.dropItem(location, item);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (ModChecks.isCustomMiningBlock(block)) {
|
||||
@@ -194,6 +200,13 @@ public class Mining {
|
||||
Misc.dropItem(location, item);
|
||||
}
|
||||
break;
|
||||
|
||||
case EMERALD_ORE:
|
||||
if (configInstance.getEmeraldDoubleDropsEnabled()) {
|
||||
item = new ItemStack(Material.EMERALD);
|
||||
Misc.dropItem(location, item);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (ModChecks.isCustomMiningBlock(block)) {
|
||||
@@ -279,6 +292,10 @@ public class Mining {
|
||||
case STONE:
|
||||
xp += Config.getInstance().getMiningXPStone();
|
||||
break;
|
||||
|
||||
case EMERALD_ORE:
|
||||
xp += Config.getInstance().getMiningXPEmeraldOre();
|
||||
break;
|
||||
|
||||
default:
|
||||
if (ModChecks.isCustomMiningBlock(block)) {
|
||||
@@ -367,6 +384,7 @@ public class Mining {
|
||||
case GOLD_ORE:
|
||||
case LAPIS_ORE:
|
||||
case REDSTONE_ORE:
|
||||
case EMERALD_ORE:
|
||||
if (tier < 3) {
|
||||
return;
|
||||
}
|
||||
@@ -385,7 +403,7 @@ public class Mining {
|
||||
case NETHERRACK:
|
||||
case SANDSTONE:
|
||||
case STONE:
|
||||
if (mcMMO.placeStore.isTrue(block)) {
|
||||
if (mcMMO.placeStore.isTrue(block) || Misc.blockBreakSimulate(block, player, true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -184,7 +184,7 @@ public class WoodCutting {
|
||||
break;
|
||||
|
||||
case JUNGLE:
|
||||
xp += Config.getInstance().getWoodcuttingXPJungle() / 4; //Nerf XP from Jungle Trees when using Tree Feller
|
||||
xp += Config.getInstance().getWoodcuttingXPJungle() / 2; //Nerf XP from Jungle Trees when using Tree Feller
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -261,6 +261,39 @@ public class WoodCutting {
|
||||
}
|
||||
}
|
||||
|
||||
byte data = currentBlock.getData();
|
||||
|
||||
if((data & 0x4) == 0x4)
|
||||
data ^= 0x4;
|
||||
|
||||
if((data & 0x8) == 0x8)
|
||||
data ^= 0x8;
|
||||
|
||||
if(TreeSpecies.getByData(data) == TreeSpecies.JUNGLE) {
|
||||
Block corner1 = currentBlock.getRelative(1, 0, 1);
|
||||
Block corner2 = currentBlock.getRelative(1, 0, -1);
|
||||
Block corner3 = currentBlock.getRelative(-1, 0, 1);
|
||||
Block corner4 = currentBlock.getRelative(-1, 0, -1);
|
||||
|
||||
if (!mcMMO.placeStore.isTrue(currentBlock)) {
|
||||
if (!isTooAggressive(currentBlock, corner1) && BlockChecks.treeFellerCompatible(corner1) && !toBeFelled.contains(corner1)) {
|
||||
processTreeFelling(corner1, toBeFelled);
|
||||
}
|
||||
|
||||
if (!isTooAggressive(currentBlock, corner2) && BlockChecks.treeFellerCompatible(corner2) && !toBeFelled.contains(corner2)) {
|
||||
processTreeFelling(corner2, toBeFelled);
|
||||
}
|
||||
|
||||
if (!isTooAggressive(currentBlock, corner3) && BlockChecks.treeFellerCompatible(corner3) && !toBeFelled.contains(corner3)) {
|
||||
processTreeFelling(corner3, toBeFelled);
|
||||
}
|
||||
|
||||
if (!isTooAggressive(currentBlock, corner4) && BlockChecks.treeFellerCompatible(corner4) && !toBeFelled.contains(corner4)) {
|
||||
processTreeFelling(corner4, toBeFelled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (BlockChecks.treeFellerCompatible(yPositive)) {
|
||||
if(!mcMMO.placeStore.isTrue(currentBlock) && !toBeFelled.contains(yPositive)) {
|
||||
processTreeFelling(yPositive, toBeFelled);
|
||||
@@ -298,6 +331,13 @@ public class WoodCutting {
|
||||
|
||||
int skillLevel = Users.getProfile(player).getSkillLevel(SkillType.WOODCUTTING);
|
||||
byte type = block.getData();
|
||||
|
||||
if((type & 0x4) == 0x4)
|
||||
type ^= 0x4;
|
||||
|
||||
if((type & 0x8) == 0x8)
|
||||
type ^= 0x8;
|
||||
|
||||
Material mat = Material.getMaterial(block.getTypeId());
|
||||
|
||||
int randomChance = 1000;
|
||||
@@ -384,7 +424,20 @@ public class WoodCutting {
|
||||
xp = ModChecks.getCustomBlock(block).getXpGain();
|
||||
}
|
||||
else {
|
||||
TreeSpecies species = TreeSpecies.getByData(block.getData());
|
||||
byte type = block.getData();
|
||||
|
||||
if((type & 0x4) == 0x4)
|
||||
type ^= 0x4;
|
||||
|
||||
if((type & 0x8) == 0x8)
|
||||
type ^= 0x8;
|
||||
|
||||
TreeSpecies species = TreeSpecies.getByData(type);
|
||||
|
||||
//Apparently species can be null in certain cases (custom server mods?)
|
||||
//https://github.com/mcMMO-Dev/mcMMO/issues/229
|
||||
if(species == null)
|
||||
return;
|
||||
|
||||
switch (species) {
|
||||
case GENERIC:
|
||||
|
||||
@@ -114,7 +114,7 @@ public class Repair {
|
||||
int enchantLevel = enchant.getValue();
|
||||
|
||||
if (configInstance.getArcaneForgingDowngradeEnabled() && enchantLevel > 1) {
|
||||
if (random.nextInt(100) <= getDowngradeChance(rank)) {
|
||||
if (random.nextInt(100) < getDowngradeChance(rank)) {
|
||||
is.addEnchantment(enchantment, --enchantLevel);
|
||||
downgraded = true;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,9 @@ public class CounterAttackEventHandler {
|
||||
}
|
||||
|
||||
protected boolean isHoldingSword() {
|
||||
if(player == null)
|
||||
return false;
|
||||
|
||||
return ItemChecks.isSword(player.getItemInHand());
|
||||
}
|
||||
|
||||
@@ -36,6 +39,9 @@ public class CounterAttackEventHandler {
|
||||
}
|
||||
|
||||
protected void sendAbilityMessages() {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
player.sendMessage(LocaleLoader.getString("Swords.Combat.Countered"));
|
||||
|
||||
if (attacker instanceof Player) {
|
||||
|
||||
@@ -19,6 +19,9 @@ public class SerratedStrikesEventHandler {
|
||||
}
|
||||
|
||||
protected void applyAbilityEffects() {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
Combat.applyAbilityAoE(player, target, damage / Swords.SERRATED_STRIKES_MODIFIER, SkillType.SWORDS);
|
||||
BleedTimer.add(target, Swords.SERRATED_STRIKES_BLEED_TICKS);
|
||||
}
|
||||
|
||||
@@ -28,6 +28,12 @@ public class SwordsManager {
|
||||
* @param defender The defending entity
|
||||
*/
|
||||
public void bleedCheck(LivingEntity defender) {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
if(permissionsInstance == null)
|
||||
return;
|
||||
|
||||
if (!permissionsInstance.swordsBleed(player)) {
|
||||
return;
|
||||
}
|
||||
@@ -49,6 +55,12 @@ public class SwordsManager {
|
||||
}
|
||||
|
||||
public void counterAttackChecks(LivingEntity attacker, int damage) {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
if(permissionsInstance == null)
|
||||
return;
|
||||
|
||||
if (!permissionsInstance.counterAttack(player)) {
|
||||
return;
|
||||
}
|
||||
@@ -72,6 +84,12 @@ public class SwordsManager {
|
||||
}
|
||||
|
||||
public void serratedStrikes(LivingEntity target, int damage) {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
if(permissionsInstance == null)
|
||||
return;
|
||||
|
||||
if (!permissionsInstance.serratedStrikes(player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,9 @@ public class BeastLoreEventHandler {
|
||||
}
|
||||
|
||||
protected void sendInspectMessage() {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
String message = LocaleLoader.getString("Combat.BeastLore") + " ";
|
||||
|
||||
if (beast.isTamed()) {
|
||||
|
||||
@@ -29,10 +29,16 @@ public class CallOfTheWildEventHandler {
|
||||
}
|
||||
|
||||
protected void sendInsufficientAmountMessage() {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
player.sendMessage(LocaleLoader.getString("Skills.NeedMore") + " " + ChatColor.GRAY + Misc.prettyItemString(inHand.getTypeId()));
|
||||
}
|
||||
|
||||
protected boolean nearbyEntityExists() {
|
||||
if(player == null)
|
||||
return false;
|
||||
|
||||
boolean entityExists = false;
|
||||
|
||||
for (Entity entity : player.getNearbyEntities(40, 40, 40)) {
|
||||
@@ -46,6 +52,9 @@ public class CallOfTheWildEventHandler {
|
||||
}
|
||||
|
||||
protected void sendFailureMessage() {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
if (type == EntityType.OCELOT) {
|
||||
player.sendMessage(LocaleLoader.getString("Taming.Summon.Fail.Ocelot"));
|
||||
}
|
||||
@@ -55,6 +64,9 @@ public class CallOfTheWildEventHandler {
|
||||
}
|
||||
|
||||
protected void spawnCreature() {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
LivingEntity entity = (LivingEntity) player.getWorld().spawnEntity(player.getLocation(), type);
|
||||
entity.setMetadata("mcmmoSummoned", new FixedMetadataValue(mcMMO.p, true));
|
||||
|
||||
@@ -69,6 +81,9 @@ public class CallOfTheWildEventHandler {
|
||||
}
|
||||
|
||||
protected void processResourceCost() {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
int newAmount = inHand.getAmount() - summonAmount;
|
||||
|
||||
if (newAmount == 0) {
|
||||
@@ -80,6 +95,9 @@ public class CallOfTheWildEventHandler {
|
||||
}
|
||||
|
||||
protected void sendSuccessMessage() {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
player.sendMessage(LocaleLoader.getString("Taming.Summon.Complete"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,9 @@ public class EnvironmentallyAwareEventHandler {
|
||||
}
|
||||
|
||||
protected void teleportWolf() {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
if (event.getDamage() > wolf.getHealth()) {
|
||||
return;
|
||||
}
|
||||
@@ -26,6 +29,9 @@ public class EnvironmentallyAwareEventHandler {
|
||||
}
|
||||
|
||||
protected void sendAbilityMessage() {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
player.sendMessage(LocaleLoader.getString("Taming.Listener.Wolf"));
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,12 @@ public class TamingManager {
|
||||
* @param damage The damage being absorbed by the wolf
|
||||
*/
|
||||
public void fastFoodService(Wolf wolf, int damage) {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
if(permissionsInstance == null)
|
||||
return;
|
||||
|
||||
if (!permissionsInstance.fastFoodService(player)) {
|
||||
return;
|
||||
}
|
||||
@@ -61,6 +67,12 @@ public class TamingManager {
|
||||
* @param event The event to modify
|
||||
*/
|
||||
public void sharpenedClaws(EntityDamageEvent event) {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
if(permissionsInstance == null)
|
||||
return;
|
||||
|
||||
if (!permissionsInstance.sharpenedClaws(player)) {
|
||||
return;
|
||||
}
|
||||
@@ -78,6 +90,12 @@ public class TamingManager {
|
||||
* @param event The event to modify
|
||||
*/
|
||||
public void gore(EntityDamageEvent event) {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
if(permissionsInstance == null)
|
||||
return;
|
||||
|
||||
if (!permissionsInstance.gore(player)) {
|
||||
return;
|
||||
}
|
||||
@@ -150,6 +168,12 @@ public class TamingManager {
|
||||
* @param livingEntity The entity to examine
|
||||
*/
|
||||
public void beastLore(LivingEntity livingEntity) {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
if(permissionsInstance == null)
|
||||
return;
|
||||
|
||||
if (!permissionsInstance.beastLore(player)) {
|
||||
return;
|
||||
}
|
||||
@@ -166,6 +190,12 @@ public class TamingManager {
|
||||
* @param summonAmount The amount of material needed to summon the entity
|
||||
*/
|
||||
private void callOfTheWild(EntityType type, int summonAmount) {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
if(permissionsInstance == null)
|
||||
return;
|
||||
|
||||
if (!permissionsInstance.callOfTheWild(player)) {
|
||||
return;
|
||||
}
|
||||
@@ -198,6 +228,12 @@ public class TamingManager {
|
||||
* @param cause The damage cause of the event
|
||||
*/
|
||||
private void environmentallyAware(EntityDamageEvent event, DamageCause cause) {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
if(permissionsInstance == null)
|
||||
return;
|
||||
|
||||
if (!permissionsInstance.environmentallyAware(player)) {
|
||||
return;
|
||||
}
|
||||
@@ -230,6 +266,12 @@ public class TamingManager {
|
||||
* @param cause The damage cause of the event
|
||||
*/
|
||||
private void thickFur(EntityDamageEvent event, DamageCause cause) {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
if(permissionsInstance == null)
|
||||
return;
|
||||
|
||||
if (!permissionsInstance.thickFur(player)) {
|
||||
return;
|
||||
}
|
||||
@@ -247,6 +289,12 @@ public class TamingManager {
|
||||
* @param event The event to modify
|
||||
*/
|
||||
private void shockProof(EntityDamageEvent event) {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
if(permissionsInstance == null)
|
||||
return;
|
||||
|
||||
if (!permissionsInstance.shockProof(player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,12 @@ public class UnarmedManager {
|
||||
* @param defender The defending player
|
||||
*/
|
||||
public void disarmCheck(Player defender) {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
if(permissionsInstance == null)
|
||||
return;
|
||||
|
||||
if (!permissionsInstance.disarm(player)) {
|
||||
return;
|
||||
}
|
||||
@@ -58,6 +64,12 @@ public class UnarmedManager {
|
||||
* @param event The event to modify
|
||||
*/
|
||||
public void deflectCheck(EntityDamageEvent event) {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
if(permissionsInstance == null)
|
||||
return;
|
||||
|
||||
if (!permissionsInstance.deflect(player)) {
|
||||
return;
|
||||
}
|
||||
@@ -82,6 +94,12 @@ public class UnarmedManager {
|
||||
* @param event The event to modify.
|
||||
*/
|
||||
public void bonusDamage(EntityDamageEvent event) {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
if(permissionsInstance == null)
|
||||
return;
|
||||
|
||||
if (!permissionsInstance.unarmedBonus(player)) {
|
||||
return;
|
||||
}
|
||||
@@ -99,6 +117,12 @@ public class UnarmedManager {
|
||||
* @return true if the defender was not disarmed, false otherwise
|
||||
*/
|
||||
private boolean hasIronGrip(Player defender) {
|
||||
if(defender == null)
|
||||
return false;
|
||||
|
||||
if(permissionsInstance == null)
|
||||
return false;
|
||||
|
||||
if (!permissionsInstance.ironGrip(defender)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -52,6 +52,10 @@ public class BlockChecks {
|
||||
case VINE:
|
||||
case WATER_LILY:
|
||||
case YELLOW_FLOWER:
|
||||
case COCOA:
|
||||
case EMERALD_ORE:
|
||||
case CARROT:
|
||||
case POTATO:
|
||||
return true;
|
||||
|
||||
default:
|
||||
@@ -84,6 +88,7 @@ public class BlockChecks {
|
||||
case CHEST:
|
||||
case DISPENSER:
|
||||
case ENCHANTMENT_TABLE:
|
||||
case ENDER_CHEST:
|
||||
case FENCE_GATE:
|
||||
case FURNACE:
|
||||
case IRON_DOOR_BLOCK:
|
||||
@@ -95,6 +100,8 @@ public class BlockChecks {
|
||||
case WALL_SIGN:
|
||||
case WOODEN_DOOR:
|
||||
case WORKBENCH:
|
||||
case BEACON:
|
||||
case ANVIL:
|
||||
return false;
|
||||
|
||||
default:
|
||||
@@ -122,6 +129,7 @@ public class BlockChecks {
|
||||
case IRON_ORE:
|
||||
case LAPIS_ORE:
|
||||
case REDSTONE_ORE:
|
||||
case EMERALD_ORE:
|
||||
return true;
|
||||
|
||||
default:
|
||||
@@ -146,6 +154,7 @@ public class BlockChecks {
|
||||
case DIRT:
|
||||
return true;
|
||||
case SMOOTH_BRICK:
|
||||
case COBBLE_WALL:
|
||||
if (block.getData() == 0) {
|
||||
return true;
|
||||
}
|
||||
@@ -174,6 +183,9 @@ public class BlockChecks {
|
||||
case VINE:
|
||||
case WATER_LILY:
|
||||
case YELLOW_FLOWER:
|
||||
case COCOA:
|
||||
case CARROT:
|
||||
case POTATO:
|
||||
return true;
|
||||
|
||||
case CROPS:
|
||||
@@ -216,6 +228,7 @@ public class BlockChecks {
|
||||
case REDSTONE_ORE:
|
||||
case SANDSTONE:
|
||||
case STONE:
|
||||
case EMERALD_ORE:
|
||||
return true;
|
||||
|
||||
default:
|
||||
|
||||
@@ -504,7 +504,15 @@ public class Combat {
|
||||
if (Users.getProfile(defender).getGodMode()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//It may seem a bit redundant but we need a check here to prevent bleed from being applied in applyAbilityAoE()
|
||||
EntityDamageEvent ede = new FakeEntityDamageByEntityEvent(player, entity, EntityDamageEvent.DamageCause.ENTITY_ATTACK, 1);
|
||||
mcMMO.p.getServer().getPluginManager().callEvent(ede);
|
||||
|
||||
if (ede.isCancelled()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (entity instanceof Tameable) {
|
||||
Tameable pet = (Tameable) entity;
|
||||
|
||||
|
||||
@@ -22,24 +22,28 @@ public class Database {
|
||||
private static String tablePrefix = configInstance.getMySQLTablePrefix();
|
||||
private static Connection connection = null;
|
||||
private static mcMMO plugin = null;
|
||||
private static long reconnectTimestamp = 0;
|
||||
|
||||
// Scale waiting time by this much per failed attempt
|
||||
private static final double SCALING_FACTOR = 5;
|
||||
|
||||
// Minimum wait in nanoseconds (default 500ms)
|
||||
private static final long MIN_WAIT = 500*100000L;
|
||||
|
||||
// Maximum time to wait between reconnects (default 5 minutes)
|
||||
private static final long MAX_WAIT = 5*60000000000L;
|
||||
|
||||
// How long to wait when checking if connection is valid (default 3 seconds)
|
||||
private static final int VALID_TIMEOUT = 3;
|
||||
|
||||
// When next to try connecting to Database in nanoseconds
|
||||
private static long nextReconnectTimestamp = 0L;
|
||||
|
||||
// How many connection attemtps have failed
|
||||
private static int reconnectAttempt = 0;
|
||||
|
||||
public Database(mcMMO instance) {
|
||||
plugin = instance;
|
||||
connect(); //Connect to MySQL
|
||||
|
||||
// Load the driver instance
|
||||
try {
|
||||
Class.forName("com.mysql.jdbc.Driver");
|
||||
DriverManager.getConnection(connectionString);
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
plugin.getLogger().warning(e.getLocalizedMessage());
|
||||
}
|
||||
catch (SQLException ex) {
|
||||
plugin.getLogger().warning(ex.getLocalizedMessage());
|
||||
printErrors(ex);
|
||||
}
|
||||
checkConnected(); //Connect to MySQL
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -49,6 +53,8 @@ public class Database {
|
||||
try {
|
||||
System.out.println("[mcMMO] Attempting connection to MySQL...");
|
||||
|
||||
// Force driver to load if not yet loaded
|
||||
Class.forName("com.mysql.jdbc.Driver");
|
||||
Properties connectionProperties = new Properties();
|
||||
connectionProperties.put("autoReconnect", "false");
|
||||
connectionProperties.put("maxReconnects", "0");
|
||||
@@ -57,10 +63,15 @@ public class Database {
|
||||
System.out.println("[mcMMO] Connection to MySQL was a success!");
|
||||
}
|
||||
catch (SQLException ex) {
|
||||
connection = null;
|
||||
System.out.println("[mcMMO] Connection to MySQL failed!");
|
||||
ex.printStackTrace();
|
||||
printErrors(ex);
|
||||
}
|
||||
} catch (ClassNotFoundException ex) {
|
||||
connection = null;
|
||||
System.out.println("[mcMMO] MySQL database driver not found!");
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -127,7 +138,7 @@ public class Database {
|
||||
*/
|
||||
public void checkDatabaseStructure(DatabaseUpdate update) {
|
||||
String sql = null;
|
||||
ResultSet resultSet;
|
||||
ResultSet resultSet = null;
|
||||
HashMap<Integer, ArrayList<String>> rows = new HashMap<Integer, ArrayList<String>>();
|
||||
|
||||
switch (update) {
|
||||
@@ -143,8 +154,9 @@ public class Database {
|
||||
break;
|
||||
}
|
||||
|
||||
PreparedStatement statement = null;
|
||||
try {
|
||||
PreparedStatement statement = connection.prepareStatement(sql);
|
||||
statement = connection.prepareStatement(sql);
|
||||
resultSet = statement.executeQuery();
|
||||
|
||||
while (resultSet.next()) {
|
||||
@@ -156,8 +168,6 @@ public class Database {
|
||||
|
||||
rows.put(resultSet.getRow(), column);
|
||||
}
|
||||
|
||||
statement.close();
|
||||
}
|
||||
catch (SQLException ex) {
|
||||
switch (update) {
|
||||
@@ -175,6 +185,21 @@ public class Database {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} finally {
|
||||
if (resultSet != null) {
|
||||
try {
|
||||
resultSet.close();
|
||||
} catch (SQLException e) {
|
||||
// Ignore the error, we're leaving
|
||||
}
|
||||
}
|
||||
if (statement != null) {
|
||||
try {
|
||||
statement.close();
|
||||
} catch (SQLException e) {
|
||||
// Ignore the error, we're leaving
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,21 +210,27 @@ public class Database {
|
||||
* @return true if the query was successfully written, false otherwise.
|
||||
*/
|
||||
public boolean write(String sql) {
|
||||
if (isConnected()) {
|
||||
if (checkConnected()) {
|
||||
PreparedStatement statement = null;
|
||||
try {
|
||||
PreparedStatement statement = connection.prepareStatement(sql);
|
||||
statement = connection.prepareStatement(sql);
|
||||
statement.executeUpdate();
|
||||
statement.close();
|
||||
return true;
|
||||
}
|
||||
catch (SQLException ex) {
|
||||
printErrors(ex);
|
||||
return false;
|
||||
} finally {
|
||||
if (statement != null) {
|
||||
try {
|
||||
statement.close();
|
||||
} catch (SQLException e) {
|
||||
printErrors(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
attemptReconnect();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -214,7 +245,7 @@ public class Database {
|
||||
ResultSet resultSet;
|
||||
int result = 0;
|
||||
|
||||
if (isConnected()) {
|
||||
if (checkConnected()) {
|
||||
try {
|
||||
PreparedStatement statement = connection.prepareStatement(sql);
|
||||
resultSet = statement.executeQuery();
|
||||
@@ -232,44 +263,100 @@ public class Database {
|
||||
printErrors(ex);
|
||||
}
|
||||
}
|
||||
else {
|
||||
attemptReconnect();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get connection status
|
||||
* Check connection status and re-establish if dead or stale.
|
||||
*
|
||||
* If the very first immediate attempt fails, further attempts
|
||||
* will be made in progressively larger intervals up to MAX_WAIT
|
||||
* intervals.
|
||||
*
|
||||
* This allows for MySQL to time out idle connections as needed by
|
||||
* server operator, without affecting McMMO, while still providing
|
||||
* protection against a database outage taking down Bukkit's tick
|
||||
* processing loop due to attemping a database connection each
|
||||
* time McMMO needs the database.
|
||||
*
|
||||
* @return the boolean value for whether or not we are connected
|
||||
*/
|
||||
public static boolean isConnected() {
|
||||
if (connection == null) {
|
||||
return false;
|
||||
}
|
||||
public static boolean checkConnected() {
|
||||
boolean isClosed = true;
|
||||
boolean isValid = false;
|
||||
boolean exists = (connection != null);
|
||||
|
||||
try {
|
||||
return connection.isValid(3);
|
||||
}
|
||||
catch (SQLException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Initialized as needed later
|
||||
long timestamp=0;
|
||||
|
||||
// If we're waiting for server to recover then leave early
|
||||
if (nextReconnectTimestamp > 0 && nextReconnectTimestamp > System.nanoTime()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (exists) {
|
||||
try {
|
||||
isClosed = connection.isClosed();
|
||||
} catch (SQLException e) {
|
||||
isClosed = true;
|
||||
e.printStackTrace();
|
||||
printErrors(e);
|
||||
}
|
||||
|
||||
if (!isClosed) {
|
||||
try {
|
||||
isValid = connection.isValid(VALID_TIMEOUT);
|
||||
} catch (SQLException e) {
|
||||
// Don't print stack trace because it's valid to lose idle connections
|
||||
// to the server and have to restart them.
|
||||
isValid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedules a Sync Delayed Task with the Bukkit Scheduler to attempt reconnection after a minute has elapsed
|
||||
* This will check for a connection being present or not to prevent unneeded reconnection attempts
|
||||
*/
|
||||
public static void attemptReconnect() {
|
||||
final int RECONNECT_WAIT_TICKS = 60000;
|
||||
final int RECONNECT_DELAY_TICKS = 1200;
|
||||
// Leave if all ok
|
||||
if (exists && !isClosed && isValid) {
|
||||
// Housekeeping
|
||||
nextReconnectTimestamp = 0;
|
||||
reconnectAttempt = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Cleanup after ourselves for GC and MySQL's sake
|
||||
if (exists && !isClosed) {
|
||||
try {
|
||||
connection.close();
|
||||
} catch (SQLException ex) {
|
||||
// This is a housekeeping exercise, ignore errors
|
||||
}
|
||||
}
|
||||
|
||||
if (reconnectTimestamp + RECONNECT_WAIT_TICKS < System.currentTimeMillis()) {
|
||||
System.out.println("[mcMMO] Connection to MySQL was lost! Attempting to reconnect in 60 seconds..."); //Only reconnect if another attempt hasn't been made recently
|
||||
reconnectTimestamp = System.currentTimeMillis();
|
||||
plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new SQLReconnect(plugin), RECONNECT_DELAY_TICKS);
|
||||
}
|
||||
// Try to connect again
|
||||
connect();
|
||||
|
||||
// Leave if connection is good
|
||||
try {
|
||||
if (connection != null && !connection.isClosed()) {
|
||||
// Schedule a database save if we really had an outage
|
||||
if (reconnectAttempt > 1) {
|
||||
plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new SQLReconnect(plugin), 5);
|
||||
}
|
||||
nextReconnectTimestamp = 0;
|
||||
reconnectAttempt = 0;
|
||||
return true;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
// Failed to check isClosed, so presume connection is bad and attempt later
|
||||
e.printStackTrace();
|
||||
printErrors(e);
|
||||
}
|
||||
|
||||
reconnectAttempt++;
|
||||
|
||||
nextReconnectTimestamp = (long)(System.nanoTime() + Math.min(MAX_WAIT, (reconnectAttempt*SCALING_FACTOR*MIN_WAIT)));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -282,7 +369,7 @@ public class Database {
|
||||
ResultSet resultSet;
|
||||
HashMap<Integer, ArrayList<String>> rows = new HashMap<Integer, ArrayList<String>>();
|
||||
|
||||
if (isConnected()) {
|
||||
if (checkConnected()) {
|
||||
try {
|
||||
PreparedStatement statement = connection.prepareStatement(sql);
|
||||
resultSet = statement.executeQuery();
|
||||
@@ -303,9 +390,6 @@ public class Database {
|
||||
printErrors(ex);
|
||||
}
|
||||
}
|
||||
else {
|
||||
attemptReconnect();
|
||||
}
|
||||
|
||||
return rows;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.gmail.nossr50.util;
|
||||
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.Material;
|
||||
|
||||
import com.gmail.nossr50.mcMMO;
|
||||
import com.gmail.nossr50.api.SpoutToolsAPI;
|
||||
@@ -463,4 +464,14 @@ public class ItemChecks {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if an item is enchantable.
|
||||
*
|
||||
* @param is Item to check
|
||||
* @return true if the item is enchantable, false otherwise
|
||||
*/
|
||||
public static boolean isEnchantable(ItemStack is) {
|
||||
return isArmor(is) || isSword(is) || isAxe(is) || isShovel(is) || isPickaxe(is) || (is.getType() == Material.BOW);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,6 +264,22 @@ public class Permissions {
|
||||
return player.hasPermission("mcmmo.ability.herbalism.greenthumbblocks");
|
||||
}
|
||||
|
||||
public boolean greenThumbCarrots(Player player) {
|
||||
return player.hasPermission("mcmmo.ability.herbalism.greenthumbcarrots");
|
||||
}
|
||||
|
||||
public boolean greenThumbCocoa(Player player) {
|
||||
return player.hasPermission("mcmmo.ability.herbalism.greenthumbcocoa");
|
||||
}
|
||||
|
||||
public boolean greenThumbNetherwart(Player player) {
|
||||
return player.hasPermission("mcmmo.ability.herbalism.greenthumbnetherwart");
|
||||
}
|
||||
|
||||
public boolean greenThumbPotatoes(Player player) {
|
||||
return player.hasPermission("mcmmo.ability.herbalism.greenthumbpotatoes");
|
||||
}
|
||||
|
||||
public boolean greenThumbWheat(Player player) {
|
||||
return player.hasPermission("mcmmo.ability.herbalism.greenthumbwheat");
|
||||
}
|
||||
|
||||
@@ -80,6 +80,9 @@ public class Skills {
|
||||
* @param ability The ability to watch cooldowns for
|
||||
*/
|
||||
public static void watchCooldown(Player player, PlayerProfile profile, AbilityType ability) {
|
||||
if(player == null || profile == null || ability == null)
|
||||
return;
|
||||
|
||||
if (!profile.getAbilityInformed(ability) && cooldownOver(profile.getSkillDATS(ability) * TIME_CONVERSION_FACTOR, ability.getCooldown(), player)) {
|
||||
profile.setAbilityInformed(ability, true);
|
||||
player.sendMessage(ability.getAbilityRefresh());
|
||||
@@ -396,6 +399,9 @@ public class Skills {
|
||||
*/
|
||||
public static void abilityCheck(Player player, SkillType type) {
|
||||
PlayerProfile profile = Users.getProfile(player);
|
||||
if (profile == null) {
|
||||
return;
|
||||
}
|
||||
ToolType tool = type.getTool();
|
||||
|
||||
if (!profile.getToolPreparationMode(tool)) {
|
||||
@@ -504,7 +510,13 @@ public class Skills {
|
||||
* @param xp the amount of XP to gain
|
||||
*/
|
||||
public static void xpProcessing(Player player, PlayerProfile profile, SkillType type, int xp) {
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
if (type.getPermissions(player)) {
|
||||
if(Users.getPlayer(player) == null)
|
||||
return;
|
||||
|
||||
Users.getPlayer(player).addXP(type, xp);
|
||||
xpCheckSkill(type, player, profile);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ import com.gmail.nossr50.mcMMO;
|
||||
import com.gmail.nossr50.runnables.ChunkletUnloader;
|
||||
|
||||
public class HashChunkletManager implements ChunkletManager {
|
||||
private HashMap<String, ChunkletStore> store = new HashMap<String, ChunkletStore>();
|
||||
public HashMap<String, ChunkletStore> store = new HashMap<String, ChunkletStore>();
|
||||
|
||||
@Override
|
||||
public void loadChunklet(int cx, int cy, int cz, World world) {
|
||||
@@ -107,6 +107,8 @@ public class HashChunkletManager implements ChunkletManager {
|
||||
public void saveWorld(World world) {
|
||||
String worldName = world.getName();
|
||||
File dataDir = new File(world.getWorldFolder(), "mcmmo_data");
|
||||
if(!dataDir.exists())
|
||||
dataDir.mkdirs();
|
||||
|
||||
for(String key : store.keySet()) {
|
||||
String[] info = key.split(",");
|
||||
@@ -280,6 +282,8 @@ public class HashChunkletManager implements ChunkletManager {
|
||||
ObjectOutputStream objOut = null;
|
||||
|
||||
try {
|
||||
if(!location.exists())
|
||||
location.createNewFile();
|
||||
fileOut = new FileOutputStream(location);
|
||||
objOut = new ObjectOutputStream(fileOut);
|
||||
objOut.writeObject(cStore);
|
||||
|
||||
@@ -4,7 +4,7 @@ public class PrimitiveChunkletStore implements ChunkletStore {
|
||||
private static final long serialVersionUID = -3453078050608607478L;
|
||||
|
||||
/** X, Z, Y */
|
||||
private boolean[][][] store = new boolean[16][16][64];
|
||||
public boolean[][][] store = new boolean[16][16][64];
|
||||
|
||||
@Override
|
||||
public boolean isTrue(int x, int y, int z) {
|
||||
|
||||
@@ -9,7 +9,7 @@ public class PrimitiveExChunkletStore implements ChunkletStore, Externalizable {
|
||||
private static final long serialVersionUID = 8603603827094383873L;
|
||||
|
||||
/** X, Z, Y */
|
||||
private boolean[][][] store = new boolean[16][16][64];
|
||||
public boolean[][][] store = new boolean[16][16][64];
|
||||
|
||||
@Override
|
||||
public boolean isTrue(int x, int y, int z) {
|
||||
|
||||
168
src/main/java/com/gmail/nossr50/util/blockmeta/chunkmeta/ChunkManager.java
Executable file
168
src/main/java/com/gmail/nossr50/util/blockmeta/chunkmeta/ChunkManager.java
Executable file
@@ -0,0 +1,168 @@
|
||||
package com.gmail.nossr50.util.blockmeta.chunkmeta;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
|
||||
public interface ChunkManager {
|
||||
public void closeAll();
|
||||
public ChunkStore readChunkStore(World world, int x, int z) throws IOException;
|
||||
public void writeChunkStore(World world, int x, int z, ChunkStore data);
|
||||
public void closeChunkStore(World world, int x, int z);
|
||||
|
||||
/**
|
||||
* Loads a specific chunklet
|
||||
*
|
||||
* @param cx Chunklet X coordinate that needs to be loaded
|
||||
* @param cy Chunklet Y coordinate that needs to be loaded
|
||||
* @param cz Chunklet Z coordinate that needs to be loaded
|
||||
* @param world World that the chunklet needs to be loaded in
|
||||
*/
|
||||
public void loadChunklet(int cx, int cy, int cz, World world);
|
||||
|
||||
/**
|
||||
* Unload a specific chunklet
|
||||
*
|
||||
* @param cx Chunklet X coordinate that needs to be unloaded
|
||||
* @param cy Chunklet Y coordinate that needs to be unloaded
|
||||
* @param cz Chunklet Z coordinate that needs to be unloaded
|
||||
* @param world World that the chunklet needs to be unloaded from
|
||||
*/
|
||||
public void unloadChunklet(int cx, int cy, int cz, World world);
|
||||
|
||||
/**
|
||||
* Load a given Chunk's Chunklet data
|
||||
*
|
||||
* @param cx Chunk X coordinate that is to be loaded
|
||||
* @param cz Chunk Z coordinate that is to be loaded
|
||||
* @param world World that the Chunk is in
|
||||
*/
|
||||
public void loadChunk(int cx, int cz, World world);
|
||||
|
||||
/**
|
||||
* Unload a given Chunk's Chunklet data
|
||||
*
|
||||
* @param cx Chunk X coordinate that is to be unloaded
|
||||
* @param cz Chunk Z coordinate that is to be unloaded
|
||||
* @param world World that the Chunk is in
|
||||
*/
|
||||
public void unloadChunk(int cx, int cz, 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
|
||||
*/
|
||||
public void saveChunk(int cx, int cz, World world);
|
||||
|
||||
public boolean isChunkLoaded(int cx, int cz, World world);
|
||||
/**
|
||||
* Informs the ChunkletManager a chunk is loaded
|
||||
*
|
||||
* @param cx Chunk X coordinate that is loaded
|
||||
* @param cz Chunk Z coordinate that is loaded
|
||||
* @param world World that the chunk was loaded in
|
||||
*/
|
||||
public void chunkLoaded(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
|
||||
*/
|
||||
public void chunkUnloaded(int cx, int cz, World world);
|
||||
|
||||
/**
|
||||
* Save all ChunkletStores related to the given world
|
||||
*
|
||||
* @param world World to save
|
||||
*/
|
||||
public void saveWorld(World world);
|
||||
|
||||
/**
|
||||
* Unload all ChunkletStores from memory related to the given world after saving them
|
||||
*
|
||||
* @param world World to unload
|
||||
*/
|
||||
public void unloadWorld(World world);
|
||||
|
||||
/**
|
||||
* Load all ChunkletStores from all loaded chunks from this world into memory
|
||||
*
|
||||
* @param world World to load
|
||||
*/
|
||||
public void loadWorld(World world);
|
||||
|
||||
/**
|
||||
* Save all ChunkletStores
|
||||
*/
|
||||
public void saveAll();
|
||||
|
||||
/**
|
||||
* Unload all ChunkletStores after saving them
|
||||
*/
|
||||
public void unloadAll();
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public 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
|
||||
*/
|
||||
public boolean isTrue(Block block);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public 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
|
||||
*/
|
||||
public void setTrue(Block block);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public 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
|
||||
*/
|
||||
public void setFalse(Block block);
|
||||
|
||||
/**
|
||||
* Delete any ChunkletStores that are empty
|
||||
*/
|
||||
public void cleanUp();
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.gmail.nossr50.util.blockmeta.chunkmeta;
|
||||
|
||||
import com.gmail.nossr50.config.HiddenConfig;
|
||||
|
||||
public class ChunkManagerFactory {
|
||||
public static ChunkManager getChunkManager() {
|
||||
HiddenConfig hConfig = HiddenConfig.getInstance();
|
||||
|
||||
if(hConfig.getChunkletsEnabled()) {
|
||||
return new HashChunkManager();
|
||||
} else {
|
||||
return new NullChunkManager();
|
||||
}
|
||||
}
|
||||
}
|
||||
74
src/main/java/com/gmail/nossr50/util/blockmeta/chunkmeta/ChunkStore.java
Executable file
74
src/main/java/com/gmail/nossr50/util/blockmeta/chunkmeta/ChunkStore.java
Executable file
@@ -0,0 +1,74 @@
|
||||
package com.gmail.nossr50.util.blockmeta.chunkmeta;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.gmail.nossr50.util.blockmeta.ChunkletStore;
|
||||
|
||||
/**
|
||||
* A ChunkStore should be responsible for a 16x16xWorldHeight area of data
|
||||
*/
|
||||
public interface ChunkStore extends Serializable {
|
||||
/**
|
||||
* Checks the chunk's save state
|
||||
*
|
||||
* @return true if the has been modified since it was last saved
|
||||
*/
|
||||
public boolean isDirty();
|
||||
/**
|
||||
* Checks the chunk's save state
|
||||
*
|
||||
* @param dirty the save state of the current chunk
|
||||
*/
|
||||
public void setDirty(boolean dirty);
|
||||
/**
|
||||
* Checks the chunk's x coordinate
|
||||
*
|
||||
* @return the chunk's x coordinate.
|
||||
*/
|
||||
public int getChunkX();
|
||||
/**
|
||||
* Checks the chunk's z coordinate
|
||||
*
|
||||
* @return the chunk's z coordinate.
|
||||
*/
|
||||
public int getChunkZ();
|
||||
/**
|
||||
* Checks the value at the given coordinates
|
||||
*
|
||||
* @param x x coordinate in current chunklet
|
||||
* @param y y coordinate in current chunklet
|
||||
* @param z z coordinate in current chunklet
|
||||
* @return true if the value is true at the given coordinates, false if otherwise
|
||||
*/
|
||||
public boolean isTrue(int x, int y, int z);
|
||||
|
||||
/**
|
||||
* Set the value to true at the given coordinates
|
||||
*
|
||||
* @param x x coordinate in current chunklet
|
||||
* @param y y coordinate in current chunklet
|
||||
* @param z z coordinate in current chunklet
|
||||
*/
|
||||
public void setTrue(int x, int y, int z);
|
||||
|
||||
/**
|
||||
* Set the value to false at the given coordinates
|
||||
*
|
||||
* @param x x coordinate in current chunklet
|
||||
* @param y y coordinate in current chunklet
|
||||
* @param z z coordinate in current chunklet
|
||||
*/
|
||||
public void setFalse(int x, int y, int z);
|
||||
|
||||
/**
|
||||
* @return true if all values in the chunklet are false, false if otherwise
|
||||
*/
|
||||
public boolean isEmpty();
|
||||
|
||||
/**
|
||||
* Set all values in this ChunkletStore to the values from another provided ChunkletStore
|
||||
*
|
||||
* @param otherStore Another ChunkletStore that this one should copy all data from
|
||||
*/
|
||||
public void copyFrom(ChunkletStore otherStore);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.gmail.nossr50.util.blockmeta.chunkmeta;
|
||||
|
||||
import org.bukkit.World;
|
||||
|
||||
public class ChunkStoreFactory {
|
||||
protected static ChunkStore getChunkStore(World world, int x, int z) {
|
||||
// TODO: Add in loading from config what type of store we want.
|
||||
return new PrimitiveChunkStore(world, x, z);
|
||||
}
|
||||
}
|
||||
424
src/main/java/com/gmail/nossr50/util/blockmeta/chunkmeta/HashChunkManager.java
Executable file
424
src/main/java/com/gmail/nossr50/util/blockmeta/chunkmeta/HashChunkManager.java
Executable file
@@ -0,0 +1,424 @@
|
||||
package com.gmail.nossr50.util.blockmeta.chunkmeta;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.Boolean;
|
||||
import java.lang.Integer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
|
||||
import com.gmail.nossr50.mcMMO;
|
||||
import com.gmail.nossr50.runnables.ChunkletUnloader;
|
||||
import com.gmail.nossr50.runnables.blockstoreconversion.BlockStoreConversionZDirectory;
|
||||
import com.gmail.nossr50.util.blockmeta.ChunkletStore;
|
||||
import com.gmail.nossr50.util.blockmeta.PrimitiveChunkletStore;
|
||||
import com.gmail.nossr50.util.blockmeta.PrimitiveExChunkletStore;
|
||||
import com.gmail.nossr50.util.blockmeta.HashChunkletManager;
|
||||
|
||||
import org.getspout.spoutapi.chunkstore.mcMMOSimpleRegionFile;
|
||||
|
||||
public class HashChunkManager implements ChunkManager {
|
||||
private HashMap<UUID, HashMap<Long, mcMMOSimpleRegionFile>> regionFiles = new HashMap<UUID, HashMap<Long, mcMMOSimpleRegionFile>>();
|
||||
public HashMap<String, ChunkStore> store = new HashMap<String, ChunkStore>();
|
||||
public ArrayList<BlockStoreConversionZDirectory> converters = new ArrayList<BlockStoreConversionZDirectory>();
|
||||
private HashMap<UUID, Boolean> oldData = new HashMap<UUID, Boolean>();
|
||||
|
||||
@Override
|
||||
public synchronized void closeAll() {
|
||||
for (UUID uid : regionFiles.keySet()) {
|
||||
HashMap<Long, mcMMOSimpleRegionFile> worldRegions = regionFiles.get(uid);
|
||||
Iterator<mcMMOSimpleRegionFile> itr = worldRegions.values().iterator();
|
||||
while (itr.hasNext()) {
|
||||
mcMMOSimpleRegionFile rf = itr.next();
|
||||
if (rf != null) {
|
||||
rf.close();
|
||||
itr.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
regionFiles.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized ChunkStore readChunkStore(World world, int x, int z) throws IOException {
|
||||
mcMMOSimpleRegionFile rf = getSimpleRegionFile(world, x, z);
|
||||
InputStream in = rf.getInputStream(x, z);
|
||||
if (in == null) {
|
||||
return null;
|
||||
}
|
||||
ObjectInputStream objectStream = new ObjectInputStream(in);
|
||||
try {
|
||||
Object o = objectStream.readObject();
|
||||
if (o instanceof ChunkStore) {
|
||||
return (ChunkStore) o;
|
||||
} else {
|
||||
throw new RuntimeException("Wrong class type read for chunk meta data for " + x + ", " + z);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// Assume the format changed
|
||||
return null;
|
||||
//throw new RuntimeException("Unable to process chunk meta data for " + x + ", " + z, e);
|
||||
} catch (ClassNotFoundException e) {
|
||||
// Assume the format changed
|
||||
//System.out.println("[SpoutPlugin] is Unable to find serialized class for " + x + ", " + z + ", " + e.getMessage());
|
||||
return null;
|
||||
//throw new RuntimeException("Unable to find serialized class for " + x + ", " + z, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void writeChunkStore(World world, int x, int z, ChunkStore data) {
|
||||
if (!data.isDirty()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
mcMMOSimpleRegionFile rf = getSimpleRegionFile(world, x, z);
|
||||
ObjectOutputStream objectStream = new ObjectOutputStream(rf.getOutputStream(x, z));
|
||||
objectStream.writeObject(data);
|
||||
objectStream.flush();
|
||||
objectStream.close();
|
||||
data.setDirty(false);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Unable to write chunk meta data for " + x + ", " + z, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void closeChunkStore(World world, int x, int z) {
|
||||
mcMMOSimpleRegionFile rf = getSimpleRegionFile(world, x, z);
|
||||
if (rf != null) {
|
||||
rf.close();
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized mcMMOSimpleRegionFile getSimpleRegionFile(World world, int x, int z) {
|
||||
File directory = new File(world.getWorldFolder(), "mcmmo_regions");
|
||||
|
||||
directory.mkdirs();
|
||||
|
||||
UUID key = world.getUID();
|
||||
|
||||
HashMap<Long, mcMMOSimpleRegionFile> worldRegions = regionFiles.get(key);
|
||||
|
||||
if (worldRegions == null) {
|
||||
worldRegions = new HashMap<Long, mcMMOSimpleRegionFile>();
|
||||
regionFiles.put(key, worldRegions);
|
||||
}
|
||||
|
||||
int rx = x >> 5;
|
||||
int rz = z >> 5;
|
||||
|
||||
long key2 = (((long) rx) << 32) | (((long) rz) & 0xFFFFFFFFL);
|
||||
|
||||
mcMMOSimpleRegionFile regionFile = worldRegions.get(key2);
|
||||
|
||||
if (regionFile == null) {
|
||||
File file = new File(directory, "mcmmo_" + rx + "_" + rz + "_.mcm");
|
||||
regionFile = new mcMMOSimpleRegionFile(file, rx, rz);
|
||||
worldRegions.put(key2, regionFile);
|
||||
}
|
||||
|
||||
return regionFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void loadChunklet(int cx, int cy, int cz, World world) {
|
||||
loadChunk(cx, cz, world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void unloadChunklet(int cx, int cy, int cz, World world) {
|
||||
unloadChunk(cx, cz, world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void loadChunk(int cx, int cz, World world) {
|
||||
if(world == null)
|
||||
return;
|
||||
|
||||
if(store.containsKey(world.getName() + "," + cx + "," + cz))
|
||||
return;
|
||||
|
||||
ChunkStore in = null;
|
||||
|
||||
UUID key = world.getUID();
|
||||
if(!this.oldData.containsKey(key))
|
||||
this.oldData.put(key, (new File(world.getWorldFolder(), "mcmmo_data")).exists());
|
||||
|
||||
if(this.oldData.containsKey(key) && oldData.get(key))
|
||||
convertChunk(new File(world.getWorldFolder(), "mcmmo_data"), cx, cz, world, true);
|
||||
|
||||
try {
|
||||
in = readChunkStore(world, cx, cz);
|
||||
}
|
||||
catch(Exception e) {}
|
||||
|
||||
if(in != null) {
|
||||
store.put(world.getName() + "," + cx + "," + cz, in);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void unloadChunk(int cx, int cz, World world) {
|
||||
saveChunk(cx, cz, world);
|
||||
|
||||
if(store.containsKey(world.getName() + "," + cx + "," + cz)) {
|
||||
store.remove(world.getName() + "," + cx + "," + cz);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void saveChunk(int cx, int cz, World world) {
|
||||
if(world == null)
|
||||
return;
|
||||
|
||||
if(store.containsKey(world.getName() + "," + cx + "," + cz)) {
|
||||
ChunkStore out = store.get(world.getName() + "," + cx + "," + cz);
|
||||
|
||||
if(!out.isDirty())
|
||||
return;
|
||||
|
||||
writeChunkStore(world, cx, cz, out);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isChunkLoaded(int cx, int cz, World world) {
|
||||
if(world == null)
|
||||
return false;
|
||||
|
||||
return store.containsKey(world.getName() + "," + cx + "," + cz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void chunkLoaded(int cx, int cz, World world) {}
|
||||
|
||||
@Override
|
||||
public synchronized void chunkUnloaded(int cx, int cz, World world) {
|
||||
if(world == null)
|
||||
return;
|
||||
|
||||
ChunkletUnloader.addToList(cx, cx, world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void saveWorld(World world) {
|
||||
if(world == null)
|
||||
return;
|
||||
|
||||
closeAll();
|
||||
String worldName = world.getName();
|
||||
|
||||
for(String key : store.keySet()) {
|
||||
String[] info = key.split(",");
|
||||
if(worldName.equals(info[0])) {
|
||||
int cx = 0;
|
||||
int cz = 0;
|
||||
|
||||
try {
|
||||
cx = Integer.parseInt(info[1]);
|
||||
cz = Integer.parseInt(info[2]);
|
||||
}
|
||||
catch(Exception e) {
|
||||
return;
|
||||
}
|
||||
saveChunk(cx, cz, world);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void unloadWorld(World world) {
|
||||
if(world == null)
|
||||
return;
|
||||
|
||||
closeAll();
|
||||
String worldName = world.getName();
|
||||
|
||||
for(String key : store.keySet()) {
|
||||
String[] info = key.split(",");
|
||||
if(worldName.equals(info[0])) {
|
||||
int cx = 0;
|
||||
int cz = 0;
|
||||
|
||||
try {
|
||||
cx = Integer.parseInt(info[1]);
|
||||
cz = Integer.parseInt(info[2]);
|
||||
}
|
||||
catch(Exception e) {
|
||||
return;
|
||||
}
|
||||
unloadChunk(cx, cz, world);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void loadWorld(World world) {}
|
||||
|
||||
@Override
|
||||
public synchronized void saveAll() {
|
||||
closeAll();
|
||||
|
||||
for(World world : Bukkit.getWorlds()) {
|
||||
saveWorld(world);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void unloadAll() {
|
||||
closeAll();
|
||||
|
||||
for(World world : Bukkit.getWorlds()) {
|
||||
unloadWorld(world);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isTrue(int x, int y, int z, World world) {
|
||||
if(world == null)
|
||||
return false;
|
||||
|
||||
int cx = x / 16;
|
||||
int cz = z / 16;
|
||||
String key = world.getName() + "," + cx + "," + cz;
|
||||
|
||||
if (!store.containsKey(key)) {
|
||||
loadChunk(cx, cz, world);
|
||||
}
|
||||
|
||||
if (!store.containsKey(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ChunkStore check = store.get(key);
|
||||
int ix = Math.abs(x) % 16;
|
||||
int iz = Math.abs(z) % 16;
|
||||
|
||||
return check.isTrue(ix, y, iz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isTrue(Block block) {
|
||||
if(block == null)
|
||||
return false;
|
||||
|
||||
return isTrue(block.getX(), block.getY(), block.getZ(), block.getWorld());
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void setTrue(int x, int y, int z, World world) {
|
||||
if(world == null)
|
||||
return;
|
||||
|
||||
int cx = x / 16;
|
||||
int cz = z / 16;
|
||||
|
||||
int ix = Math.abs(x) % 16;
|
||||
int iz = Math.abs(z) % 16;
|
||||
|
||||
String key = world.getName() + "," + cx + "," + cz;
|
||||
|
||||
if (!store.containsKey(key)) {
|
||||
loadChunk(cx, cz, world);
|
||||
}
|
||||
|
||||
ChunkStore cStore = store.get(key);
|
||||
|
||||
if (cStore == null) {
|
||||
cStore = ChunkStoreFactory.getChunkStore(world, cx, cz);
|
||||
store.put(key, cStore);
|
||||
}
|
||||
|
||||
cStore.setTrue(ix, y, iz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void setTrue(Block block) {
|
||||
if(block == null)
|
||||
return;
|
||||
|
||||
setTrue(block.getX(), block.getY(), block.getZ(), block.getWorld());
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void setFalse(int x, int y, int z, World world) {
|
||||
if(world == null)
|
||||
return;
|
||||
|
||||
int cx = x / 16;
|
||||
int cz = z / 16;
|
||||
|
||||
int ix = Math.abs(x) % 16;
|
||||
int iz = Math.abs(z) % 16;
|
||||
|
||||
String key = world.getName() + "," + cx + "," + cz;
|
||||
|
||||
if (!store.containsKey(key)) {
|
||||
loadChunk(cx, cz, world);
|
||||
}
|
||||
|
||||
ChunkStore cStore = store.get(key);
|
||||
|
||||
if (cStore == null) {
|
||||
return; //No need to make a store for something we will be setting to false
|
||||
}
|
||||
|
||||
cStore.setFalse(ix, y, iz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void setFalse(Block block) {
|
||||
if(block == null)
|
||||
return;
|
||||
|
||||
setFalse(block.getX(), block.getY(), block.getZ(), block.getWorld());
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void cleanUp() {}
|
||||
|
||||
public synchronized void convertChunk(File dataDir, int cx, int cz, World world) {
|
||||
convertChunk(dataDir, cx, cz, world, false);
|
||||
}
|
||||
|
||||
public synchronized void convertChunk(File dataDir, int cx, int cz, World world, boolean actually) {
|
||||
if(!actually)
|
||||
return;
|
||||
if(!dataDir.exists()) return;
|
||||
File cxDir = new File(dataDir, "" + cx);
|
||||
if(!cxDir.exists()) return;
|
||||
File czDir = new File(cxDir, "" + cz);
|
||||
if(!czDir.exists()) return;
|
||||
|
||||
boolean conversionSet = false;
|
||||
|
||||
for(BlockStoreConversionZDirectory converter : this.converters) {
|
||||
if(converter == null)
|
||||
continue;
|
||||
|
||||
if(converter.taskID >= 0)
|
||||
continue;
|
||||
|
||||
converter.start(world, cxDir, czDir);
|
||||
conversionSet = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if(!conversionSet) {
|
||||
BlockStoreConversionZDirectory converter = new BlockStoreConversionZDirectory();
|
||||
converter.start(world, cxDir, czDir);
|
||||
converters.add(converter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package com.gmail.nossr50.util.blockmeta.chunkmeta;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
|
||||
public class NullChunkManager implements ChunkManager {
|
||||
|
||||
@Override
|
||||
public void closeAll() {}
|
||||
|
||||
@Override
|
||||
public ChunkStore readChunkStore(World world, int x, int z) throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeChunkStore(World world, int x, int z, ChunkStore data) {}
|
||||
|
||||
@Override
|
||||
public void closeChunkStore(World world, int x, int z) {}
|
||||
|
||||
@Override
|
||||
public void loadChunklet(int cx, int cy, int cz, World world) {}
|
||||
|
||||
@Override
|
||||
public void unloadChunklet(int cx, int cy, int cz, World world) {}
|
||||
|
||||
@Override
|
||||
public void loadChunk(int cx, int cz, World world) {}
|
||||
|
||||
@Override
|
||||
public void unloadChunk(int cx, int cz, World world) {}
|
||||
|
||||
@Override
|
||||
public void saveChunk(int cx, int cz, World world) {}
|
||||
|
||||
@Override
|
||||
public boolean isChunkLoaded(int cx, int cz, World world) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void chunkLoaded(int cx, int cz, World world) {}
|
||||
|
||||
@Override
|
||||
public void chunkUnloaded(int cx, int cz, World world) {}
|
||||
|
||||
@Override
|
||||
public void saveWorld(World world) {}
|
||||
|
||||
@Override
|
||||
public void unloadWorld(World world) {}
|
||||
|
||||
@Override
|
||||
public void loadWorld(World world) {}
|
||||
|
||||
@Override
|
||||
public void saveAll() {}
|
||||
|
||||
@Override
|
||||
public void unloadAll() {}
|
||||
|
||||
@Override
|
||||
public boolean isTrue(int x, int y, int z, World world) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTrue(Block block) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTrue(int x, int y, int z, World world) {}
|
||||
|
||||
@Override
|
||||
public void setTrue(Block block) {}
|
||||
|
||||
@Override
|
||||
public void setFalse(int x, int y, int z, World world) {}
|
||||
|
||||
@Override
|
||||
public void setFalse(Block block) {}
|
||||
|
||||
@Override
|
||||
public void cleanUp() {}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
package com.gmail.nossr50.util.blockmeta.chunkmeta;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.World;
|
||||
|
||||
import com.gmail.nossr50.mcMMO;
|
||||
import com.gmail.nossr50.util.blockmeta.ChunkletStore;
|
||||
|
||||
public class PrimitiveChunkStore implements ChunkStore {
|
||||
private static final long serialVersionUID = -1L;
|
||||
transient private boolean dirty = false;
|
||||
/** X, Z, Y */
|
||||
public boolean[][][] store;
|
||||
private static final int CURRENT_VERSION = 5;
|
||||
private static final int MAGIC_NUMBER = 0xEA5EDEBB;
|
||||
private int cx;
|
||||
private int cz;
|
||||
private UUID worldUid;
|
||||
transient private int worldHeight;
|
||||
transient private int xBitShifts;
|
||||
transient private int zBitShifts;
|
||||
transient private boolean conversionNeeded;
|
||||
|
||||
public PrimitiveChunkStore(World world, int cx, int cz) {
|
||||
this.cx = cx;
|
||||
this.cz = cz;
|
||||
this.worldUid = world.getUID();
|
||||
|
||||
this.worldHeight = world != null ? world.getMaxHeight() : 128;
|
||||
this.xBitShifts = 11;
|
||||
this.zBitShifts = 7;
|
||||
|
||||
this.store = new boolean[16][16][this.worldHeight];
|
||||
|
||||
conversionNeeded = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirty() {
|
||||
return dirty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDirty(boolean dirty) {
|
||||
this.dirty = dirty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getChunkX() {
|
||||
return cx;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getChunkZ() {
|
||||
return cz;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTrue(int x, int y, int z) {
|
||||
return store[x][z][y];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTrue(int x, int y, int z) {
|
||||
store[x][z][y] = true;
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFalse(int x, int y, int z) {
|
||||
store[x][z][y] = false;
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
for(int x = 0; x < 16; x++) {
|
||||
for(int z = 0; z < 16; z++) {
|
||||
for(int y = 0; y < this.worldHeight; y++) {
|
||||
if(store[x][z][y]) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copyFrom(ChunkletStore otherStore) {
|
||||
for(int x = 0; x < 16; x++) {
|
||||
for(int z = 0; z < 16; z++) {
|
||||
for(int y = 0; y < this.worldHeight; y++) {
|
||||
store[x][z][y] = otherStore.isTrue(x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
private void writeObject(ObjectOutputStream out) throws IOException {
|
||||
out.writeInt(MAGIC_NUMBER);
|
||||
out.writeInt(CURRENT_VERSION);
|
||||
|
||||
out.writeLong(worldUid.getLeastSignificantBits());
|
||||
out.writeLong(worldUid.getMostSignificantBits());
|
||||
out.writeInt(cx);
|
||||
out.writeInt(cz);
|
||||
out.writeObject(store);
|
||||
|
||||
dirty = false;
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
int fileVersionNumber; // Can be used to determine the format of the file
|
||||
|
||||
long lsb = in.readLong();
|
||||
if (((int) (lsb >> 32)) == MAGIC_NUMBER) {
|
||||
fileVersionNumber = (int) lsb;
|
||||
lsb = in.readLong();
|
||||
} else {
|
||||
fileVersionNumber = 0;
|
||||
}
|
||||
|
||||
long msb = in.readLong();
|
||||
worldUid = new UUID(msb, lsb);
|
||||
cx = in.readInt();
|
||||
cz = in.readInt();
|
||||
|
||||
// Constructor is not invoked, need to set these fields
|
||||
World world = mcMMO.p.getServer().getWorld(this.worldUid);
|
||||
|
||||
this.worldHeight = world.getMaxHeight();
|
||||
this.xBitShifts = 11;
|
||||
this.zBitShifts = 7;
|
||||
|
||||
store = (boolean[][][]) in.readObject();
|
||||
|
||||
if (fileVersionNumber < CURRENT_VERSION) {
|
||||
fixArray();
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void fixArray() {
|
||||
boolean[][][] temp = this.store;
|
||||
this.store = new boolean[16][16][this.worldHeight];
|
||||
for(int x = 0; x < 16; x++) {
|
||||
for(int z = 0; z < 16; z++) {
|
||||
for(int y = 0; y < this.worldHeight; y++) {
|
||||
try {
|
||||
store[x][z][y] = temp[x][y][z];
|
||||
}
|
||||
catch(Exception e) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
39
src/main/java/org/getspout/spoutapi/chunkstore/mcMMOSimpleChunkBuffer.java
Executable file
39
src/main/java/org/getspout/spoutapi/chunkstore/mcMMOSimpleChunkBuffer.java
Executable file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* This file is part of SpoutPlugin.
|
||||
*
|
||||
* Copyright (c) 2011-2012, SpoutDev <http://www.spout.org/>
|
||||
* SpoutPlugin is licensed under the GNU Lesser General Public License.
|
||||
*
|
||||
* SpoutPlugin is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* SpoutPlugin is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.getspout.spoutapi.chunkstore;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class mcMMOSimpleChunkBuffer extends ByteArrayOutputStream {
|
||||
final mcMMOSimpleRegionFile rf;
|
||||
final int index;
|
||||
|
||||
mcMMOSimpleChunkBuffer(mcMMOSimpleRegionFile rf, int index) {
|
||||
super(1024);
|
||||
this.rf = rf;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
rf.write(index, buf, count);
|
||||
}
|
||||
}
|
||||
300
src/main/java/org/getspout/spoutapi/chunkstore/mcMMOSimpleRegionFile.java
Executable file
300
src/main/java/org/getspout/spoutapi/chunkstore/mcMMOSimpleRegionFile.java
Executable file
@@ -0,0 +1,300 @@
|
||||
/*
|
||||
* This file is part of SpoutPlugin.
|
||||
*
|
||||
* Copyright (c) 2011-2012, SpoutDev <http://www.spout.org/>
|
||||
* SpoutPlugin is licensed under the GNU Lesser General Public License.
|
||||
*
|
||||
* SpoutPlugin is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* SpoutPlugin is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.getspout.spoutapi.chunkstore;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.ArrayList;
|
||||
import java.util.zip.DeflaterOutputStream;
|
||||
import java.util.zip.InflaterInputStream;
|
||||
|
||||
public class mcMMOSimpleRegionFile {
|
||||
private RandomAccessFile file;
|
||||
private final int[] dataStart = new int[1024];
|
||||
private final int[] dataActualLength = new int[1024];
|
||||
private final int[] dataLength = new int[1024];
|
||||
private final ArrayList<Boolean> inuse = new ArrayList<Boolean>();
|
||||
private int segmentSize;
|
||||
private int segmentMask;
|
||||
private final int rx;
|
||||
private final int rz;
|
||||
private final int defaultSegmentSize;
|
||||
private final File parent;
|
||||
@SuppressWarnings("unused")
|
||||
private long lastAccessTime = System.currentTimeMillis();
|
||||
@SuppressWarnings("unused")
|
||||
private static long TIMEOUT_TIME = 300000; // 5 min
|
||||
|
||||
public mcMMOSimpleRegionFile(File f, int rx, int rz) {
|
||||
this(f, rx, rz, 10);
|
||||
}
|
||||
|
||||
public mcMMOSimpleRegionFile(File f, int rx, int rz, int defaultSegmentSize) {
|
||||
this.rx = rx;
|
||||
this.rz = rz;
|
||||
this.defaultSegmentSize = defaultSegmentSize;
|
||||
this.parent = f;
|
||||
|
||||
lastAccessTime = System.currentTimeMillis();
|
||||
if (file == null) {
|
||||
try {
|
||||
this.file = new RandomAccessFile(parent, "rw");
|
||||
|
||||
if (file.length() < 4096 * 3) {
|
||||
for (int i = 0; i < 1024 * 3; i++) {
|
||||
file.writeInt(0);
|
||||
}
|
||||
file.seek(4096 * 2);
|
||||
file.writeInt(defaultSegmentSize);
|
||||
}
|
||||
|
||||
file.seek(4096 * 2);
|
||||
|
||||
this.segmentSize = file.readInt();
|
||||
this.segmentMask = (1 << segmentSize) - 1;
|
||||
|
||||
int reservedSegments = this.sizeToSegments(4096 * 3);
|
||||
|
||||
for (int i = 0; i < reservedSegments; i++) {
|
||||
while (inuse.size() <= i) {
|
||||
inuse.add(false);
|
||||
}
|
||||
inuse.set(i, true);
|
||||
}
|
||||
|
||||
file.seek(0);
|
||||
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
dataStart[i] = file.readInt();
|
||||
}
|
||||
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
dataActualLength[i] = file.readInt();
|
||||
dataLength[i] = sizeToSegments(dataActualLength[i]);
|
||||
setInUse(i, true);
|
||||
}
|
||||
|
||||
extendFile();
|
||||
} catch (IOException fnfe) {
|
||||
throw new RuntimeException(fnfe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized final RandomAccessFile getFile() {
|
||||
lastAccessTime = System.currentTimeMillis();
|
||||
if (file == null) {
|
||||
try {
|
||||
this.file = new RandomAccessFile(parent, "rw");
|
||||
|
||||
if (file.length() < 4096 * 3) {
|
||||
for (int i = 0; i < 1024 * 3; i++) {
|
||||
file.writeInt(0);
|
||||
}
|
||||
file.seek(4096 * 2);
|
||||
file.writeInt(defaultSegmentSize);
|
||||
}
|
||||
|
||||
file.seek(4096 * 2);
|
||||
|
||||
this.segmentSize = file.readInt();
|
||||
this.segmentMask = (1 << segmentSize) - 1;
|
||||
|
||||
int reservedSegments = this.sizeToSegments(4096 * 3);
|
||||
|
||||
for (int i = 0; i < reservedSegments; i++) {
|
||||
while (inuse.size() <= i) {
|
||||
inuse.add(false);
|
||||
}
|
||||
inuse.set(i, true);
|
||||
}
|
||||
|
||||
file.seek(0);
|
||||
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
dataStart[i] = file.readInt();
|
||||
}
|
||||
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
dataActualLength[i] = file.readInt();
|
||||
dataLength[i] = sizeToSegments(dataActualLength[i]);
|
||||
setInUse(i, true);
|
||||
}
|
||||
|
||||
extendFile();
|
||||
} catch (IOException fnfe) {
|
||||
throw new RuntimeException(fnfe);
|
||||
}
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
public synchronized boolean testCloseTimeout() {
|
||||
/*if (System.currentTimeMillis() - TIMEOUT_TIME > lastAccessTime) {
|
||||
close();
|
||||
return true;
|
||||
}*/
|
||||
return false;
|
||||
}
|
||||
|
||||
public synchronized DataOutputStream getOutputStream(int x, int z) {
|
||||
int index = getChunkIndex(x, z);
|
||||
return new DataOutputStream(new DeflaterOutputStream(new mcMMOSimpleChunkBuffer(this, index)));
|
||||
}
|
||||
|
||||
public synchronized DataInputStream getInputStream(int x, int z) throws IOException {
|
||||
int index = getChunkIndex(x, z);
|
||||
int actualLength = dataActualLength[index];
|
||||
if (actualLength == 0) {
|
||||
return null;
|
||||
}
|
||||
byte[] data = new byte[actualLength];
|
||||
|
||||
getFile().seek(dataStart[index] << segmentSize);
|
||||
getFile().readFully(data);
|
||||
return new DataInputStream(new InflaterInputStream(new ByteArrayInputStream(data)));
|
||||
}
|
||||
|
||||
synchronized void write(int index, byte[] buffer, int size) throws IOException {
|
||||
int oldStart = setInUse(index, false);
|
||||
int start = findSpace(oldStart, size);
|
||||
getFile().seek(start << segmentSize);
|
||||
getFile().write(buffer, 0, size);
|
||||
dataStart[index] = start;
|
||||
dataActualLength[index] = size;
|
||||
dataLength[index] = sizeToSegments(size);
|
||||
setInUse(index, true);
|
||||
saveFAT();
|
||||
}
|
||||
|
||||
public synchronized void close() {
|
||||
try {
|
||||
if (file != null) {
|
||||
file.seek(4096 * 2);
|
||||
file.close();
|
||||
}
|
||||
file = null;
|
||||
} catch (IOException ioe) {
|
||||
throw new RuntimeException("Unable to close file", ioe);
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized int setInUse(int index, boolean used) {
|
||||
if (dataActualLength[index] == 0) {
|
||||
return dataStart[index];
|
||||
}
|
||||
|
||||
int start = dataStart[index];
|
||||
int end = start + dataLength[index];
|
||||
|
||||
for (int i = start; i < end; i++) {
|
||||
while (i > inuse.size() - 1) {
|
||||
inuse.add(false);
|
||||
}
|
||||
Boolean old = inuse.set(i, used);
|
||||
if (old != null && old == used) {
|
||||
if (old) {
|
||||
throw new IllegalStateException("Attempting to overwrite an in-use segment");
|
||||
} else {
|
||||
throw new IllegalStateException("Attempting to delete empty segment");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dataStart[index];
|
||||
}
|
||||
|
||||
private synchronized void extendFile() throws IOException {
|
||||
long extend = (-getFile().length()) & segmentMask;
|
||||
|
||||
getFile().seek(getFile().length());
|
||||
|
||||
while ((extend--) > 0) {
|
||||
getFile().write(0);
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized int findSpace(int oldStart, int size) {
|
||||
int segments = sizeToSegments(size);
|
||||
|
||||
boolean oldFree = true;
|
||||
for (int i = oldStart; i < inuse.size() && i < oldStart + segments; i++) {
|
||||
if (inuse.get(i)) {
|
||||
oldFree = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (oldFree) {
|
||||
return oldStart;
|
||||
}
|
||||
|
||||
int start = 0;
|
||||
int end = 0;
|
||||
|
||||
while (end < inuse.size()) {
|
||||
if (inuse.get(end)) {
|
||||
end++;
|
||||
start = end;
|
||||
} else {
|
||||
end++;
|
||||
}
|
||||
if (end - start >= segments) {
|
||||
return start;
|
||||
}
|
||||
}
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
private synchronized int sizeToSegments(int size) {
|
||||
if (size <= 0) {
|
||||
return 1;
|
||||
} else {
|
||||
return ((size - 1) >> segmentSize) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized Integer getChunkIndex(int x, int z) {
|
||||
if (rx != (x >> 5) || rz != (z >> 5)) {
|
||||
throw new RuntimeException(x + ", " + z + " not in region " + rx + ", " + rz);
|
||||
}
|
||||
|
||||
x = x & 0x1F;
|
||||
z = z & 0x1F;
|
||||
|
||||
return (x << 5) + z;
|
||||
}
|
||||
|
||||
private synchronized void saveFAT() throws IOException {
|
||||
getFile().seek(0);
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
getFile().writeInt(dataStart[i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
getFile().writeInt(dataActualLength[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -92,6 +92,14 @@ Fishing:
|
||||
Tier3: 400
|
||||
Tier4: 600
|
||||
Tier5: 800
|
||||
|
||||
Shake:
|
||||
Chance:
|
||||
Rank_1: 25
|
||||
Rank_2: 40
|
||||
Rank_3: 55
|
||||
Rank_4: 60
|
||||
Rank_5: 75
|
||||
|
||||
#
|
||||
# Settings for Abilities
|
||||
@@ -133,6 +141,7 @@ Skills:
|
||||
Acrobatics:
|
||||
Enabled_For_PVP: true
|
||||
Enabled_For_PVE: true
|
||||
Prevent_AFK_Leveling: true
|
||||
Level_Cap: 0
|
||||
Archery:
|
||||
Enabled_For_PVP: true
|
||||
@@ -149,8 +158,10 @@ Skills:
|
||||
Level_Cap: 0
|
||||
Herbalism:
|
||||
Level_Cap: 0
|
||||
Prevent_AFK_Leveling: true
|
||||
Green_Thumb:
|
||||
Cobble_To_Mossy: true
|
||||
CobbleWall_To_MossyWall: true
|
||||
SmoothBrick_To_MossyBrick: true
|
||||
Dirt_To_Grass: true
|
||||
Mining:
|
||||
@@ -197,6 +208,9 @@ Double_Drops:
|
||||
Water_Lilies: true
|
||||
Wheat: true
|
||||
Yellow_Flowers: true
|
||||
Cocoa: true
|
||||
Carrot: true
|
||||
Potato: true
|
||||
Mining:
|
||||
Coal: true
|
||||
Diamond: true
|
||||
@@ -211,6 +225,7 @@ Double_Drops:
|
||||
Redstone: true
|
||||
Sandstone: true
|
||||
Stone: true
|
||||
Emerald: true
|
||||
Woodcutting:
|
||||
Oak: true
|
||||
Birch: true
|
||||
@@ -264,6 +279,9 @@ Experience:
|
||||
Nether_Wart: 50
|
||||
Lily_Pads: 100
|
||||
Vines: 10
|
||||
Cocoa: 30
|
||||
Carrot: 50
|
||||
Potato: 50
|
||||
Mining:
|
||||
Sandstone: 30
|
||||
Glowstone: 30
|
||||
@@ -278,6 +296,7 @@ Experience:
|
||||
Iron: 250
|
||||
End_Stone: 150
|
||||
Moss_Stone: 30
|
||||
Emerald: 1000
|
||||
Taming:
|
||||
Animal_Taming:
|
||||
Wolf: 250
|
||||
|
||||
@@ -4,4 +4,6 @@
|
||||
###
|
||||
Options:
|
||||
# true to use Chunklets metadata store system, false to disable
|
||||
Chunklets: true
|
||||
Chunklets: true
|
||||
# Square root of the number of chunks to convert per tick.
|
||||
ConversionRate: 1
|
||||
@@ -102,7 +102,7 @@ Excavation.Skillup=[[YELLOW]]Excavation skill increased by {0}. Total ({1})
|
||||
Fishing.Ability.Info=[[RED]]Magic Hunter: [[GRAY]] **Improves With Treasure Hunter Rank**
|
||||
Fishing.Ability.Locked.0=LOCKED UNTIL 150+ SKILL (SHAKE)
|
||||
Fishing.Ability.Rank=[[RED]]Treasure Hunter Rank: [[YELLOW]]{0}/5
|
||||
Fishing.Ability.Shake=[[RED]]Shake: [[YELLOW]]Tear items off mobs, mutilating them in the process ;_;
|
||||
Fishing.Ability.Shake=[[RED]]Shake Chance: [[YELLOW]]{0}%
|
||||
Fishing.Effect.0=Treasure Hunter (Passive)
|
||||
Fishing.Effect.1=Fish up misc. objects
|
||||
Fishing.Effect.2=Magic Hunter
|
||||
@@ -221,8 +221,8 @@ Repair.Skills.Super.Chance=[[RED]]Super Repair Chance: [[YELLOW]]{0}
|
||||
Repair.Skillup=[[YELLOW]]Repair skill increased by {0}. Total ({1})
|
||||
|
||||
##Arcane Forging
|
||||
Repair.Arcane.Chance.Downgrade=[[GRAY]]AF Downgrade Chance: [[YELLOW]]{0}
|
||||
Repair.Arcane.Chance.Success=[[GRAY]]AF Success Rate: [[YELLOW]]{0}
|
||||
Repair.Arcane.Chance.Downgrade=[[GRAY]]AF Downgrade Chance: [[YELLOW]]{0}%
|
||||
Repair.Arcane.Chance.Success=[[GRAY]]AF Success Rate: [[YELLOW]]{0}%
|
||||
Repair.Arcane.Downgrade=[[RED]]Arcane power has decreased for this item.
|
||||
Repair.Arcane.Fail=[[RED]]Arcane power has permanently left the item.
|
||||
Repair.Arcane.Lost=[[RED]]You were not skilled enough to keep any enchantments.
|
||||
|
||||
Reference in New Issue
Block a user