1
0
mirror of https://github.com/mcMMO-Dev/mcMMO.git synced 2026-02-18 01:42:32 +01:00

Compare commits

..

96 Commits

Author SHA1 Message Date
TfT_02
b0681c10b9 About time that this got changed to 1.3.12 2012-11-13 16:47:59 +01:00
TfT_02
1bf0cd1d15 /fishing command will now also display the bonus gained from lucky perk 2012-11-13 10:08:05 +01:00
Grant
212b42c8b9 Merge pull request #305 from TfT-02/master
Changed the fishing skill shake + small fix for lucky perk in fishing
2012-11-11 11:45:55 -08:00
Grant
9c4ff30ce7 Merge pull request #304 from Glitchfinder/master
Attempting a minor reduction in lag for larger servers.
2012-11-11 11:45:11 -08:00
Grant
d7510b83c8 Merge pull request #307 from Glitchfinder/fixes
Additional fixes and patches.
2012-11-11 11:44:54 -08:00
Glitchfinder
9a9e0cc7de Modifying the amount of experience earned when using Tree Feller on jungle trees. It was nerfed a bit too much. 2012-11-10 12:45:54 -08:00
Glitchfinder
a8a90ee815 Fixing excessive null chunk before earning Woodcutting experience. 2012-11-10 12:43:08 -08:00
Glitchfinder
7859660ece Adding herbalism green thumb ability to carrots, potatoes, and netherwart. 2012-11-09 16:37:12 -08:00
Glitchfinder
b93dafee63 Applying a temporary patch to stop the wrong sand and gravel from being flagged as touched by players. 2012-11-09 09:45:50 -08:00
TfT_02
a1a61e9d4a Added new method for calculating the ShakeChance 2012-11-08 20:15:40 +01:00
TfT_02
464d6bdd35 Added the shake percentage
There are associated stats now.

Also added a '%' to Arcane chances in locale file
2012-11-08 20:15:02 +01:00
Glitchfinder
2c613d5b99 Fixing a null pointer error related to skill cooldowns. 2012-11-07 19:04:17 -08:00
Glitchfinder
d1f683b8a5 Adding the option to negate experience earned for Acrobatics or Herbalism while in a minecart to prevent afk leveling. 2012-11-07 18:41:18 -08:00
TfT_02
f4bb8ccb7d Add Shake chances in the default config.yml 2012-11-07 14:14:49 +01:00
TfT_02
00364afd8f Made the shake rank chance configurable 2012-11-07 14:02:30 +01:00
TfT_02
f5f07f7016 This wasn't right. 2012-11-07 13:32:30 +01:00
TfT_02
2bdeeb2d6e Changed shake drops from guaranteed to based upon fishing level and perks. 2012-11-07 13:30:20 +01:00
Glitchfinder
f023529d37 Reducing filesystem usage. Should help reduce lag on larger servers. THIS IS NOT A PERMANENT SOLUTION. 2012-11-06 23:15:15 -08:00
NuclearW
b8d37cb223 Merge pull request #299 from Glitchfinder/master
Fixing index error.

Better not do this all night, I'm not sticking around for that much :I
2012-11-05 20:18:26 -08:00
Glitchfinder
88ed14fe5c Fixing index error. 2012-11-05 20:14:23 -08:00
NuclearW
cd30771775 Merge pull request #298 from Glitchfinder/master
Fixing conversion lag.
2012-11-05 19:50:29 -08:00
Glitchfinder
00a5bc5cf3 Fixing lag caused by conversion. 2012-11-05 19:48:41 -08:00
Glitchfinder
a17d58fe32 Fixing previous commit. 2012-11-05 19:42:18 -08:00
Glitchfinder
c21286dbc3 Offloading chunk conversion. SHould alleviate lag. 2012-11-05 19:28:00 -08:00
Glitchfinder
7fc99630e0 Resolving a few issues with playability. Should be a bit better. 2012-11-05 18:02:53 -08:00
NuclearW
69a5cd1017 Merge pull request #295 from Glitchfinder/master
Updating block storage to a region-style format.
2012-11-05 17:37:49 -08:00
Glitchfinder
3129acfc19 General cleanup for pull request. 2012-11-05 16:03:44 -08:00
Glitchfinder
c3dd777e44 Merge remote-tracking branch 'mcmmo/master' 2012-11-05 14:02:07 -08:00
Grant
c5120b9c72 Merge pull request #293 from Glitchfinder/fixes
Additional fixes and patches.
2012-11-05 07:53:50 -08:00
Glitchfinder
91a18fe7a2 Fixing herbalism to look for cobble walls when trying to convert cobble walls. 2012-11-04 21:47:15 -08:00
Glitchfinder
62f5185a1b Attempting to fix index error. 2012-11-04 20:36:47 -08:00
Glitchfinder
f4cb83319e Fixes an NPE involving certain explosions. 2012-11-04 16:39:06 -08:00
Glitchfinder
c7b3b7a826 Green thumb now converts cobble walls to mossy cobble walls. 2012-11-04 16:06:33 -08:00
Glitchfinder
01fb245da3 Fixing double drops for herbalism so that carrots and potatoes drop items instead of blocks. 2012-11-04 15:54:22 -08:00
Glitchfinder
83e072dad1 Fixing a potential error with legacy chunklet types. 2012-11-04 13:43:14 -08:00
Glitchfinder
eb5ac80714 Updating modified block storage to a region-style format. 2012-11-04 13:36:57 -08:00
Grant
b57cc7bd59 Merge pull request #284 from Glitchfinder/master
Attempting to resolve various issues in the issue tracker.
2012-11-04 11:24:32 -08:00
Glitchfinder
d532164cd6 Incorporating #287 due to incompatible edits. 2012-11-02 08:45:50 -07:00
Glitchfinder
61ae4826d1 Addresses issue #286. 2012-11-01 16:43:59 -07:00
Glitchfinder
be4e62fe9d Hopefully addresses part of the empty enchant issue. 2012-10-31 22:47:04 -07:00
Glitchfinder
d9346ab260 Fixing default experience for the newer herbalism materials. 2012-10-31 15:44:45 -07:00
Glitchfinder
87c4f318a4 Fixing fishing a bit. 2012-10-31 12:39:04 -07:00
Glitchfinder
30b87e8035 Resolving potential conflict with #285. (Missed the newline) 2012-10-30 20:12:43 -07:00
Glitchfinder
26a85846fc Resolving potential conflict with #285. 2012-10-30 20:11:24 -07:00
Glitchfinder
cd40507609 Resolving issue #211. 2012-10-30 20:05:37 -07:00
Glitchfinder
a9ea2e0137 Resolving issue #258. 2012-10-30 19:24:20 -07:00
Glitchfinder
6964f7adfc Resolving issue #238. 2012-10-30 18:12:50 -07:00
Glitchfinder
70231b6ae0 Resolving issues #243, #241, and #234. 2012-10-30 17:59:58 -07:00
U-YUE\Sean
9354831729 Finished fixing issues #272, #266, #261, and #255. 2012-10-30 13:14:22 -07:00
U-YUE\Sean
ab7a83b37e Attempting to fix issues #272 , #266 , #261 , and #255 . 2012-10-30 11:46:52 -07:00
U-YUE\Sean
8dfa8c20f3 Resolving first half of issue #283 . Recommend closing issue and reopening with a new ticket number for the issue regarding stats. Stat bug probably involves commit @42aa42699129448ef7fa0e4e5de96840004c13ee 2012-10-30 10:26:46 -07:00
Grant
67499eeff7 Merge pull request #281 from Glitchfinder/master
Fixed checked data values for carrots and potatoes.
2012-10-30 07:01:35 -07:00
Grant
d43ff6263f Merge pull request #282 from Glitchfinder/master
Adds support for newer mobs to the fishing shake ability.
2012-10-30 07:01:25 -07:00
Glitchfinder
058dc8c611 Added support for newer mobs to fishing's shake ability. 2012-10-29 14:27:22 -07:00
Glitchfinder
8871964be0 Fixing checked data values for carrots and potatoes. 2012-10-29 12:33:13 -07:00
Grant
42aa426991 Merge pull request #271 from mcunha/better-db-handling
Better db handling
2012-10-29 10:25:49 -07:00
Grant
7cee94e0b8 Merge pull request #274 from zippy120/master
Added checks in the events to prevent errors when Citizens NPCs perform tasks.
2012-10-29 10:25:39 -07:00
Grant
fa96a6beec Merge pull request #278 from Glitchfinder/master
Basic update for 1.4.2
2012-10-29 10:25:29 -07:00
Grant
efc0edf3ef Merge pull request #279 from mcunha/fix-mossied-cobblestone
Don't award double drops to mossified cobblestone
2012-10-29 10:25:07 -07:00
Marco Cunha
f1d785777c Don't award double drops to mossified cobblestone 2012-10-29 17:17:52 +01:00
Glitchfinder
db0168205d Added herbalism food bonuses. 2012-10-28 22:47:26 -07:00
Glitchfinder
2a20ed95fa Added missed checks for potatoes and carrots. 2012-10-28 20:56:33 -07:00
Glitchfinder
11f1889f1f Added support for carrots and potatoes. Also updated to ignore beacon blocks and anvil blocks. 2012-10-28 20:53:03 -07:00
zippy120
703b5b2f3f Added checks in the events to prevent errors when Citizens NPCs perform tasks. 2012-10-28 09:26:46 -06:00
Marco Cunha
58a15e61dd Fix refactoring typos 2012-10-22 19:05:13 +02:00
Marco Cunha
896f57f0b4 Force proper disposal of resultsets and statements 2012-10-22 15:03:31 +02:00
Marco Cunha
34ae64706e Improved DB connection handling
Support for aggressive connection timeouts, with exponential backoff
for multiple failures.
2012-10-22 14:45:16 +02:00
Grant
43fe92fe3f Merge pull request #269 from Glitchfinder/master
Finished adding skill checks for Emerald Ore and Cocoa.
2012-10-18 08:34:47 -07:00
Glitchfinder
31513d52d7 Fixing spacing issues and making herbalism drop cocoa beans instead of a cocoa block. 2012-10-17 21:26:16 -07:00
Glitchfinder
70a16fe344 Finished adding skill checks for Emerald Ore and Cocoa. 2012-10-17 13:41:19 -07:00
nossr50
4570ffb8f5 Merge pull request #263 from h31ix/enderchest2
Don't activate abilities by opening an Ender Chest
2012-09-30 18:38:34 -07:00
h31ix
22f6ed324d Added ender chest to list of blocks that should not cause ability activation 2012-09-30 12:48:20 -04:00
nossr50
e29484e14b Merge pull request #252 from mcunha/master
Fix ore dupe bug with ore blocks on pistons
2012-09-09 16:50:17 -07:00
Marco Cunha
7e21fdd862 Fix ore dupe bug with ore blocks on pistons 2012-09-10 01:53:16 +03:00
nossr50
01e69cdf5e Fixing some mistakes. 2012-09-07 14:49:00 -07:00
nossr50
9ad7840236 Merge pull request #246 from matix931/patch-4
Update src/main/java/com/gmail/nossr50/config/Config.java
2012-09-05 21:11:15 -07:00
nossr50
e97ec36094 Merge pull request #247 from matix931/patch-5
Update src/main/resources/config.yml
2012-09-05 21:11:07 -07:00
nossr50
ef318eeaec Merge pull request #248 from matix931/patch-7
Update src/main/java/com/gmail/nossr50/skills/gathering/Herbalism.java
2012-09-05 21:10:58 -07:00
nossr50
3314b18318 Merge pull request #249 from matix931/patch-6
Update src/main/java/com/gmail/nossr50/skills/gathering/Mining.java
2012-09-05 21:10:44 -07:00
matix931
5f04ecfdd4 Update src/main/java/com/gmail/nossr50/skills/gathering/Herbalism.java 2012-09-05 11:45:43 +03:00
matix931
91d294acff Update src/main/java/com/gmail/nossr50/skills/gathering/Mining.java
Another change against 1.3.2
2012-09-05 11:19:34 +03:00
matix931
283cdeed6c Update src/main/resources/config.yml 2012-09-05 11:10:50 +03:00
matix931
a283fce4ec Update src/main/java/com/gmail/nossr50/config/Config.java
Doing something against 1.3.2
2012-09-05 11:09:14 +03:00
nossr50
f8d525d797 Merge branch 'master' of https://github.com/mcMMO-Dev/mcMMO 2012-09-03 13:27:11 -07:00
nossr50
80dabad10e Nerfs to axes 2012-09-03 13:26:48 -07:00
nossr50
8181989e98 Merge pull request #240 from matix931/patch-3
Update src/main/java/com/gmail/nossr50/skills/repair/Repair.java
2012-09-02 08:04:26 -07:00
matix931
0f7bf13834 Update src/main/java/com/gmail/nossr50/skills/repair/Repair.java
When DowngradeChance is 0 random can be the same (0 to 99) so can't be <= becouse downgrade will continue
2012-08-31 18:03:54 +03:00
nossr50
c1d6e79a41 Vampirism fix 2012-08-30 09:16:08 -07:00
nossr50
6f073250f4 Merge pull request #233 from t00thpick1/master
Added missing null check
2012-08-18 06:19:00 -07:00
t00thpick1
c084ccde40 Added missing null check 2012-08-17 18:45:08 -03:00
nossr50
b73a06b9ab Merge pull request #232 from t00thpick1/master
Actually fixed dupes
2012-08-16 22:23:27 -07:00
t00thpick1
740c1131ea Made superbreaker not dupe if event is cancelled 2012-08-17 01:28:28 -03:00
t00thpick1
0a798aec30 Made gigadrill not dupe if event is cancelled 2012-08-17 01:27:41 -03:00
nossr50
9089e70155 Dupes are bad mmkay 2012-08-14 14:24:54 -07:00
nossr50
f532630d1b Another fix to make us more compatible with other plugins 2012-08-14 14:21:07 -07:00
nossr50
7b47d32a96 Citizens compatibility. Bug fix for Woodcutting/custom trees. 2012-08-14 14:09:49 -07:00
74 changed files with 2815 additions and 257 deletions

View File

@@ -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
View 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>

View File

@@ -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)) {

View File

@@ -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();

View File

@@ -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;

View File

@@ -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"));

View File

@@ -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;

View File

@@ -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;

View File

@@ -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();

View File

@@ -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"));
}

View File

@@ -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"));
}

View File

@@ -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;

View File

@@ -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() }));

View File

@@ -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";

View File

@@ -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 }));
}
}
}

View File

@@ -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); }

View File

@@ -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;
}
}

View File

@@ -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();

View File

@@ -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();

View File

@@ -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();

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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();

View File

@@ -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);
}

View File

@@ -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) {

View File

@@ -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

View File

@@ -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();
}
/**

View File

@@ -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;
}
}
}

View File

@@ -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
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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) {

View File

@@ -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();
}

View File

@@ -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;
}

View File

@@ -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) {

View File

@@ -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)

View File

@@ -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);

View 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;
}
}
}

View File

@@ -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
}
}

View File

@@ -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;
}

View File

@@ -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:

View File

@@ -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;
}

View File

@@ -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) {

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -19,6 +19,9 @@ public class BeastLoreEventHandler {
}
protected void sendInspectMessage() {
if(player == null)
return;
String message = LocaleLoader.getString("Combat.BeastLore") + " ";
if (beast.isTamed()) {

View File

@@ -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"));
}
}

View File

@@ -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"));
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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:

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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);
}
}

View File

@@ -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");
}

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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) {

View 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();
}

View File

@@ -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();
}
}
}

View 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);
}

View File

@@ -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);
}
}

View 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);
}
}
}

View File

@@ -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() {}
}

View File

@@ -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) {}
}
}
}
}
}

View 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);
}
}

View 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]);
}
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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.