Spears update (#5236)

Spears update
This commit is contained in:
Robert Alan Chapton
2025-12-14 14:23:25 -08:00
committed by GitHub
parent a907bfd624
commit b15365e978
55 changed files with 5927 additions and 3090 deletions

View File

@@ -1,3 +1,33 @@
Version 2.2.046
Added Spears combat skill
Added Spears to repair.vanilla.yml and salvage.vanilla.yml (see notes)
Added various permissions related to Spears
Added /spears skill command
Added Nautilus to taming XP in experience.yml
Added Camel_Husk to taming XP in experience.yml
Added Camel_Husk to combat XP in experience.yml
Added Parched to combat XP in experience.yml
Fixed bug where converting from SQL to FlatFile would not copy data for tridents, crossbows, maces, or spears
(Codebase) Added docker-based unit tests for SQL databases (see notes)
(Codebase) Large refactor to both SQLDatabaseManager and FlatFileDatabaseManager
(Codebase) Database related errors are now more descriptive and have had their logging improved
NOTES:
This update had a lot of changes behind the scenes, please report any bugs you find to our GitHub issues page!
You will need to manually update repair.vanilla.yml and salvage.vanilla.yml to get support for Spears, or...
If you want to update salvage/repair configs the easy way, you simply can delete these config files to have mcMMO regenerate them with the new entries.
If you don't want to delete them, you can find the default values for these config files in the defaults folder at plugins\mcMMO\defaults after running this mcMMO update at least once.
You can use this default file to copy paste if you please.
Docker is ONLY required for developers compiling mcMMO from source code and ONLY for running SQL-related unit tests.
mcMMO itself does NOT require Docker to run, and servers using prebuilt releases are completely unaffected.
New SQL database unit tests use Testcontainers to spin up temporary MySQL/MariaDB instances for testing purposes.
These containers are created at test time and are never used at runtime.
If you compile mcMMO locally and do not have Docker installed, SQL-related unit tests may fail.
In this case, you can safely compile with -DskipTests to skip unit tests entirely.
Skipping tests has no impact on mcMMO functionality when running on a server.
Known Issues:
I ran into an issue where having a spear in the offhand while the main hand is empty causes attacks to be incorrectly classified as unarmed. This allows unarmed abilities to apply to spear damage. As a temporary measure, Ive disabled unarmed skills from applying to combat when a spear is equipped in the offhand while I investigate a more robust solution.
Version 2.2.045
Green Thumb now replants some crops it was failing to replant before (see notes)
Green Thumb now replants harvested plants faster

113
pom.xml
View File

@@ -1,8 +1,10 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.gmail.nossr50.mcMMO</groupId>
<artifactId>mcMMO</artifactId>
<version>2.2.046-SNAPSHOT</version>
<version>2.2.046</version>
<name>mcMMO</name>
<url>https://github.com/mcMMO-Dev/mcMMO</url>
<scm>
@@ -13,8 +15,8 @@
</scm>
<properties>
<!-- <spigot.version>1.19-R0.1-SNAPSHOT</spigot.version>-->
<spigot.version>1.21.10-R0.1-SNAPSHOT</spigot.version>
<!-- <spigot.version>1.19-R0.1-SNAPSHOT</spigot.version>-->
<spigot.version>1.21.11-R0.1-SNAPSHOT</spigot.version>
<kyori.adventure.version>4.23.0</kyori.adventure.version>
<kyori.adventure.platform.version>4.4.1-SNAPSHOT</kyori.adventure.platform.version>
<kyori.option.version>1.1.0</kyori.option.version>
@@ -182,11 +184,13 @@
</relocation>
<relocation>
<pattern>co.aikar.commands</pattern>
<shadedPattern>com.gmail.nossr50.mcmmo.acf</shadedPattern> <!-- Replace this -->
<shadedPattern>com.gmail.nossr50.mcmmo.acf
</shadedPattern> <!-- Replace this -->
</relocation>
<relocation>
<pattern>co.aikar.locales</pattern>
<shadedPattern>com.gmail.nossr50.mcmmo.locales</shadedPattern> <!-- Replace this -->
<shadedPattern>com.gmail.nossr50.mcmmo.locales
</shadedPattern> <!-- Replace this -->
</relocation>
<relocation>
<pattern>org.apache.commons.logging</pattern>
@@ -194,7 +198,8 @@
</relocation>
<relocation>
<pattern>org.apache.juli</pattern>
<shadedPattern>com.gmail.nossr50.mcmmo.database.tomcat.juli</shadedPattern>
<shadedPattern>com.gmail.nossr50.mcmmo.database.tomcat.juli
</shadedPattern>
</relocation>
<relocation>
<pattern>org.apache.tomcat</pattern>
@@ -385,11 +390,11 @@
<version>3.0.2</version>
<scope>compile</scope>
</dependency>
<!-- <dependency>-->
<!-- <groupId>io.papermc.paper</groupId>-->
<!-- <artifactId>paper-api</artifactId>-->
<!-- <version>1.21.8-R0.1-SNAPSHOT</version>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>io.papermc.paper</groupId>-->
<!-- <artifactId>paper-api</artifactId>-->
<!-- <version>1.21.8-R0.1-SNAPSHOT</version>-->
<!-- </dependency>-->
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
@@ -426,10 +431,76 @@
</exclusion>
</exclusions>
</dependency>
<!-- JUnit 5 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.11.0-M2</version>
<version>5.11.0</version>
<scope>test</scope>
</dependency>
<!-- Testcontainers core -->
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>2.0.2</version>
<scope>test</scope>
</dependency>
<!-- Testcontainers JUnit Jupiter integration -->
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-junit-jupiter</artifactId>
<version>2.0.2</version>
<scope>test</scope>
</dependency>
<!-- Log4j core for tests -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.25.2</version>
<scope>test</scope>
</dependency>
<!-- Log4j API -->
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-api -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.25.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j-impl -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.25.2</version>
<scope>test</scope>
</dependency>
<!-- MySQL Testcontainers module -->
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-mysql</artifactId>
<scope>test</scope>
</dependency>
<!-- MariaDB Testcontainers module -->
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-mariadb</artifactId>
<scope>test</scope>
</dependency>
<!-- MySQL JDBC driver -->
<!-- https://mvnrepository.com/artifact/com.mysql/mysql-connector-j -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>9.5.0</version>
<scope>test</scope>
</dependency>
<!-- MariaDB JDBC driver -->
<!-- https://mvnrepository.com/artifact/org.mariadb.jdbc/mariadb-java-client -->
<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
<version>3.5.6</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -447,7 +518,7 @@
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
<version>10.1.24</version>
<version>11.0.14</version>
<scope>compile</scope>
</dependency>
<dependency>
@@ -458,7 +529,8 @@
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>33.2.0-jre</version> <!-- At this time Spigot is including 29.0 Guava classes that we are using -->
<version>33.2.0-jre
</version> <!-- At this time Spigot is including 29.0 Guava classes that we are using -->
<scope>compile</scope>
</dependency>
<dependency>
@@ -468,4 +540,15 @@
<scope>compile</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-bom</artifactId>
<version>2.0.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>

View File

@@ -73,7 +73,7 @@ public class AcrobaticsCommand extends SkillCommand {
protected List<Component> getTextComponents(Player player) {
List<Component> textComponents = new ArrayList<>();
TextComponentFactory.getSubSkillTextComponents(player, textComponents,
TextComponentFactory.appendSubSkillTextComponents(player, textComponents,
PrimarySkillType.ACROBATICS);
return textComponents;

View File

@@ -92,7 +92,7 @@ public class AlchemyCommand extends SkillCommand {
protected List<Component> getTextComponents(Player player) {
List<Component> textComponents = new ArrayList<>();
TextComponentFactory.getSubSkillTextComponents(player, textComponents,
TextComponentFactory.appendSubSkillTextComponents(player, textComponents,
PrimarySkillType.ALCHEMY);
return textComponents;

View File

@@ -93,7 +93,7 @@ public class ArcheryCommand extends SkillCommand {
protected List<Component> getTextComponents(Player player) {
List<Component> textComponents = new ArrayList<>();
TextComponentFactory.getSubSkillTextComponents(player, textComponents,
TextComponentFactory.appendSubSkillTextComponents(player, textComponents,
PrimarySkillType.ARCHERY);
return textComponents;

View File

@@ -119,7 +119,7 @@ public class AxesCommand extends SkillCommand {
protected List<Component> getTextComponents(Player player) {
final List<Component> textComponents = new ArrayList<>();
TextComponentFactory.getSubSkillTextComponents(player, textComponents,
TextComponentFactory.appendSubSkillTextComponents(player, textComponents,
PrimarySkillType.AXES);
return textComponents;

View File

@@ -68,7 +68,7 @@ public class CrossbowsCommand extends SkillCommand {
protected List<Component> getTextComponents(Player player) {
List<Component> textComponents = new ArrayList<>();
TextComponentFactory.getSubSkillTextComponents(player, textComponents,
TextComponentFactory.appendSubSkillTextComponents(player, textComponents,
PrimarySkillType.CROSSBOWS);
return textComponents;

View File

@@ -71,7 +71,7 @@ public class ExcavationCommand extends SkillCommand {
protected List<Component> getTextComponents(Player player) {
List<Component> textComponents = new ArrayList<>();
TextComponentFactory.getSubSkillTextComponents(player, textComponents,
TextComponentFactory.appendSubSkillTextComponents(player, textComponents,
PrimarySkillType.EXCAVATION);
return textComponents;

View File

@@ -185,7 +185,7 @@ public class FishingCommand extends SkillCommand {
protected List<Component> getTextComponents(Player player) {
List<Component> textComponents = new ArrayList<>();
TextComponentFactory.getSubSkillTextComponents(player, textComponents,
TextComponentFactory.appendSubSkillTextComponents(player, textComponents,
PrimarySkillType.FISHING);
return textComponents;

View File

@@ -187,7 +187,7 @@ public class HerbalismCommand extends SkillCommand {
protected List<Component> getTextComponents(Player player) {
List<Component> textComponents = new ArrayList<>();
TextComponentFactory.getSubSkillTextComponents(player, textComponents,
TextComponentFactory.appendSubSkillTextComponents(player, textComponents,
PrimarySkillType.HERBALISM);
return textComponents;

View File

@@ -23,7 +23,8 @@ public class MacesCommand extends SkillCommand {
super(PrimarySkillType.MACES);
}
String crippleChanceToApply, crippleChanceToApplyLucky, crippleLengthAgainstPlayers, crippleLengthAgainstMobs;
String crippleChanceToApply, crippleChanceToApplyLucky, crippleLengthAgainstPlayers,
crippleLengthAgainstMobs;
@Override
protected void dataCalculations(Player player, float skillValue) {
@@ -33,7 +34,6 @@ public class MacesCommand extends SkillCommand {
MacesManager.getCrippleTickDuration(true) / 20.0D);
crippleLengthAgainstMobs = String.valueOf(
MacesManager.getCrippleTickDuration(false) / 20.0D);
crippleChanceToApply =
mcMMO.p.getAdvancedConfig().getCrippleChanceToApplyOnHit(crippleRank) + "%";
crippleChanceToApplyLucky = String.valueOf(
@@ -77,7 +77,7 @@ public class MacesCommand extends SkillCommand {
protected List<Component> getTextComponents(Player player) {
List<Component> textComponents = new ArrayList<>();
TextComponentFactory.getSubSkillTextComponents(player, textComponents,
TextComponentFactory.appendSubSkillTextComponents(player, textComponents,
PrimarySkillType.MACES);
return textComponents;

View File

@@ -144,7 +144,7 @@ public class MiningCommand extends SkillCommand {
protected List<Component> getTextComponents(Player player) {
List<Component> textComponents = new ArrayList<>();
TextComponentFactory.getSubSkillTextComponents(player, textComponents,
TextComponentFactory.appendSubSkillTextComponents(player, textComponents,
PrimarySkillType.MINING);
return textComponents;

View File

@@ -134,7 +134,7 @@ public class RepairCommand extends SkillCommand {
protected List<Component> getTextComponents(Player player) {
List<Component> textComponents = new ArrayList<>();
TextComponentFactory.getSubSkillTextComponents(player, textComponents,
TextComponentFactory.appendSubSkillTextComponents(player, textComponents,
PrimarySkillType.REPAIR);
return textComponents;

View File

@@ -72,7 +72,7 @@ public class SalvageCommand extends SkillCommand {
protected List<Component> getTextComponents(Player player) {
List<Component> textComponents = new ArrayList<>();
TextComponentFactory.getSubSkillTextComponents(player, textComponents,
TextComponentFactory.appendSubSkillTextComponents(player, textComponents,
PrimarySkillType.SALVAGE);
return textComponents;

View File

@@ -97,7 +97,7 @@ public class SmeltingCommand extends SkillCommand {
protected List<Component> getTextComponents(Player player) {
List<Component> textComponents = new ArrayList<>();
TextComponentFactory.getSubSkillTextComponents(player, textComponents,
TextComponentFactory.appendSubSkillTextComponents(player, textComponents,
PrimarySkillType.SMELTING);
return textComponents;

View File

@@ -0,0 +1,85 @@
package com.gmail.nossr50.commands.skills;
import static com.gmail.nossr50.datatypes.skills.SubSkillType.SPEARS_MOMENTUM;
import static com.gmail.nossr50.datatypes.skills.SubSkillType.SPEARS_SPEARS_LIMIT_BREAK;
import static com.gmail.nossr50.datatypes.skills.SubSkillType.SPEARS_SPEAR_MASTERY;
import static com.gmail.nossr50.util.skills.SkillUtils.canUseSubskill;
import static com.gmail.nossr50.util.text.TextComponentFactory.appendSubSkillTextComponents;
import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
import com.gmail.nossr50.locale.LocaleLoader;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.skills.spears.SpearsManager;
import com.gmail.nossr50.util.player.UserManager;
import com.gmail.nossr50.util.skills.CombatUtils;
import com.gmail.nossr50.util.skills.RankUtils;
import com.gmail.nossr50.util.skills.SkillUtils;
import java.util.ArrayList;
import java.util.List;
import net.kyori.adventure.text.Component;
import org.bukkit.entity.Player;
public class SpearsCommand extends SkillCommand {
public SpearsCommand() {
super(PrimarySkillType.SPEARS);
}
String momentumChanceToApply, momentumChanceToApplyLucky, momentumDuration;
@Override
protected void dataCalculations(Player player, float skillValue) {
if (SkillUtils.canUseSubskill(player, SPEARS_MOMENTUM)) {
int momentumRank = RankUtils.getRank(player, SPEARS_MOMENTUM);
momentumDuration = String.valueOf(
SpearsManager.getMomentumTickDuration(momentumRank) / 20.0D);
momentumChanceToApply =
mcMMO.p.getAdvancedConfig().getMomentumChanceToApplyOnHit(momentumRank) + "%";
momentumChanceToApplyLucky = String.valueOf(
mcMMO.p.getAdvancedConfig().getMomentumChanceToApplyOnHit(momentumRank) * 1.33);
}
}
@Override
protected void permissionsCheck(Player player) {
}
@Override
protected List<String> statsDisplay(Player player, float skillValue, boolean hasEndurance,
boolean isLucky) {
final SpearsManager spearsManager = UserManager.getPlayer(player).getSpearsManager();
final double spearMasteryBonusDmg = spearsManager.getSpearMasteryBonusDamage();
List<String> messages = new ArrayList<>();
if (canUseSubskill(player, SPEARS_SPEARS_LIMIT_BREAK)) {
messages.add(getStatMessage(SPEARS_SPEARS_LIMIT_BREAK,
String.valueOf(CombatUtils.getLimitBreakDamageAgainstQuality(player,
SPEARS_SPEARS_LIMIT_BREAK, 1000))));
}
if (canUseSubskill(player, SPEARS_SPEAR_MASTERY)) {
messages.add(getStatMessage(SPEARS_SPEAR_MASTERY,
String.valueOf(spearMasteryBonusDmg)));
}
if (SkillUtils.canUseSubskill(player, SPEARS_MOMENTUM)) {
messages.add(getStatMessage(SPEARS_MOMENTUM, momentumChanceToApply)
+ (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus",
momentumChanceToApplyLucky) : ""));
messages.add(getStatMessage(true, true, SPEARS_MOMENTUM, momentumDuration));
}
return messages;
}
@Override
protected List<Component> getTextComponents(Player player) {
List<Component> textComponents = new ArrayList<>();
appendSubSkillTextComponents(player, textComponents, PrimarySkillType.SPEARS);
return textComponents;
}
}

View File

@@ -22,8 +22,8 @@ public class SwordsCommand extends SkillCommand {
private String serratedStrikesLengthEndurance;
private String rupturePureTickDamageAgainstPlayers, rupturePureTickDamageAgainstMobs,
ruptureExplosionDamageAgainstPlayers, ruptureExplosionDamageAgainstMobs,
ruptureLengthSecondsAgainstPlayers, ruptureLengthSecondsAgainstMobs, ruptureChanceToApply, ruptureChanceToApplyLucky;
ruptureLengthSecondsAgainstPlayers, ruptureLengthSecondsAgainstMobs,
ruptureChanceToApply, ruptureChanceToApplyLucky;
private boolean canCounter;
private boolean canSerratedStrike;
@@ -56,11 +56,6 @@ public class SwordsCommand extends SkillCommand {
rupturePureTickDamageAgainstMobs = String.valueOf(
mcMMO.p.getAdvancedConfig().getRuptureTickDamage(false, ruptureRank));
ruptureExplosionDamageAgainstPlayers = String.valueOf(
mcMMO.p.getAdvancedConfig().getRuptureExplosionDamage(true, ruptureRank));
ruptureExplosionDamageAgainstMobs = String.valueOf(
mcMMO.p.getAdvancedConfig().getRuptureExplosionDamage(false, ruptureRank));
ruptureChanceToApply =
mcMMO.p.getAdvancedConfig().getRuptureChanceToApplyOnHit(ruptureRank) + "%";
ruptureChanceToApplyLucky = String.valueOf(
@@ -105,7 +100,6 @@ public class SwordsCommand extends SkillCommand {
messages.add(LocaleLoader.getString("Swords.SubSkill.Rupture.Stat.TickDamage",
rupturePureTickDamageAgainstPlayers, rupturePureTickDamageAgainstMobs));
// messages.add(LocaleLoader.getString("Swords.SubSkill.Rupture.Stat.ExplosionDamage", ruptureExplosionDamageAgainstPlayers, ruptureExplosionDamageAgainstMobs));
messages.add(LocaleLoader.getString("Swords.Combat.Rupture.Note.Update.One"));
}
@@ -134,7 +128,7 @@ public class SwordsCommand extends SkillCommand {
protected List<Component> getTextComponents(Player player) {
List<Component> textComponents = new ArrayList<>();
TextComponentFactory.getSubSkillTextComponents(player, textComponents,
TextComponentFactory.appendSubSkillTextComponents(player, textComponents,
PrimarySkillType.SWORDS);
return textComponents;

View File

@@ -115,7 +115,7 @@ public class TamingCommand extends SkillCommand {
protected List<Component> getTextComponents(Player player) {
List<Component> textComponents = new ArrayList<>();
TextComponentFactory.getSubSkillTextComponents(player, textComponents, this.skill);
TextComponentFactory.appendSubSkillTextComponents(player, textComponents, this.skill);
return textComponents;
}

View File

@@ -50,7 +50,7 @@ public class TridentsCommand extends SkillCommand {
protected List<Component> getTextComponents(Player player) {
List<Component> textComponents = new ArrayList<>();
TextComponentFactory.getSubSkillTextComponents(player, textComponents,
TextComponentFactory.appendSubSkillTextComponents(player, textComponents,
PrimarySkillType.TRIDENTS);
return textComponents;

View File

@@ -136,7 +136,7 @@ public class UnarmedCommand extends SkillCommand {
protected List<Component> getTextComponents(Player player) {
List<Component> textComponents = new ArrayList<>();
TextComponentFactory.getSubSkillTextComponents(player, textComponents,
TextComponentFactory.appendSubSkillTextComponents(player, textComponents,
PrimarySkillType.UNARMED);
return textComponents;

View File

@@ -123,7 +123,7 @@ public class WoodcuttingCommand extends SkillCommand {
protected List<Component> getTextComponents(Player player) {
List<Component> textComponents = new ArrayList<>();
TextComponentFactory.getSubSkillTextComponents(player, textComponents,
TextComponentFactory.appendSubSkillTextComponents(player, textComponents,
PrimarySkillType.WOODCUTTING);
return textComponents;

View File

@@ -11,6 +11,7 @@ import net.md_5.bungee.api.ChatColor;
public class AdvancedConfig extends BukkitConfig {
int[] defaultCrippleValues = new int[]{10, 15, 20, 25};
int[] defaultMomentumValues = new int[]{5, 10, 15, 20, 25, 30, 35, 40, 45, 50};
public AdvancedConfig(File dataFolder) {
super("advanced.yml", dataFolder);
@@ -884,7 +885,17 @@ public class AdvancedConfig extends BukkitConfig {
/* MACES */
public double getCrippleChanceToApplyOnHit(int rank) {
String root = "Skills.Maces.Cripple.Chance_To_Apply_On_Hit.Rank_";
return config.getDouble(root + rank, defaultCrippleValues[rank - 1]);
return config.getDouble("Skills.Maces.Cripple.Chance_To_Apply_On_Hit.Rank_" + rank,
defaultCrippleValues[rank - 1]);
}
/* SPEARS */
public double getMomentumChanceToApplyOnHit(int rank) {
return config.getDouble("Skills.Spears.Momentum.Chance_To_Apply_On_Hit.Rank_" + rank,
defaultMomentumValues[rank - 1]);
}
public double getSpearMasteryRankDamageMultiplier() {
return config.getDouble("Skills.Spears.SpearMastery.Rank_Damage_Multiplier", 0.4D);
}
}

View File

@@ -424,10 +424,6 @@ public class GeneralConfig extends BukkitConfig {
return config.getBoolean("MySQL.Server.SSL", true);
}
public boolean getMySQLDebug() {
return config.getBoolean("MySQL.Debug", false);
}
public boolean getMySQLPublicKeyRetrieval() {
return config.getBoolean("MySQL.Server.allowPublicKeyRetrieval", true);
}

View File

@@ -28,8 +28,8 @@ public class DatabaseManagerFactory {
: "Flatfile") + " database");
}
return mcMMO.p.getGeneralConfig().getUseMySQL() ? new SQLDatabaseManager(logger,
MYSQL_DRIVER)
return mcMMO.p.getGeneralConfig().getUseMySQL()
? new SQLDatabaseManager(logger, MYSQL_DRIVER)
: new FlatFileDatabaseManager(userFilePath, logger, purgeTime, startingLevel);
}

View File

@@ -9,6 +9,7 @@ import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_GREEN_
import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_MACES;
import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_SERRATED_STRIKES;
import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_SKULL_SPLITTER;
import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_SPEARS;
import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_SUPER_BREAKER;
import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_SUPER_SHOTGUN;
import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_TREE_FELLER;
@@ -25,6 +26,7 @@ import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_HERBALISM;
import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_MACES;
import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_MINING;
import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_REPAIR;
import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_SPEARS;
import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_SWORDS;
import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_TAMING;
import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_TRIDENTS;
@@ -45,6 +47,7 @@ import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_HERBALIS
import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_MACES;
import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_MINING;
import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_REPAIR;
import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_SPEARS;
import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_SWORDS;
import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_TAMING;
import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_TRIDENTS;
@@ -318,27 +321,26 @@ public class FlatFileDataProcessor {
throws IndexOutOfBoundsException {
return switch (dataIndex) {
case USERNAME_INDEX ->
ExpectedType.STRING; //Assumption: Used to be for something, no longer used
//Assumption: Used to be for something, no longer used
//Assumption: Used to be used for something, no longer used
ExpectedType.STRING;
//Assumption: Used to be used for something, no longer used
case 2, 3, 23, 33, HEALTHBAR, LEGACY_LAST_LOGIN -> ExpectedType.IGNORED;
case SKILLS_MINING, SKILLS_REPAIR, SKILLS_UNARMED, SKILLS_HERBALISM, SKILLS_EXCAVATION,
SKILLS_ARCHERY,
SKILLS_SWORDS, SKILLS_AXES, SKILLS_WOODCUTTING, SKILLS_ACROBATICS, SKILLS_TAMING,
SKILLS_FISHING,
SKILLS_ALCHEMY, SKILLS_CROSSBOWS, SKILLS_TRIDENTS, SKILLS_MACES, COOLDOWN_BERSERK,
SKILLS_ALCHEMY, SKILLS_CROSSBOWS, SKILLS_TRIDENTS, SKILLS_MACES, SKILLS_SPEARS,
COOLDOWN_BERSERK,
COOLDOWN_GIGA_DRILL_BREAKER, COOLDOWN_TREE_FELLER, COOLDOWN_GREEN_TERRA,
COOLDOWN_SERRATED_STRIKES,
COOLDOWN_SKULL_SPLITTER, COOLDOWN_SUPER_BREAKER, COOLDOWN_BLAST_MINING,
SCOREBOARD_TIPS,
COOLDOWN_CHIMAERA_WING, COOLDOWN_SUPER_SHOTGUN, COOLDOWN_TRIDENTS,
COOLDOWN_ARCHERY, COOLDOWN_MACES -> ExpectedType.INTEGER;
COOLDOWN_ARCHERY, COOLDOWN_MACES, COOLDOWN_SPEARS -> ExpectedType.INTEGER;
case EXP_MINING, EXP_WOODCUTTING, EXP_REPAIR, EXP_UNARMED, EXP_HERBALISM,
EXP_EXCAVATION, EXP_ARCHERY,
EXP_SWORDS, EXP_AXES, EXP_ACROBATICS, EXP_TAMING, EXP_FISHING, EXP_ALCHEMY,
EXP_CROSSBOWS,
EXP_TRIDENTS, EXP_MACES -> ExpectedType.FLOAT;
EXP_TRIDENTS, EXP_MACES, EXP_SPEARS -> ExpectedType.FLOAT;
case UUID_INDEX -> ExpectedType.UUID;
case OVERHAUL_LAST_LOGIN -> ExpectedType.LONG;
default -> throw new IndexOutOfBoundsException();

View File

@@ -9,6 +9,7 @@ import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_GREEN_
import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_MACES;
import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_SERRATED_STRIKES;
import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_SKULL_SPLITTER;
import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_SPEARS;
import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_SUPER_BREAKER;
import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_SUPER_SHOTGUN;
import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_TREE_FELLER;
@@ -24,6 +25,7 @@ import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_HERBALISM;
import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_MACES;
import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_MINING;
import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_REPAIR;
import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_SPEARS;
import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_SWORDS;
import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_TAMING;
import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_TRIDENTS;
@@ -45,6 +47,7 @@ import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_HERBALIS
import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_MACES;
import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_MINING;
import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_REPAIR;
import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_SPEARS;
import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_SWORDS;
import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_TAMING;
import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_TRIDENTS;
@@ -114,18 +117,16 @@ public class FlatFileDataUtil {
throws IndexOutOfBoundsException {
//TODO: Add UUID recovery? Might not even be worth it.
return switch (index) {
//We'll keep using this value for legacy compatibility reasons (not sure if needed but don't care)
case USERNAME_INDEX ->
LEGACY_INVALID_OLD_USERNAME; //We'll keep using this value for legacy compatibility reasons (not sure if needed but don't care)
//Assumption: Used to be for something, no longer used
//Assumption: Used to be for something, no longer used
//Assumption: Used to be used for something, no longer used
LEGACY_INVALID_OLD_USERNAME;
//Assumption: Used to be used for something, no longer used
case 2, 3, 23, 33, LEGACY_LAST_LOGIN, HEALTHBAR -> "IGNORED";
case SKILLS_MINING, SKILLS_REPAIR, SKILLS_UNARMED, SKILLS_HERBALISM, SKILLS_EXCAVATION,
SKILLS_ARCHERY,
SKILLS_SWORDS, SKILLS_AXES, SKILLS_WOODCUTTING, SKILLS_ACROBATICS, SKILLS_TAMING,
SKILLS_FISHING,
SKILLS_ALCHEMY, SKILLS_CROSSBOWS, SKILLS_TRIDENTS, SKILLS_MACES ->
SKILLS_ALCHEMY, SKILLS_CROSSBOWS, SKILLS_TRIDENTS, SKILLS_MACES, SKILLS_SPEARS ->
String.valueOf(startingLevel);
case OVERHAUL_LAST_LOGIN -> String.valueOf(-1L);
case COOLDOWN_BERSERK, COOLDOWN_GIGA_DRILL_BREAKER, COOLDOWN_TREE_FELLER,
@@ -133,12 +134,12 @@ public class FlatFileDataUtil {
COOLDOWN_SERRATED_STRIKES, COOLDOWN_SKULL_SPLITTER, COOLDOWN_SUPER_BREAKER,
COOLDOWN_BLAST_MINING,
COOLDOWN_SUPER_SHOTGUN, COOLDOWN_TRIDENTS, COOLDOWN_ARCHERY, COOLDOWN_MACES,
SCOREBOARD_TIPS, COOLDOWN_CHIMAERA_WING,
COOLDOWN_SPEARS, SCOREBOARD_TIPS, COOLDOWN_CHIMAERA_WING,
EXP_MINING, EXP_WOODCUTTING, EXP_REPAIR, EXP_UNARMED, EXP_HERBALISM,
EXP_EXCAVATION, EXP_ARCHERY,
EXP_SWORDS, EXP_AXES, EXP_ACROBATICS, EXP_TAMING, EXP_FISHING, EXP_ALCHEMY,
EXP_CROSSBOWS,
EXP_TRIDENTS, EXP_MACES -> "0";
EXP_TRIDENTS, EXP_MACES, EXP_SPEARS -> "0";
case UUID_INDEX ->
throw new IndexOutOfBoundsException(); //TODO: Add UUID recovery? Might not even be worth it.
default -> throw new IndexOutOfBoundsException();

View File

@@ -3,7 +3,6 @@ package com.gmail.nossr50.datatypes.database;
public enum UpgradeType {
ADD_FISHING,
ADD_BLAST_MINING_COOLDOWN,
ADD_SQL_INDEXES,
ADD_MOB_HEALTHBARS,
DROP_SQL_PARTY_NAMES,
DROP_SPOUT,

View File

@@ -40,6 +40,7 @@ import com.gmail.nossr50.skills.mining.MiningManager;
import com.gmail.nossr50.skills.repair.RepairManager;
import com.gmail.nossr50.skills.salvage.SalvageManager;
import com.gmail.nossr50.skills.smelting.SmeltingManager;
import com.gmail.nossr50.skills.spears.SpearsManager;
import com.gmail.nossr50.skills.swords.SwordsManager;
import com.gmail.nossr50.skills.taming.TamingManager;
import com.gmail.nossr50.skills.tridents.TridentsManager;
@@ -63,6 +64,7 @@ import com.gmail.nossr50.util.sounds.SoundType;
import java.util.EnumMap;
import java.util.Map;
import java.util.UUID;
import java.util.logging.Level;
import net.kyori.adventure.identity.Identified;
import net.kyori.adventure.identity.Identity;
import org.bukkit.Bukkit;
@@ -171,73 +173,50 @@ public class McMMOPlayer implements Identified {
try {
initManager(primarySkillType);
} catch (InvalidSkillException e) {
e.printStackTrace();
mcMMO.p.getLogger().log(Level.SEVERE,
"Invalid skill while initializing skill managers for player "
+ player.getName()
+ ". Contact the plugin developers.", e);
}
}
}
//TODO: Add test
private void initManager(PrimarySkillType primarySkillType) throws InvalidSkillException {
switch (primarySkillType) {
case ACROBATICS:
skillManagers.put(primarySkillType, new AcrobaticsManager(this));
break;
case ALCHEMY:
skillManagers.put(primarySkillType, new AlchemyManager(this));
break;
case ARCHERY:
skillManagers.put(primarySkillType, new ArcheryManager(this));
break;
case AXES:
skillManagers.put(primarySkillType, new AxesManager(this));
break;
case CROSSBOWS:
skillManagers.put(primarySkillType, new CrossbowsManager(this));
break;
case EXCAVATION:
skillManagers.put(primarySkillType, new ExcavationManager(this));
break;
case FISHING:
skillManagers.put(primarySkillType, new FishingManager(this));
break;
case HERBALISM:
skillManagers.put(primarySkillType, new HerbalismManager(this));
break;
case MINING:
skillManagers.put(primarySkillType, new MiningManager(this));
break;
case REPAIR:
skillManagers.put(primarySkillType, new RepairManager(this));
break;
case SALVAGE:
skillManagers.put(primarySkillType, new SalvageManager(this));
break;
case SMELTING:
skillManagers.put(primarySkillType, new SmeltingManager(this));
break;
case SWORDS:
skillManagers.put(primarySkillType, new SwordsManager(this));
break;
case TAMING:
skillManagers.put(primarySkillType, new TamingManager(this));
break;
case TRIDENTS:
skillManagers.put(primarySkillType, new TridentsManager(this));
break;
case UNARMED:
skillManagers.put(primarySkillType, new UnarmedManager(this));
break;
case WOODCUTTING:
skillManagers.put(primarySkillType, new WoodcuttingManager(this));
break;
case MACES:
if (mcMMO.getCompatibilityManager().getMinecraftGameVersion().isAtLeast(1, 21, 0)) {
skillManagers.put(primarySkillType, new MacesManager(this));
}
break;
default:
throw new InvalidSkillException(
"The skill named has no manager! Contact the devs!");
final var version = mcMMO.getCompatibilityManager().getMinecraftGameVersion();
final SkillManager manager = switch (primarySkillType) {
case ACROBATICS -> new AcrobaticsManager(this);
case ALCHEMY -> new AlchemyManager(this);
case ARCHERY -> new ArcheryManager(this);
case AXES -> new AxesManager(this);
case CROSSBOWS -> new CrossbowsManager(this);
case EXCAVATION -> new ExcavationManager(this);
case FISHING -> new FishingManager(this);
case HERBALISM -> new HerbalismManager(this);
case MINING -> new MiningManager(this);
case REPAIR -> new RepairManager(this);
case SALVAGE -> new SalvageManager(this);
case SMELTING -> new SmeltingManager(this);
case SWORDS -> new SwordsManager(this);
case TAMING -> new TamingManager(this);
case TRIDENTS -> new TridentsManager(this);
case UNARMED -> new UnarmedManager(this);
case WOODCUTTING -> new WoodcuttingManager(this);
case MACES -> version.isAtLeast(1, 21, 0)
? new MacesManager(this)
: null; // keep current behavior: no manager on older versions
case SPEARS -> version.isAtLeast(1, 21, 11)
? new SpearsManager(this)
: null; // same here
};
if (manager != null) {
skillManagers.put(primarySkillType, manager);
} else {
throw new InvalidSkillException("No valid skill manager for skill: " + primarySkillType);
}
}
@@ -369,6 +348,10 @@ public class McMMOPlayer implements Identified {
return (SmeltingManager) skillManagers.get(PrimarySkillType.SMELTING);
}
public SpearsManager getSpearsManager() {
return (SpearsManager) skillManagers.get(PrimarySkillType.SPEARS);
}
public SwordsManager getSwordsManager() {
return (SwordsManager) skillManagers.get(PrimarySkillType.SWORDS);
}

View File

@@ -87,7 +87,7 @@ public class PlayerProfile {
this.loaded = isLoaded;
}
public PlayerProfile(@NotNull String playerName, UUID uuid, boolean isLoaded, int startingLvl) {
public PlayerProfile(@NotNull String playerName, @Nullable UUID uuid, boolean isLoaded, int startingLvl) {
this(playerName, uuid, startingLvl);
this.loaded = isLoaded;
}

View File

@@ -24,6 +24,7 @@ public enum PrimarySkillType {
REPAIR,
SALVAGE,
SMELTING,
SPEARS,
SWORDS,
TAMING,
TRIDENTS,

View File

@@ -83,6 +83,11 @@ public enum SubSkillType {
SMELTING_SECOND_SMELT,
SMELTING_UNDERSTANDING_THE_ART(8),
/* Spears */
SPEARS_SPEARS_LIMIT_BREAK(10),
SPEARS_MOMENTUM(10),
SPEARS_SPEAR_MASTERY(8),
/* Swords */
SWORDS_COUNTER_ATTACK(1),
SWORDS_RUPTURE(4),

View File

@@ -93,6 +93,13 @@ public enum SuperAbilityType {
"Placeholder",
"Placeholder",
"Placeholder"),
SPEARS_SUPER_ABILITY(
"Placeholder",
"Placeholder",
"Placeholder",
"Placeholder",
"Placeholder",
"Placeholder"),
/**
* Has cooldown - but has to share a skill with Super Breaker, so needs special treatment
@@ -216,8 +223,8 @@ public enum SuperAbilityType {
case SUPER_BREAKER -> Permissions.superBreaker(player);
case TREE_FELLER -> Permissions.treeFeller(player);
// TODO: once implemented, return permissions for the following abilities
case EXPLOSIVE_SHOT, TRIDENTS_SUPER_ABILITY, SUPER_SHOTGUN, MACES_SUPER_ABILITY ->
false;
case EXPLOSIVE_SHOT, TRIDENTS_SUPER_ABILITY, SUPER_SHOTGUN, MACES_SUPER_ABILITY,
SPEARS_SUPER_ABILITY -> false;
};
}

View File

@@ -168,6 +168,7 @@ public class PlayerListener implements Listener {
if (WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) {
return;
}
// world guard main flag check
if (WorldGuardUtils.isWorldGuardLoaded() && !WorldGuardManager.getInstance()
.hasMainFlag((Player) event.getEntity())) {
@@ -342,8 +343,8 @@ public class PlayerListener implements Listener {
FishingManager fishingManager = UserManager.getPlayer(player).getFishingManager();
switch (event.getState()) {
// CAUGHT_FISH happens for any item caught (including junk and treasure)
case CAUGHT_FISH:
//TODO Update to new API once available! Waiting for case CAUGHT_TREASURE
if (event.getCaught() != null) {
Item fishingCatch = (Item) event.getCaught();
@@ -675,6 +676,10 @@ public class PlayerListener implements Listener {
*/
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onPlayerInteractLowest(PlayerInteractEvent event) {
if (event.getAction() == Action.PHYSICAL) {
return;
}
/* WORLD BLACKLIST CHECK */
if (WorldBlacklist.isWorldBlacklisted(event.getPlayer().getWorld())) {
return;
@@ -817,6 +822,10 @@ public class PlayerListener implements Listener {
*/
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerInteractMonitor(PlayerInteractEvent event) {
if (event.getAction() == Action.PHYSICAL) {
return;
}
/* WORLD BLACKLIST CHECK */
if (WorldBlacklist.isWorldBlacklisted(event.getPlayer().getWorld())) {
return;

View File

@@ -0,0 +1,121 @@
package com.gmail.nossr50.skills.spears;
import static com.gmail.nossr50.util.random.ProbabilityUtil.isStaticSkillRNGSuccessful;
import static com.gmail.nossr50.util.skills.RankUtils.getRank;
import com.gmail.nossr50.datatypes.interactions.NotificationType;
import com.gmail.nossr50.datatypes.player.McMMOPlayer;
import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
import com.gmail.nossr50.datatypes.skills.SubSkillType;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.skills.SkillManager;
import com.gmail.nossr50.util.Permissions;
import com.gmail.nossr50.util.player.NotificationManager;
import java.util.Locale;
import org.bukkit.NamespacedKey;
import org.bukkit.Registry;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class SpearsManager extends SkillManager {
private static @Nullable PotionEffectType swiftnessEffectType;
public SpearsManager(McMMOPlayer mmoPlayer) {
super(mmoPlayer, PrimarySkillType.SPEARS);
}
private static @Nullable PotionEffectType mockSpigotMatch(@NotNull String input) {
// Replicates match() behaviour for older versions lacking this API
final String filtered = input.toLowerCase(Locale.ROOT).replaceAll("\\s+", "_");
final NamespacedKey namespacedKey = NamespacedKey.fromString(filtered);
return (namespacedKey != null) ? Registry.EFFECT.get(namespacedKey) : null;
}
/**
* Process Momentum activation.
*/
public void potentiallyApplyMomentum() {
// Lazy initialized to avoid some backwards compatibility issues
if (swiftnessEffectType == null) {
if (mockSpigotMatch("speed") == null) {
mcMMO.p.getLogger().severe("Unable to find the Speed PotionEffectType, " +
"mcMMO will not function properly.");
throw new IllegalStateException("Unable to find the Speed PotionEffectType!");
} else {
swiftnessEffectType = mockSpigotMatch("speed");
}
}
if (!canMomentumBeApplied()) {
return;
}
int momentumRank = getRank(getPlayer(), SubSkillType.SPEARS_MOMENTUM);
// Chance to activate on hit is influence by the CD
double momentumOdds = (mcMMO.p.getAdvancedConfig().getMomentumChanceToApplyOnHit(momentumRank)
* Math.min(mmoPlayer.getAttackStrength(), 1.0D));
if (isStaticSkillRNGSuccessful(PrimarySkillType.SPEARS, mmoPlayer, momentumOdds)) {
if (mmoPlayer.useChatNotifications()) {
NotificationManager.sendPlayerInformation(mmoPlayer.getPlayer(),
NotificationType.SUBSKILL_MESSAGE, "Spears.SubSkill.Momentum.Activated");
}
// Momentum is success, Momentum the target
getPlayer().addPotionEffect(swiftnessEffectType.createEffect(
getMomentumTickDuration(momentumRank),
getMomentumStrength()));
// TODO: Consider adding an effect here
// ParticleEffectUtils.playMomentumEffect(target);
}
}
public static int getMomentumTickDuration(int momentumRank) {
return 20 * (momentumRank * 2);
}
public static int getMomentumStrength() {
return 2;
}
private boolean canMomentumBeApplied() {
// TODO: Potentially it should overwrite the effect if we are providing a stronger one
if (swiftnessEffectType == null) {
return false;
}
final PotionEffect currentlyAppliedPotion = getPlayer()
.getPotionEffect(swiftnessEffectType);
if (currentlyAppliedPotion != null) {
if (isCurrentPotionEffectStronger(currentlyAppliedPotion)) {
return false;
}
}
if (!Permissions.canUseSubSkill(mmoPlayer.getPlayer(), SubSkillType.SPEARS_MOMENTUM)) {
return false;
}
return true;
}
private boolean isCurrentPotionEffectStronger(@NotNull PotionEffect potionEffect) {
if (potionEffect.getAmplifier() > getMomentumStrength()) {
return true;
}
if (potionEffect.getDuration() > getMomentumTickDuration(getRank(getPlayer(),
SubSkillType.SPEARS_MOMENTUM))) {
return true;
}
return false;
}
public double getSpearMasteryBonusDamage() {
return mcMMO.p.getAdvancedConfig().getSpearMasteryRankDamageMultiplier()
* getRank(getPlayer(), SubSkillType.SPEARS_SPEAR_MASTERY);
}
}

View File

@@ -166,20 +166,6 @@ public final class ItemUtils {
}
}
// TODO: Unit tests
public static boolean isCrossbow(@NotNull ItemStack item) {
return mcMMO.getMaterialMapStore().isCrossbow(item.getType().getKey().getKey());
}
// TODO: Unit tests
public static boolean isTrident(@NotNull ItemStack item) {
return mcMMO.getMaterialMapStore().isTrident(item.getType().getKey().getKey());
}
public static boolean isMace(@NotNull ItemStack item) {
return mcMMO.getMaterialMapStore().isMace(item.getType().getKey().getKey());
}
public static boolean hasItemInEitherHand(@NotNull Player player, Material material) {
return player.getInventory().getItemInMainHand().getType() == material
|| player.getInventory().getItemInOffHand().getType() == material;
@@ -276,6 +262,46 @@ public final class ItemUtils {
return null;
}
/**
* Checks if the item is a crossbow.
*
* @param item Item to check
* @return true if the item is a crossbow, false otherwise
*/
public static boolean isCrossbow(@NotNull ItemStack item) {
return mcMMO.getMaterialMapStore().isCrossbow(item.getType().getKey().getKey());
}
/**
* Checks if the item is a trident.
*
* @param item Item to check
* @return true if the item is a trident, false otherwise
*/
public static boolean isTrident(@NotNull ItemStack item) {
return mcMMO.getMaterialMapStore().isTrident(item.getType().getKey().getKey());
}
/**
* Checks if the item is a mace.
*
* @param item Item to check
* @return true if the item is a mace, false otherwise
*/
public static boolean isMace(@NotNull ItemStack item) {
return mcMMO.getMaterialMapStore().isMace(item.getType().getKey().getKey());
}
/**
* Checks if the item is a spear.
* @param item Item to check
*
* @return true if the item is a spear, false otherwise
*/
public static boolean isSpear(@NotNull ItemStack item) {
return mcMMO.getMaterialMapStore().isSpear(item.getType().getKey().getKey());
}
/**
* Checks if the item is a sword.
*

View File

@@ -8,6 +8,7 @@ public class LogUtils {
public static final String DEBUG_STR = "[D] ";
public static void debug(@NotNull Logger logger, @NotNull String message) {
// Messages here will get filtered based on config settings via LogFilter
logger.info(DEBUG_STR + message);
}
}

View File

@@ -51,9 +51,10 @@ public class MaterialMapStore {
private final @NotNull HashSet<String> tridents;
private final @NotNull HashSet<String> bows;
private final @NotNull HashSet<String> crossbows;
private final @NotNull HashSet<String> tools;
private final @NotNull HashSet<String> enchantables;
private final @NotNull HashSet<String> maces;
private final @NotNull HashSet<String> spears;
private final @NotNull HashSet<String> enchantables;
private final @NotNull HashSet<String> tools;
private final @NotNull HashSet<String> ores;
private final @NotNull HashSet<String> intendedToolPickAxe;
@@ -95,15 +96,15 @@ public class MaterialMapStore {
crossbows = new HashSet<>();
stringTools = new HashSet<>();
prismarineTools = new HashSet<>();
tools = new HashSet<>();
swords = new HashSet<>();
axes = new HashSet<>();
pickAxes = new HashSet<>();
shovels = new HashSet<>();
hoes = new HashSet<>();
tridents = new HashSet<>();
spears = new HashSet<>();
maces = new HashSet<>();
tools = new HashSet<>();
enchantables = new HashSet<>();
@@ -459,6 +460,7 @@ public class MaterialMapStore {
enchantables.addAll(bows);
enchantables.addAll(crossbows);
enchantables.addAll(maces);
enchantables.addAll(spears);
enchantables.add("shears");
enchantables.add("fishing_rod");
@@ -484,6 +486,7 @@ public class MaterialMapStore {
fillShovels();
fillTridents();
fillMaces();
fillSpears();
fillStringTools();
fillPrismarineTools();
fillBows();
@@ -502,6 +505,7 @@ public class MaterialMapStore {
tools.addAll(bows);
tools.addAll(crossbows);
tools.addAll(maces);
tools.addAll(spears);
}
private void fillBows() {
@@ -527,6 +531,16 @@ public class MaterialMapStore {
maces.add("mace");
}
private void fillSpears() {
spears.add("wooden_spear");
spears.add("stone_spear");
spears.add("copper_spear");
spears.add("iron_spear");
spears.add("golden_spear");
spears.add("diamond_spear");
spears.add("netherite_spear");
}
private void fillTridents() {
tridents.add("trident");
}
@@ -874,6 +888,14 @@ public class MaterialMapStore {
return maces.contains(id);
}
public boolean isSpear(@NotNull Material material) {
return isSpear(material.getKey().getKey());
}
public boolean isSpear(@NotNull String id) {
return spears.contains(id);
}
public boolean isLeatherArmor(@NotNull Material material) {
return isLeatherArmor(material.getKey().getKey());
}

View File

@@ -41,6 +41,7 @@ import com.gmail.nossr50.commands.skills.MmoInfoCommand;
import com.gmail.nossr50.commands.skills.RepairCommand;
import com.gmail.nossr50.commands.skills.SalvageCommand;
import com.gmail.nossr50.commands.skills.SmeltingCommand;
import com.gmail.nossr50.commands.skills.SpearsCommand;
import com.gmail.nossr50.commands.skills.SwordsCommand;
import com.gmail.nossr50.commands.skills.TamingCommand;
import com.gmail.nossr50.commands.skills.TridentsCommand;
@@ -101,6 +102,7 @@ public final class CommandRegistrationManager {
case REPAIR -> command.setExecutor(new RepairCommand());
case SALVAGE -> command.setExecutor(new SalvageCommand());
case SMELTING -> command.setExecutor(new SmeltingCommand());
case SPEARS -> command.setExecutor(new SpearsCommand());
case SWORDS -> command.setExecutor(new SwordsCommand());
case TAMING -> command.setExecutor(new TamingCommand());
case TRIDENTS -> command.setExecutor(new TridentsCommand());

View File

@@ -3,6 +3,7 @@ package com.gmail.nossr50.util.skills;
import static com.gmail.nossr50.datatypes.experience.XPGainReason.PVP;
import static com.gmail.nossr50.util.AttributeMapper.MAPPED_MOVEMENT_SPEED;
import static com.gmail.nossr50.util.MobMetadataUtils.hasMobFlag;
import static com.gmail.nossr50.util.Permissions.canUseSubSkill;
import static com.gmail.nossr50.util.skills.ProjectileUtils.isCrossbowProjectile;
import com.gmail.nossr50.config.experience.ExperienceConfig;
@@ -19,6 +20,7 @@ import com.gmail.nossr50.skills.acrobatics.AcrobaticsManager;
import com.gmail.nossr50.skills.archery.ArcheryManager;
import com.gmail.nossr50.skills.axes.AxesManager;
import com.gmail.nossr50.skills.maces.MacesManager;
import com.gmail.nossr50.skills.spears.SpearsManager;
import com.gmail.nossr50.skills.swords.SwordsManager;
import com.gmail.nossr50.skills.taming.TamingManager;
import com.gmail.nossr50.skills.tridents.TridentsManager;
@@ -331,6 +333,46 @@ public final class CombatUtils {
printFinalDamageDebug(player, event, mmoPlayer);
}
private static void processSpearsCombat(@NotNull LivingEntity target,
@NotNull Player player,
@NotNull EntityDamageByEntityEvent event) {
if (event.getCause() == DamageCause.THORNS) {
return;
}
double boostedDamage = event.getDamage();
final McMMOPlayer mmoPlayer = UserManager.getPlayer(player);
//Make sure the profiles been loaded
if (mmoPlayer == null) {
return;
}
final SpearsManager spearsManager = mmoPlayer.getSpearsManager();
if (canUseSubSkill(player, SubSkillType.SPEARS_SPEAR_MASTERY)) {
boostedDamage += spearsManager.getSpearMasteryBonusDamage()
* mmoPlayer.getAttackStrength();
}
// Apply Limit Break DMG
if (canUseLimitBreak(player, target, SubSkillType.SPEARS_SPEARS_LIMIT_BREAK)) {
boostedDamage += (getLimitBreakDamage(
player, target, SubSkillType.SPEARS_SPEARS_LIMIT_BREAK)
* mmoPlayer.getAttackStrength());
}
event.setDamage(boostedDamage);
// Apply any non-damage effects here
spearsManager.potentiallyApplyMomentum();
processCombatXP(mmoPlayer, target, PrimarySkillType.SPEARS);
printFinalDamageDebug(player, event, mmoPlayer);
}
private static void processAxeCombat(@NotNull LivingEntity target, @NotNull Player player,
@NotNull EntityDamageByEntityEvent event) {
if (event.getCause() == DamageCause.THORNS) {
@@ -391,6 +433,11 @@ public final class CombatUtils {
double boostedDamage = event.getDamage();
// TODO: Temporary hack to avoid unintended spear / unarmed interactions
if (ItemUtils.isSpear(player.getInventory().getItemInOffHand())) {
return;
}
final McMMOPlayer mmoPlayer = UserManager.getPlayer(player);
//Make sure the profiles been loaded
@@ -642,6 +689,15 @@ public final class CombatUtils {
.doesPlayerHaveSkillPermission(player, PrimarySkillType.MACES)) {
processMacesCombat(target, player, event);
}
} else if (ItemUtils.isSpear(heldItem)) {
if (!mcMMO.p.getSkillTools()
.canCombatSkillsTrigger(PrimarySkillType.SPEARS, target)) {
return;
}
if (mcMMO.p.getSkillTools()
.doesPlayerHaveSkillPermission(player, PrimarySkillType.SPEARS)) {
processSpearsCombat(target, player, event);
}
}
} else if (entityType == EntityType.WOLF) {
Wolf wolf = (Wolf) painSource;

View File

@@ -1,6 +1,5 @@
package com.gmail.nossr50.util.skills;
import com.gmail.nossr50.api.exceptions.InvalidSkillException;
import com.gmail.nossr50.config.experience.ExperienceConfig;
import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
import com.gmail.nossr50.datatypes.skills.SubSkillType;
@@ -18,6 +17,7 @@ import java.util.Collections;
import java.util.EnumMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
@@ -27,15 +27,16 @@ import org.jetbrains.annotations.VisibleForTesting;
public class SkillTools {
private final mcMMO pluginRef;
// TODO: Java has immutable types now, switch to those
// TODO: Figure out which ones we don't need, this was copy pasted from a diff branch
public final @NotNull ImmutableList<String> LOCALIZED_SKILL_NAMES;
public final @NotNull ImmutableList<String> FORMATTED_SUBSKILL_NAMES;
public final @NotNull ImmutableSet<String> EXACT_SUBSKILL_NAMES;
public final @NotNull ImmutableList<PrimarySkillType> CHILD_SKILLS;
public final static @NotNull ImmutableList<PrimarySkillType> NON_CHILD_SKILLS;
public final static @NotNull ImmutableList<PrimarySkillType> SALVAGE_PARENTS;
public final static @NotNull ImmutableList<PrimarySkillType> SMELTING_PARENTS;
public static final @NotNull ImmutableList<PrimarySkillType> NON_CHILD_SKILLS;
public static final @NotNull ImmutableList<PrimarySkillType> SALVAGE_PARENTS;
public static final @NotNull ImmutableList<PrimarySkillType> SMELTING_PARENTS;
public final @NotNull ImmutableList<PrimarySkillType> COMBAT_SKILLS;
public final @NotNull ImmutableList<PrimarySkillType> GATHERING_SKILLS;
public final @NotNull ImmutableList<PrimarySkillType> MISC_SKILLS;
@@ -44,73 +45,141 @@ public class SkillTools {
private final @NotNull ImmutableMap<SuperAbilityType, PrimarySkillType> superAbilityParentRelationshipMap;
private final @NotNull ImmutableMap<PrimarySkillType, Set<SubSkillType>> primarySkillChildrenMap;
// The map below is for the super abilities which require readying a tool, its everything except blast mining
private final ImmutableMap<PrimarySkillType, SuperAbilityType> mainActivatedAbilityChildMap;
private final ImmutableMap<PrimarySkillType, ToolType> primarySkillToolMap;
static {
// Build NON_CHILD_SKILLS once from the enum values
ArrayList<PrimarySkillType> tempNonChildSkills = new ArrayList<>();
for (PrimarySkillType primarySkillType : PrimarySkillType.values()) {
if (primarySkillType != PrimarySkillType.SALVAGE
&& primarySkillType != PrimarySkillType.SMELTING) {
if (!isChildSkill(primarySkillType)) {
tempNonChildSkills.add(primarySkillType);
}
}
NON_CHILD_SKILLS = ImmutableList.copyOf(tempNonChildSkills);
SALVAGE_PARENTS = ImmutableList.of(PrimarySkillType.REPAIR, PrimarySkillType.FISHING);
SMELTING_PARENTS = ImmutableList.of(PrimarySkillType.MINING, PrimarySkillType.REPAIR);
SALVAGE_PARENTS = ImmutableList.of(
PrimarySkillType.REPAIR,
PrimarySkillType.FISHING
);
SMELTING_PARENTS = ImmutableList.of(
PrimarySkillType.MINING,
PrimarySkillType.REPAIR
);
}
public SkillTools(@NotNull mcMMO pluginRef) throws InvalidSkillException {
public SkillTools(@NotNull mcMMO pluginRef) {
this.pluginRef = pluginRef;
/*
* Setup subskill -> parent relationship map
*/
EnumMap<SubSkillType, PrimarySkillType> tempSubParentMap = new EnumMap<>(
SubSkillType.class);
//Super hacky and disgusting
for (PrimarySkillType primarySkillType1 : PrimarySkillType.values()) {
for (SubSkillType subSkillType : SubSkillType.values()) {
String[] splitSubSkillName = subSkillType.toString().split("_");
if (primarySkillType1.toString().equalsIgnoreCase(splitSubSkillName[0])) {
//Parent Skill Found
tempSubParentMap.put(subSkillType, primarySkillType1);
}
}
}
subSkillParentRelationshipMap = ImmutableMap.copyOf(tempSubParentMap);
this.subSkillParentRelationshipMap = buildSubSkillParentMap();
/*
* Setup primary -> (collection) subskill map
*/
EnumMap<PrimarySkillType, Set<SubSkillType>> tempPrimaryChildMap = new EnumMap<>(
PrimarySkillType.class);
//Init the empty Hash Sets
for (PrimarySkillType primarySkillType1 : PrimarySkillType.values()) {
tempPrimaryChildMap.put(primarySkillType1, new HashSet<>());
}
//Fill in the hash sets
for (SubSkillType subSkillType : SubSkillType.values()) {
PrimarySkillType parentSkill = subSkillParentRelationshipMap.get(subSkillType);
//Add this subskill as a child
tempPrimaryChildMap.get(parentSkill).add(subSkillType);
}
primarySkillChildrenMap = ImmutableMap.copyOf(tempPrimaryChildMap);
this.primarySkillChildrenMap = buildPrimarySkillChildrenMap(subSkillParentRelationshipMap);
/*
* Setup primary -> tooltype map
*/
EnumMap<PrimarySkillType, ToolType> tempToolMap = new EnumMap<>(PrimarySkillType.class);
this.primarySkillToolMap = buildPrimarySkillToolMap();
/*
* Setup ability -> primary map
* Setup primary -> ability map
*/
var abilityMaps = buildSuperAbilityMaps();
this.superAbilityParentRelationshipMap = abilityMaps.superAbilityParentRelationshipMap();
this.mainActivatedAbilityChildMap = abilityMaps.mainActivatedAbilityChildMap();
/*
* Build child skill list
*/
this.CHILD_SKILLS = buildChildSkills();
/*
* Build categorized skill lists
*/
this.COMBAT_SKILLS = buildCombatSkills();
this.GATHERING_SKILLS = ImmutableList.of(
PrimarySkillType.EXCAVATION,
PrimarySkillType.FISHING,
PrimarySkillType.HERBALISM,
PrimarySkillType.MINING,
PrimarySkillType.WOODCUTTING
);
this.MISC_SKILLS = ImmutableList.of(
PrimarySkillType.ACROBATICS,
PrimarySkillType.ALCHEMY,
PrimarySkillType.REPAIR,
PrimarySkillType.SALVAGE,
PrimarySkillType.SMELTING
);
/*
* Build formatted/localized/etc string lists
*/
this.LOCALIZED_SKILL_NAMES = ImmutableList.copyOf(buildLocalizedPrimarySkillNames());
this.FORMATTED_SUBSKILL_NAMES = ImmutableList.copyOf(buildFormattedSubSkillNameList());
this.EXACT_SUBSKILL_NAMES = ImmutableSet.copyOf(buildExactSubSkillNameList());
}
@VisibleForTesting
@NotNull
ImmutableMap<SubSkillType, PrimarySkillType> buildSubSkillParentMap() {
EnumMap<SubSkillType, PrimarySkillType> tempSubParentMap =
new EnumMap<>(SubSkillType.class);
// SubSkillType names use a convention: <PRIMARY>_SOMETHING
for (SubSkillType subSkillType : SubSkillType.values()) {
String enumName = subSkillType.name();
int underscoreIndex = enumName.indexOf('_');
String parentPrefix = underscoreIndex == -1
? enumName
: enumName.substring(0, underscoreIndex);
for (PrimarySkillType primarySkillType : PrimarySkillType.values()) {
if (primarySkillType.name().equalsIgnoreCase(parentPrefix)) {
tempSubParentMap.put(subSkillType, primarySkillType);
break;
}
}
}
return ImmutableMap.copyOf(tempSubParentMap);
}
@VisibleForTesting
@NotNull
ImmutableMap<PrimarySkillType, Set<SubSkillType>> buildPrimarySkillChildrenMap(
ImmutableMap<SubSkillType, PrimarySkillType> subParentMap) {
EnumMap<PrimarySkillType, Set<SubSkillType>> tempPrimaryChildMap =
new EnumMap<>(PrimarySkillType.class);
// Initialize empty sets
for (PrimarySkillType primarySkillType : PrimarySkillType.values()) {
tempPrimaryChildMap.put(primarySkillType, new HashSet<>());
}
// Fill sets
for (SubSkillType subSkillType : SubSkillType.values()) {
PrimarySkillType parentSkill = subParentMap.get(subSkillType);
if (parentSkill != null) {
tempPrimaryChildMap.get(parentSkill).add(subSkillType);
}
}
return ImmutableMap.copyOf(tempPrimaryChildMap);
}
@VisibleForTesting
@NotNull
ImmutableMap<PrimarySkillType, ToolType> buildPrimarySkillToolMap() {
EnumMap<PrimarySkillType, ToolType> tempToolMap =
new EnumMap<>(PrimarySkillType.class);
tempToolMap.put(PrimarySkillType.AXES, ToolType.AXE);
tempToolMap.put(PrimarySkillType.WOODCUTTING, ToolType.AXE);
@@ -120,56 +189,76 @@ public class SkillTools {
tempToolMap.put(PrimarySkillType.HERBALISM, ToolType.HOE);
tempToolMap.put(PrimarySkillType.MINING, ToolType.PICKAXE);
primarySkillToolMap = ImmutableMap.copyOf(tempToolMap);
return ImmutableMap.copyOf(tempToolMap);
}
/*
* Setup ability -> primary map
* Setup primary -> ability map
*/
/**
* Holder for the two super ability maps, so we can build them in one pass.
*/
@VisibleForTesting
record SuperAbilityMaps(
@NotNull ImmutableMap<SuperAbilityType, PrimarySkillType> superAbilityParentRelationshipMap,
@NotNull ImmutableMap<PrimarySkillType, SuperAbilityType> mainActivatedAbilityChildMap) {
}
EnumMap<SuperAbilityType, PrimarySkillType> tempAbilityParentRelationshipMap = new EnumMap<>(
SuperAbilityType.class);
EnumMap<PrimarySkillType, SuperAbilityType> tempMainActivatedAbilityChildMap = new EnumMap<>(
PrimarySkillType.class);
@VisibleForTesting
@NotNull
SuperAbilityMaps buildSuperAbilityMaps() {
final Map<SuperAbilityType, PrimarySkillType> tempAbilityParentRelationshipMap =
new EnumMap<>(SuperAbilityType.class);
final Map<PrimarySkillType, SuperAbilityType> tempMainActivatedAbilityChildMap =
new EnumMap<>(PrimarySkillType.class);
for (SuperAbilityType superAbilityType : SuperAbilityType.values()) {
try {
PrimarySkillType parent = getSuperAbilityParent(superAbilityType);
tempAbilityParentRelationshipMap.put(superAbilityType, parent);
final PrimarySkillType parent = getSuperAbilityParent(superAbilityType);
tempAbilityParentRelationshipMap.put(superAbilityType, parent);
if (superAbilityType != SuperAbilityType.BLAST_MINING) {
//This map is used only for abilities that have a tool readying phase, so blast mining is ignored
tempMainActivatedAbilityChildMap.put(parent, superAbilityType);
}
} catch (InvalidSkillException e) {
e.printStackTrace();
// This map is used only for abilities that have a tool readying phase,
// so Blast Mining is ignored.
if (superAbilityType != SuperAbilityType.BLAST_MINING) {
tempMainActivatedAbilityChildMap.put(parent, superAbilityType);
}
}
superAbilityParentRelationshipMap = ImmutableMap.copyOf(tempAbilityParentRelationshipMap);
mainActivatedAbilityChildMap = ImmutableMap.copyOf(tempMainActivatedAbilityChildMap);
/*
* Build child skill and nonchild skill lists
*/
return new SuperAbilityMaps(
ImmutableMap.copyOf(tempAbilityParentRelationshipMap),
ImmutableMap.copyOf(tempMainActivatedAbilityChildMap)
);
}
@VisibleForTesting
@NotNull
ImmutableList<PrimarySkillType> buildChildSkills() {
List<PrimarySkillType> childSkills = new ArrayList<>();
for (PrimarySkillType primarySkillType : PrimarySkillType.values()) {
if (isChildSkill(primarySkillType)) {
childSkills.add(primarySkillType);
}
}
return ImmutableList.copyOf(childSkills);
}
CHILD_SKILLS = ImmutableList.copyOf(childSkills);
@VisibleForTesting
@NotNull
ImmutableList<PrimarySkillType> buildCombatSkills() {
var gameVersion = mcMMO.getCompatibilityManager().getMinecraftGameVersion();
/*
* Build categorized skill lists
*/
// We are in a game version with Maces
if (mcMMO.getCompatibilityManager().getMinecraftGameVersion().isAtLeast(1, 21, 0)) {
COMBAT_SKILLS = ImmutableList.of(
if (gameVersion.isAtLeast(1, 21, 11)) {
// We are in a game version with Spears and Maces
return ImmutableList.of(
PrimarySkillType.ARCHERY,
PrimarySkillType.AXES,
PrimarySkillType.CROSSBOWS,
PrimarySkillType.MACES,
PrimarySkillType.SWORDS,
PrimarySkillType.SPEARS,
PrimarySkillType.TAMING,
PrimarySkillType.TRIDENTS,
PrimarySkillType.UNARMED
);
} else if (gameVersion.isAtLeast(1, 21, 0)) {
// We are in a game version with Maces
return ImmutableList.of(
PrimarySkillType.ARCHERY,
PrimarySkillType.AXES,
PrimarySkillType.CROSSBOWS,
@@ -177,42 +266,23 @@ public class SkillTools {
PrimarySkillType.SWORDS,
PrimarySkillType.TAMING,
PrimarySkillType.TRIDENTS,
PrimarySkillType.UNARMED);
PrimarySkillType.UNARMED
);
} else {
// No Maces in this version
COMBAT_SKILLS = ImmutableList.of(
return ImmutableList.of(
PrimarySkillType.ARCHERY,
PrimarySkillType.AXES,
PrimarySkillType.CROSSBOWS,
PrimarySkillType.SWORDS,
PrimarySkillType.TAMING,
PrimarySkillType.TRIDENTS,
PrimarySkillType.UNARMED);
PrimarySkillType.UNARMED
);
}
GATHERING_SKILLS = ImmutableList.of(
PrimarySkillType.EXCAVATION,
PrimarySkillType.FISHING,
PrimarySkillType.HERBALISM,
PrimarySkillType.MINING,
PrimarySkillType.WOODCUTTING);
MISC_SKILLS = ImmutableList.of(
PrimarySkillType.ACROBATICS,
PrimarySkillType.ALCHEMY,
PrimarySkillType.REPAIR,
PrimarySkillType.SALVAGE,
PrimarySkillType.SMELTING);
/*
* Build formatted/localized/etc string lists
*/
LOCALIZED_SKILL_NAMES = ImmutableList.copyOf(buildLocalizedPrimarySkillNames());
FORMATTED_SUBSKILL_NAMES = ImmutableList.copyOf(buildFormattedSubSkillNameList());
EXACT_SUBSKILL_NAMES = ImmutableSet.copyOf(buildExactSubSkillNameList());
}
private @NotNull PrimarySkillType getSuperAbilityParent(SuperAbilityType superAbilityType)
throws InvalidSkillException {
private @NotNull PrimarySkillType getSuperAbilityParent(SuperAbilityType superAbilityType) {
return switch (superAbilityType) {
case BERSERK -> PrimarySkillType.UNARMED;
case GREEN_TERRA -> PrimarySkillType.HERBALISM;
@@ -225,11 +295,12 @@ public class SkillTools {
case TRIDENTS_SUPER_ABILITY -> PrimarySkillType.TRIDENTS;
case EXPLOSIVE_SHOT -> PrimarySkillType.ARCHERY;
case MACES_SUPER_ABILITY -> PrimarySkillType.MACES;
case SPEARS_SUPER_ABILITY -> PrimarySkillType.SPEARS;
};
}
/**
* Makes a list of the "nice" version of sub skill names Used in tab completion mostly
* Makes a list of the "nice" version of sub skill names. Used in tab completion mostly.
*
* @return a list of formatted sub skill names
*/
@@ -272,9 +343,12 @@ public class SkillTools {
}
/**
* Matches a string of a skill to a skill This is NOT case sensitive First it checks the locale
* file and tries to match by the localized name of the skill Then if nothing is found it checks
* against the hard coded "name" of the skill, which is just its name in English
* Matches a string of a skill to a skill.
* This is NOT case-sensitive.
* <p>
* First it checks the locale file and tries to match by the localized name of the skill.
* Then if nothing is found it checks against the hard coded "name" of the skill,
* which is just its name in English.
*
* @param skillName target skill name
* @return the matching PrimarySkillType if one is found, otherwise null
@@ -282,8 +356,9 @@ public class SkillTools {
public PrimarySkillType matchSkill(String skillName) {
if (!pluginRef.getGeneralConfig().getLocale().equalsIgnoreCase("en_US")) {
for (PrimarySkillType type : PrimarySkillType.values()) {
if (skillName.equalsIgnoreCase(LocaleLoader.getString(
StringUtils.getCapitalized(type.name()) + ".SkillName"))) {
String localized = LocaleLoader.getString(
StringUtils.getCapitalized(type.name()) + ".SkillName");
if (skillName.equalsIgnoreCase(localized)) {
return type;
}
}
@@ -297,15 +372,15 @@ public class SkillTools {
if (!skillName.equalsIgnoreCase("all")) {
pluginRef.getLogger()
.warning("Invalid mcMMO skill (" + skillName + ")"); //TODO: Localize
.warning("Invalid mcMMO skill (" + skillName + ")"); // TODO: Localize
}
return null;
}
/**
* Gets the PrimarySkillStype to which a SubSkillType belongs Return null if it does not belong
* to one.. which should be impossible in most circumstances
* Gets the PrimarySkillType to which a SubSkillType belongs.
* Returns null if it does not belong to one (which should be impossible in most circumstances).
*
* @param subSkillType target subskill
* @return the PrimarySkillType of this SubSkill, null if it doesn't exist
@@ -315,8 +390,8 @@ public class SkillTools {
}
/**
* Gets the PrimarySkillStype to which a SuperAbilityType belongs Return null if it does not
* belong to one.. which should be impossible in most circumstances
* Gets the PrimarySkillType to which a SuperAbilityType belongs.
* Returns null if it does not belong to one (which should be impossible in most circumstances).
*
* @param superAbilityType target super ability
* @return the PrimarySkillType of this SuperAbilityType, null if it doesn't exist
@@ -326,16 +401,15 @@ public class SkillTools {
}
public SuperAbilityType getSuperAbility(PrimarySkillType primarySkillType) {
if (mainActivatedAbilityChildMap.get(primarySkillType) == null) {
return null;
}
return mainActivatedAbilityChildMap.get(primarySkillType);
}
public boolean isSuperAbilityUnlocked(PrimarySkillType primarySkillType, Player player) {
SuperAbilityType superAbilityType = mcMMO.p.getSkillTools()
.getSuperAbility(primarySkillType);
SuperAbilityType superAbilityType = getSuperAbility(primarySkillType);
if (superAbilityType == null) {
return false;
}
SubSkillType subSkillType = superAbilityType.getSubSkillTypeDefinition();
return RankUtils.hasUnlockedSubskill(player, subSkillType);
}
@@ -368,7 +442,6 @@ public class SkillTools {
return ExperienceConfig.getInstance().getFormulaSkillModifier(primarySkillType);
}
// TODO: This is a little "hacky", we probably need to add something to distinguish child skills in the enum, or to use another enum for them
public static boolean isChildSkill(PrimarySkillType primarySkillType) {
return switch (primarySkillType) {
case SALVAGE, SMELTING -> true;
@@ -392,8 +465,10 @@ public class SkillTools {
}
public boolean canCombatSkillsTrigger(PrimarySkillType primarySkillType, Entity target) {
return (target instanceof Player || (target instanceof Tameable
&& ((Tameable) target).isTamed())) ? getPVPEnabled(primarySkillType)
boolean isPlayerOrTamed = (target instanceof Player)
|| (target instanceof Tameable && ((Tameable) target).isTamed());
return isPlayerOrTamed
? getPVPEnabled(primarySkillType)
: getPVEEnabled(primarySkillType);
}
@@ -410,7 +485,7 @@ public class SkillTools {
}
public int getLevelCap(@NotNull PrimarySkillType primarySkillType) {
return mcMMO.p.getGeneralConfig().getLevelCap(primarySkillType);
return pluginRef.getGeneralConfig().getLevelCap(primarySkillType);
}
/**
@@ -445,17 +520,12 @@ public class SkillTools {
}
public @NotNull ImmutableList<PrimarySkillType> getChildSkillParents(
PrimarySkillType childSkill)
throws IllegalArgumentException {
switch (childSkill) {
case SALVAGE -> {
return SALVAGE_PARENTS;
}
case SMELTING -> {
return SMELTING_PARENTS;
}
PrimarySkillType childSkill) throws IllegalArgumentException {
return switch (childSkill) {
case SALVAGE -> SALVAGE_PARENTS;
case SMELTING -> SMELTING_PARENTS;
default -> throw new IllegalArgumentException(
"Skill " + childSkill + " is not a child skill");
}
};
}
}

View File

@@ -544,7 +544,25 @@ public class TextComponentFactory {
componentBuilder.append(Component.newline());
}
/**
* @deprecated use appendSubSkillTextComponents(Player, List<Component>, PrimarySkillType)
* @param player target player
* @param textComponents list to append to
* @param parentSkill the parent skill
*/
@Deprecated(since = "2.2.046", forRemoval = true)
public static void getSubSkillTextComponents(Player player, List<Component> textComponents,
PrimarySkillType parentSkill) {
appendSubSkillTextComponents(player, textComponents, parentSkill);
}
/**
* Appends sub-skill text components to a list for a given parent skill
* @param player target player
* @param textComponents list to append to
* @param parentSkill the parent skill
*/
public static void appendSubSkillTextComponents(Player player, List<Component> textComponents,
PrimarySkillType parentSkill) {
for (SubSkillType subSkillType : SubSkillType.values()) {
if (subSkillType.getParentSkill() == parentSkill) {

View File

@@ -647,4 +647,19 @@ Skills:
Rank_1: 10
Rank_2: 15
Rank_3: 20
Rank_4: 33
Rank_4: 33
Spears:
SpearMastery:
Rank_Damage_Multiplier: 0.4
Momentum:
Chance_To_Apply_On_Hit:
Rank_1: 5
Rank_2: 10
Rank_3: 15
Rank_4: 20
Rank_5: 25
Rank_6: 30
Rank_7: 35
Rank_8: 40
Rank_9: 45
Rank_10: 50

View File

@@ -229,6 +229,7 @@ Hardcore:
Tridents: false
Crossbows: false
Maces: false
Spears: false
Vampirism:
Leech_Percentage: 5.0
Level_Threshold: 0
@@ -249,6 +250,7 @@ Hardcore:
Tridents: false
Crossbows: false
Maces: false
Spears: false
#
# Settings for SMP Mods
@@ -427,6 +429,10 @@ Skills:
Enabled_For_PVP: true
Enabled_For_PVE: true
Level_Cap: 0
Spears:
Enabled_For_PVP: true
Enabled_For_PVE: true
Level_Cap: 0
Taming:
Enabled_For_PVP: true
Enabled_For_PVE: true

View File

@@ -95,6 +95,10 @@ Experience_Bars:
Enable: true
Color: BLUE
BarStyle: SEGMENTED_6
Spears:
Enable: true
Color: BLUE
BarStyle: SEGMENTED_6
Repair:
Enable: true
Color: PURPLE
@@ -167,6 +171,7 @@ Experience_Formula:
# Experience gained will get multiplied by these values. 1.0 by default, 0.5 means half XP gained. This happens right before multiplying the XP by the global multiplier.
Skill_Multiplier:
Spears: 1.0
Maces: 1.0
Crossbows: 1.0
Tridents: 1.0
@@ -218,6 +223,7 @@ Diminished_Returns:
Crossbows: 20000
Tridents: 20000
Maces: 20000
Spears: 20000
Time_Interval: 10
@@ -582,6 +588,7 @@ Experience_Values:
Taming:
Animal_Taming:
Camel: 1300
Camel_Husk: 1300
Sniffer: 1500
Snifflet: 900
Llama: 1200
@@ -600,12 +607,15 @@ Experience_Values:
Goat: 250
Axolotl: 600
Frog: 900
Nautilus: 1700
Zombie_Nautilus: 1700
Combat:
Multiplier:
Animals: 1.0
Armadillo: 1.1
Creeper: 4.0
Skeleton: 3.0
Parched: 2.5
Spider: 2.0
Giant: 4.0
Zombie: 2.0
@@ -683,6 +693,7 @@ Experience_Values:
Sniffer: 1.1
Snifflet: 1.1
Camel: 1.2
Camel_Husk: 1.25
Bogged: 2.0
Breeze: 4.0
Armor_Stand: 0.0

View File

@@ -27,6 +27,7 @@ JSON.Salvage=Salvage
JSON.Swords=Swords
JSON.Taming=Taming
JSON.Tridents=Tridents
JSON.Spears=Spears
JSON.Maces=Maces
JSON.Unarmed=Unarmed
JSON.Woodcutting=Woodcutting
@@ -98,6 +99,7 @@ Overhaul.Name.Smelting=Smelting
Overhaul.Name.Swords=Swords
Overhaul.Name.Taming=Taming
Overhaul.Name.Tridents=Tridents
Overhaul.Name.Spears=Spears
Overhaul.Name.Maces=Maces
Overhaul.Name.Unarmed=Unarmed
Overhaul.Name.Woodcutting=Woodcutting
@@ -125,6 +127,7 @@ XPBar.Smelting=Smelting Lv.&6{0}
XPBar.Swords=Swords Lv.&6{0}
XPBar.Taming=Taming Lv.&6{0}
XPBar.Tridents=Tridents Lv.&6{0}
XPBar.Spears=Spears Lv.&6{0}
XPBar.Maces=Maces Lv.&6{0}
XPBar.Unarmed=Unarmed Lv.&6{0}
XPBar.Woodcutting=Woodcutting Lv.&6{0}
@@ -474,6 +477,24 @@ Maces.SubSkill.Cripple.Stat=Cripple Chance
Maces.SubSkill.Cripple.Stat.Extra=[[DARK_AQUA]]Cripple Duration: &e{0}s&a vs Players, &e{1}s&a vs Mobs.
Maces.Listener=Maces:
#SPEARS
Spears.SkillName=SPEARS
Spears.Ability.Lower=&7You lower your spear.
Spears.Ability.Ready=&3You &6ready&3 your spear.
Spears.SubSkill.SpearsLimitBreak.Name=Spears Limit Break
Spears.SubSkill.SpearsLimitBreak.Description=Breaking your limits. Increased damage against tough opponents. Intended for PVP, up to server settings for whether it will boost damage in PVE.
Spears.SubSkill.SpearsLimitBreak.Stat=Limit Break Max DMG
Spears.SubSkill.SpearAbility.Name=WIP
Spears.SubSkill.Momentum.Name=Momentum
Spears.SubSkill.Momentum.Description=Adds a chance to increase movement speed for a short duration when attacking.
Spears.SubSkill.Momentum.Stat=Momentum Chance
Spears.SubSkill.Momentum.Stat.Extra=[[DARK_AQUA]]Momentum Duration: &e{0}s
Spears.SubSkill.Momentum.Activated=MOMENTUM ACTIVATED!
Spears.SubSkill.SpearMastery.Name=Spear Mastery
Spears.SubSkill.SpearMastery.Description=Adds bonus damage to your attacks.
Spears.SubSkill.SpearMastery.Stat=Spear Mastery Bonus DMG
Spears.Listener=Spears:
#SWORDS
Swords.Ability.Lower=&7You lower your sword.
Swords.Ability.Ready=&3You &6ready&3 your Sword.
@@ -913,6 +934,7 @@ Commands.XPGain.Repair=Repairing
Commands.XPGain.Swords=Attacking Monsters
Commands.XPGain.Taming=Animal Taming, or combat w/ your wolves
Commands.XPGain.Tridents=Attacking Monsters
Commands.XPGain.Spears=Attacking Monsters
Commands.XPGain.Unarmed=Attacking Monsters
Commands.XPGain.Woodcutting=Chopping down trees
Commands.XPGain=&8XP GAIN: &f{0}
@@ -1047,12 +1069,12 @@ Guides.Woodcutting.Section.1=&3How does Tree Feller work?\n&eTree Feller is an a
Guides.Woodcutting.Section.2=&3How does Leaf Blower work?\n&eLeaf Blower is a passive ability that will cause leaf\n&eblocks to break instantly when hit with an axe. By default,\n&ethis ability unlocks at level 100.
Guides.Woodcutting.Section.3=&3How do Double Drops work?\n&eThis passive ability gives you a chance to obtain an extra\n&eblock for every log you chop.
# Crossbows
Guides.Crossbows.Section.0=&3About Crossbows:\n&eCrossbows is all about shooting with your crossbow.\n\n&3XP GAIN:\n&eXP is gained whenever you shoot mobs with a crossbow.\nThis is a WIP skill and more information will be added soon.
Guides.Crossbows.Section.0=&3About Crossbows:\n&eCrossbows is all about shooting with your crossbow.\n\n&3XP GAIN:\n&eXP is gained whenever you shoot mobs with a crossbow.
Guides.Crossbows.Section.1=&3How does Trickshot work?\n&eTrickshot is an passive ability, you shoot your bolts at a shallow angle with a crossbow to attempt a Trickshot. This will cause the arrow to ricochet off of blocks and potentially hit a target. The number of potential bounces from a ricochet depend on the rank of Trickshot.
# Tridents
Guides.Tridents.Section.0=&3About Tridents:\n&eTridents skill involves impaling foes with your trident.\n\n&3XP GAIN:\n&eXP is gained whenever you hit mobs with a trident.\nThis is a WIP skill and more information will be added soon.
Guides.Maces.Section.0=&3About Maces:\n&eMaces is all about smashing your foes with a mace.\n\n&3XP GAIN:\n&eXP is gained whenever you hit mobs with a mace.\nThis is a WIP skill and more information will be added soon.
Guides.Tridents.Section.0=&3About Tridents:\n&eTridents skill involves impaling foes with your trident.\n\n&3XP GAIN:\n&eXP is gained whenever you hit mobs with a trident.
Guides.Maces.Section.0=&3About Maces:\n&eMaces is all about smashing your foes with a mace.\n\n&3XP GAIN:\n&eXP is gained whenever you hit mobs with a mace.
Guides.Spears.Section.0=&3About Spears:\n&eSpears is all about impaling your foes with a spear.\n\n&3XP GAIN:\n&eXP is gained whenever you hit mobs with a spear.
#INSPECT
Inspect.Offline= &cYou do not have permission to inspect offline players!
Inspect.OfflineStats=mcMMO Stats for Offline Player &e{0}

View File

@@ -1,20 +1,20 @@
name: mcMMO
version: ${project.version}
description: >
The goal of mcMMO is to take core Minecraft game mechanics and expand them into
add an extensive and quality RPG experience. Everything in mcMMO has been carefully
thought out and is constantly being improved upon. Currently, mcMMO adds thirteen
unique skills to train and level in. Each of these skills is highly customizable
through our configuration files, allowing server admins to tweak mcMMO to best suit
the needs of his or her server. Know that the mcMMO team is dedicated to providing
an ever-evolving experience, and that we carefully read all feedback and bug reports
in order to evaluate and balance the mechanics of mcMMO in every update.
The goal of mcMMO is to take core Minecraft game mechanics and expand them into
add an extensive and quality RPG experience. Everything in mcMMO has been carefully
thought out and is constantly being improved upon. Currently, mcMMO adds thirteen
unique skills to train and level in. Each of these skills is highly customizable
through our configuration files, allowing server admins to tweak mcMMO to best suit
the needs of his or her server. Know that the mcMMO team is dedicated to providing
an ever-evolving experience, and that we carefully read all feedback and bug reports
in order to evaluate and balance the mechanics of mcMMO in every update.
author: nossr50
authors: [GJ, NuclearW, bm01, Glitchfinder, TfT_02, t00thpick1, Riking, electronicboy, kashike]
authors: [ GJ, NuclearW, bm01, Glitchfinder, TfT_02, t00thpick1, Riking, electronicboy, kashike ]
website: https://www.mcmmo.org
main: com.gmail.nossr50.mcMMO
softdepend: [WorldGuard, CombatTag, HealthBar, PlaceholderAPI, ProtocolLib]
softdepend: [ WorldGuard, CombatTag, HealthBar, PlaceholderAPI, ProtocolLib ]
load: POSTWORLD
folia-supported: true
api-version: 1.13
@@ -26,14 +26,14 @@ commands:
mmocompat:
description: Information about the server and whether its considered fully compatible or running in compatibility mode
mmodebug:
aliases: [mcmmodebugmode]
aliases: [ mcmmodebugmode ]
description: Toggles a debug mode which will print useful information to chat
mmoinfo:
aliases: [mcinfo]
aliases: [ mcinfo ]
description: Info pages for mcMMO
permission: mcmmo.commands.mmoinfo
xprate:
aliases: [mcxprate]
aliases: [ mcxprate ]
description: Modify the xp rate or start an event
permission: mcmmo.commands.xprate
mcmmo:
@@ -59,7 +59,7 @@ commands:
permission: mcmmo.commands.mcrefresh
mccooldown:
description: Show the cooldowns on all your mcMMO abilities
aliases: [mccooldowns]
aliases: [ mccooldowns ]
permission: mcmmo.commands.mccooldown
mcchatspy:
description: Toggle mcMMO Party Chat spying on/off
@@ -68,7 +68,7 @@ commands:
description: Toggle mcMMO god-mode on/off
permission: mcmmo.commands.mcgod
mcstats:
aliases: [stats]
aliases: [ stats ]
description: Shows your mcMMO stats and xp
permission: mcmmo.commands.mcstats
mcremove:
@@ -84,7 +84,7 @@ commands:
description: Create/join a party
permission: mcmmo.commands.party
inspect:
aliases: [mcinspect, mmoinspect]
aliases: [ mcinspect, mmoinspect ]
description: View detailed mcMMO info on another player
permission: mcmmo.commands.inspect
mmoshowdb:
@@ -94,7 +94,7 @@ commands:
description: Convert between different database and formula types
permission: mcmmo.commands.mcconvert
partychat:
aliases: [pc, p]
aliases: [ pc, p ]
description: Toggle Party chat or send party chat messages
permission: mcmmo.chat.partychat
skillreset:
@@ -145,6 +145,9 @@ commands:
smelting:
description: Detailed mcMMO skill info
permission: mcmmo.commands.smelting
spears:
description: Detailed mcMMO skill info
permission: mcmmo.commands.spears
alchemy:
description: Detailed mcMMO skill info
permission: mcmmo.commands.alchemy
@@ -157,24 +160,24 @@ commands:
mmopower:
description: Shows skill mastery and power level info
permission: mcmmo.commands.mmopower
aliases: [mmopowerlevel, powerlevel]
aliases: [ mmopowerlevel, powerlevel ]
adminchat:
aliases: [ac, a]
aliases: [ ac, a ]
description: Toggle Admin chat or send admin chat messages
permission: mcmmo.chat.adminchat
mcpurge:
description: Purge users with 0 powerlevel and/or who haven't connected in several months from the server DB.
permission: mcmmo.commands.mcpurge
mcnotify:
aliases: [notify]
aliases: [ notify ]
description: Toggle mcMMO abilities chat display notifications on/off
permission: mcmmo.commands.mcnotify
mcscoreboard:
aliases: [mcsb]
aliases: [ mcsb ]
description: Manage your mcMMO Scoreboard
permission: mcmmo.commands.mcscoreboard
mcmmoreloadlocale:
aliases: [mcreloadlocale]
aliases: [ mcreloadlocale ]
description: Reloads locale
permission: mcmmo.commands.reloadlocale
permissions:
@@ -237,6 +240,7 @@ permissions:
mcmmo.ability.repair.all: true
mcmmo.ability.salvage.all: true
mcmmo.ability.smelting.all: true
mcmmo.ability.spears.all: true
mcmmo.ability.swords.all: true
mcmmo.ability.taming.all: true
mcmmo.ability.tridents.all: true
@@ -320,19 +324,19 @@ permissions:
mcmmo.ability.axes.skullsplitter:
description: Allows access to the Skull Splitter ability
mcmmo.ability.crossbows.*:
description: Allows access to all Crossbows abilities
children:
description: Allows access to all Crossbows abilities
children:
mcmmo.ability.crossbows.all: true
mcmmo.ability.crossbows.all:
description: Allows access to all Crossbows abilities
children:
mcmmo.ability.crossbows.trickshot: true
mcmmo.ability.crossbows.poweredshot: true
mcmmo.ability.crossbows.crossbowslimitbreak: true
description: Allows access to all Crossbows abilities
children:
mcmmo.ability.crossbows.trickshot: true
mcmmo.ability.crossbows.poweredshot: true
mcmmo.ability.crossbows.crossbowslimitbreak: true
mcmmo.ability.crossbows.crossbowslimitbreak:
description: Adds damage to crossbows
description: Adds damage to crossbows
mcmmo.ability.crossbows.trickshot:
description: Allows access to the Trick Shot ability
description: Allows access to the Trick Shot ability
mcmmo.ability.crossbows.poweredshot:
description: Allows access to the Powered Shot ability
mcmmo.ability.excavation.*:
@@ -646,6 +650,23 @@ permissions:
description: Allows access to the Second Smelt ability
mcmmo.ability.smelting.vanillaxpboost:
description: Allows vanilla XP boost from Smelting
mcmmo.ability.spears.*:
default: false
description: Allows access to all Spear abilities
children:
mcmmo.ability.spears.all: true
mcmmo.ability.spears.all:
description: Allows access to all Spear abilities
children:
mcmmo.ability.spears.spearslimitbreak: true
mcmmo.ability.spears.momentum: true
mcmmo.ability.spears.spearmastery: true
mcmmo.ability.spears.spearslimitbreak:
description: Adds damage to spears
mcmmo.ability.spears.momentum:
description: Allows access to the Spear Momentum ability
mcmmo.ability.spears.spearmastery:
description: Allows access to the Spear Mastery ability
mcmmo.ability.swords.*:
default: false
description: Allows access to all Swords abilities
@@ -885,6 +906,7 @@ permissions:
mcmmo.commands.repair: true
mcmmo.commands.salvage: true
mcmmo.commands.smelting: true
mcmmo.commands.spears: true
mcmmo.commands.swords: true
mcmmo.commands.taming: true
mcmmo.commands.unarmed: true
@@ -898,7 +920,7 @@ permissions:
mcmmo.commands.addxp: true
mcmmo.commands.addxp.others: true
mcmmo.commands.defaults: true
# mcmmo.commands.hardcore.all: true
# mcmmo.commands.hardcore.all: true
mcmmo.commands.inspect.far: true
mcmmo.commands.inspect.hidden: true
mcmmo.commands.mcability.others: true
@@ -918,7 +940,7 @@ permissions:
mcmmo.commands.ptp.world.all: true
mcmmo.commands.reloadlocale: true
mcmmo.commands.skillreset.all: true
# mcmmo.commands.vampirism.all: true
# mcmmo.commands.vampirism.all: true
mcmmo.commands.xprate.all: true
mcmmo.commands.acrobatics:
description: Allows access to the acrobatics command
@@ -1058,6 +1080,7 @@ permissions:
mcmmo.commands.mctop.repair: true
mcmmo.commands.mctop.salvage: true
mcmmo.commands.mctop.smelting: true
mcmmo.commands.mctop.spears: true
mcmmo.commands.mctop.swords: true
mcmmo.commands.mctop.taming: true
mcmmo.commands.mctop.tridents: true
@@ -1091,6 +1114,8 @@ permissions:
description: Allows access to the mctop command for salvage
mcmmo.commands.mctop.smelting:
description: Allows access to the mctop command for smelting
mcmmo.commands.mctop.spears:
description: Allows access to the mctop command for spears
mcmmo.commands.mctop.swords:
description: Allows access to the mctop command for swords
mcmmo.commands.mctop.taming:
@@ -1239,6 +1264,7 @@ permissions:
mcmmo.commands.skillreset.repair: true
mcmmo.commands.skillreset.salvage: true
mcmmo.commands.skillreset.smelting: true
mcmmo.commands.skillreset.spears: true
mcmmo.commands.skillreset.swords: true
mcmmo.commands.skillreset.taming: true
mcmmo.commands.skillreset.unarmed: true
@@ -1268,6 +1294,8 @@ permissions:
description: Allows access to the skillreset command for crossbows
mcmmo.commands.skillreset.tridents:
description: Allows access to the skillreset command for tridents
mcmmo.commands.skillreset.spears:
description: Allows access to the skillreset command for spears
mcmmo.commands.skillreset.maces:
description: Allows access to the skillreset command for maces
mcmmo.commands.skillreset.others.*:
@@ -1290,6 +1318,7 @@ permissions:
mcmmo.commands.skillreset.others.repair: true
mcmmo.commands.skillreset.others.salvage: true
mcmmo.commands.skillreset.others.smelting: true
mcmmo.commands.skillreset.others.spears: true
mcmmo.commands.skillreset.others.swords: true
mcmmo.commands.skillreset.others.taming: true
mcmmo.commands.skillreset.others.unarmed: true
@@ -1321,6 +1350,8 @@ permissions:
description: Allows access to the skillreset command for salvage for other players
mcmmo.commands.skillreset.others.smelting:
description: Allows access to the skillreset command for smelting for other players
mcmmo.commands.skillreset.others.spears:
description: Allows access to the skillreset command for spears for other players
mcmmo.commands.skillreset.others.swords:
description: Allows access to the skillreset command for swords for other players
mcmmo.commands.skillreset.others.taming:
@@ -1406,7 +1437,7 @@ permissions:
default: false
description: implies access to all mcmmo perks
children:
mcmmo.perks.all: true
mcmmo.perks.all: true
mcmmo.perks.all:
default: false
description: implies access to all mcmmo perks
@@ -1497,6 +1528,7 @@ permissions:
mcmmo.perks.lucky.repair: true
mcmmo.perks.lucky.salvage: true
mcmmo.perks.lucky.smelting: true
mcmmo.perks.lucky.spears: true
mcmmo.perks.lucky.swords: true
mcmmo.perks.lucky.taming: true
mcmmo.perks.lucky.unarmed: true
@@ -1539,6 +1571,9 @@ permissions:
mcmmo.perks.lucky.salvage:
default: false
description: Gives Salvage abilities & skills a 33.3% better chance to activate.
mcmmo.perks.lucky.spears:
default: false
description: Gives Spears abilities & skills a 33.3% better chance to activate.
mcmmo.perks.lucky.smelting:
default: false
description: Gives Smelting abilities & skills a 33.3% better chance to activate.
@@ -1600,6 +1635,7 @@ permissions:
mcmmo.perks.xp.150percentboost.mining: true
mcmmo.perks.xp.150percentboost.repair: true
mcmmo.perks.xp.150percentboost.smelting: true
mcmmo.perks.xp.150percentboost.spears: true
mcmmo.perks.xp.150percentboost.swords: true
mcmmo.perks.xp.150percentboost.taming: true
mcmmo.perks.xp.150percentboost.tridents: true
@@ -1641,6 +1677,9 @@ permissions:
mcmmo.perks.xp.150percentboost.smelting:
default: false
description: Multiplies incoming Smelting XP by 2.5
mcmmo.perks.xp.150percentboost.spears:
default: false
description: Multiplies incoming Spears XP by 2.5
mcmmo.perks.xp.150percentboost.swords:
default: false
description: Multiplies incoming Swords XP by 2.5
@@ -1682,6 +1721,7 @@ permissions:
mcmmo.perks.xp.50percentboost.mining: true
mcmmo.perks.xp.50percentboost.repair: true
mcmmo.perks.xp.50percentboost.smelting: true
mcmmo.perks.xp.50percentboost.spears: true
mcmmo.perks.xp.50percentboost.swords: true
mcmmo.perks.xp.50percentboost.taming: true
mcmmo.perks.xp.50percentboost.tridents: true
@@ -1720,6 +1760,9 @@ permissions:
mcmmo.perks.xp.50percentboost.repair:
default: false
description: Multiplies incoming Repair XP by 1.5
mcmmo.perks.xp.50percentboost.spears:
default: false
description: Multiplies incoming Spears XP by 1.5
mcmmo.perks.xp.50percentboost.smelting:
default: false
description: Multiplies incoming Smelting XP by 1.5
@@ -1739,87 +1782,91 @@ permissions:
default: false
description: Multiplies incoming Woodcutting XP by 1.5
mcmmo.perks.xp.25percentboost.*:
default: false
description: Multiplies incoming XP by 1.25
children:
mcmmo.perks.xp.25percentboost.all: true
mcmmo.perks.xp.25percentboost:
default: false
description: Multiplies incoming XP by 1.25
children:
mcmmo.perks.xp.25percentboost.all: true
mcmmo.perks.xp.25percentboost.all:
default: false
description: Multiplies incoming XP by 1.25
children:
mcmmo.perks.xp.25percentboost.acrobatics: true
mcmmo.perks.xp.25percentboost.alchemy: true
mcmmo.perks.xp.25percentboost.archery: true
mcmmo.perks.xp.25percentboost.axes: true
mcmmo.perks.xp.25percentboost.crossbows: true
mcmmo.perks.xp.25percentboost.excavation: true
mcmmo.perks.xp.25percentboost.fishing: true
mcmmo.perks.xp.25percentboost.herbalism: true
mcmmo.perks.xp.25percentboost.maces: true
mcmmo.perks.xp.25percentboost.mining: true
mcmmo.perks.xp.25percentboost.repair: true
mcmmo.perks.xp.25percentboost.smelting: true
mcmmo.perks.xp.25percentboost.swords: true
mcmmo.perks.xp.25percentboost.taming: true
mcmmo.perks.xp.25percentboost.tridents: true
mcmmo.perks.xp.25percentboost.unarmed: true
mcmmo.perks.xp.25percentboost.woodcutting: true
mcmmo.perks.xp.25percentboost.acrobatics:
default: false
description: Multiplies incoming Acrobatics XP by 1.25
mcmmo.perks.xp.25percentboost.alchemy:
default: false
description: Multiplies incoming Acrobatics XP by 1.25
mcmmo.perks.xp.25percentboost.archery:
default: false
description: Multiplies incoming Archery XP by 1.25
mcmmo.perks.xp.25percentboost.axes:
default: false
description: Multiplies incoming Axes XP by 1.25
mcmmo.perks.xp.25percentboost.crossbows:
default: false
description: Multiplies incoming Crossbows XP by 1.25
mcmmo.perks.xp.25percentboost.excavation:
default: false
description: Multiplies incoming Excavation XP by 1.25
mcmmo.perks.xp.25percentboost.fishing:
default: false
description: Multiplies incoming Fishing XP by 1.25
mcmmo.perks.xp.25percentboost.herbalism:
default: false
description: Multiplies incoming Herbalism XP by 1.25
mcmmo.perks.xp.25percentboost.maces:
default: false
description: Multiplies incoming Maces XP by 1.25
mcmmo.perks.xp.25percentboost.mining:
default: false
description: Multiplies incoming Mining XP by 1.25
mcmmo.perks.xp.25percentboost.repair:
default: false
description: Multiplies incoming Repair XP by 1.25
mcmmo.perks.xp.25percentboost.smelting:
default: false
description: Multiplies incoming Smelting XP by 1.25
mcmmo.perks.xp.25percentboost.swords:
default: false
description: Multiplies incoming Swords XP by 1.25
mcmmo.perks.xp.25percentboost.taming:
default: false
description: Multiplies incoming Taming XP by 1.25
mcmmo.perks.xp.25percentboost.tridents:
default: false
description: Multiplies incoming Tridents XP by 1.25
mcmmo.perks.xp.25percentboost.unarmed:
default: false
description: Multiplies incoming Unarmed XP by 1.5
mcmmo.perks.xp.25percentboost.woodcutting:
default: false
description: Multiplies incoming Woodcutting XP by 1.25
mcmmo.perks.xp.25percentboost.all: true
mcmmo.perks.xp.25percentboost:
default: false
description: Multiplies incoming XP by 1.25
children:
mcmmo.perks.xp.25percentboost.all: true
mcmmo.perks.xp.25percentboost.all:
default: false
description: Multiplies incoming XP by 1.25
children:
mcmmo.perks.xp.25percentboost.acrobatics: true
mcmmo.perks.xp.25percentboost.alchemy: true
mcmmo.perks.xp.25percentboost.archery: true
mcmmo.perks.xp.25percentboost.axes: true
mcmmo.perks.xp.25percentboost.crossbows: true
mcmmo.perks.xp.25percentboost.excavation: true
mcmmo.perks.xp.25percentboost.fishing: true
mcmmo.perks.xp.25percentboost.herbalism: true
mcmmo.perks.xp.25percentboost.maces: true
mcmmo.perks.xp.25percentboost.mining: true
mcmmo.perks.xp.25percentboost.repair: true
mcmmo.perks.xp.25percentboost.smelting: true
mcmmo.perks.xp.25percentboost.spears: true
mcmmo.perks.xp.25percentboost.swords: true
mcmmo.perks.xp.25percentboost.taming: true
mcmmo.perks.xp.25percentboost.tridents: true
mcmmo.perks.xp.25percentboost.unarmed: true
mcmmo.perks.xp.25percentboost.woodcutting: true
mcmmo.perks.xp.25percentboost.acrobatics:
default: false
description: Multiplies incoming Acrobatics XP by 1.25
mcmmo.perks.xp.25percentboost.alchemy:
default: false
description: Multiplies incoming Acrobatics XP by 1.25
mcmmo.perks.xp.25percentboost.archery:
default: false
description: Multiplies incoming Archery XP by 1.25
mcmmo.perks.xp.25percentboost.axes:
default: false
description: Multiplies incoming Axes XP by 1.25
mcmmo.perks.xp.25percentboost.crossbows:
default: false
description: Multiplies incoming Crossbows XP by 1.25
mcmmo.perks.xp.25percentboost.excavation:
default: false
description: Multiplies incoming Excavation XP by 1.25
mcmmo.perks.xp.25percentboost.fishing:
default: false
description: Multiplies incoming Fishing XP by 1.25
mcmmo.perks.xp.25percentboost.herbalism:
default: false
description: Multiplies incoming Herbalism XP by 1.25
mcmmo.perks.xp.25percentboost.maces:
default: false
description: Multiplies incoming Maces XP by 1.25
mcmmo.perks.xp.25percentboost.mining:
default: false
description: Multiplies incoming Mining XP by 1.25
mcmmo.perks.xp.25percentboost.repair:
default: false
description: Multiplies incoming Repair XP by 1.25
mcmmo.perks.xp.25percentboost.smelting:
default: false
description: Multiplies incoming Smelting XP by 1.25
mcmmo.perks.xp.25percentboost.spears:
default: false
description: Multiplies incoming Spears XP by 1.25
mcmmo.perks.xp.25percentboost.swords:
default: false
description: Multiplies incoming Swords XP by 1.25
mcmmo.perks.xp.25percentboost.taming:
default: false
description: Multiplies incoming Taming XP by 1.25
mcmmo.perks.xp.25percentboost.tridents:
default: false
description: Multiplies incoming Tridents XP by 1.25
mcmmo.perks.xp.25percentboost.unarmed:
default: false
description: Multiplies incoming Unarmed XP by 1.5
mcmmo.perks.xp.25percentboost.woodcutting:
default: false
description: Multiplies incoming Woodcutting XP by 1.25
mcmmo.perks.xp.10percentboost.*:
default: false
description: Multiplies incoming XP by 1.1
@@ -1846,6 +1893,7 @@ permissions:
mcmmo.perks.xp.10percentboost.mining: true
mcmmo.perks.xp.10percentboost.repair: true
mcmmo.perks.xp.10percentboost.smelting: true
mcmmo.perks.xp.10percentboost.spears: true
mcmmo.perks.xp.10percentboost.swords: true
mcmmo.perks.xp.10percentboost.taming: true
mcmmo.perks.xp.10percentboost.tridents: true
@@ -1884,6 +1932,9 @@ permissions:
mcmmo.perks.xp.10percentboost.repair:
default: false
description: Multiplies incoming Repair XP by 1.1
mcmmo.perks.xp.10percentboost.spears:
default: false
description: Multiplies incoming Spears XP by 1.1
mcmmo.perks.xp.10percentboost.smelting:
default: false
description: Multiplies incoming Smelting XP by 1.1
@@ -1928,6 +1979,7 @@ permissions:
mcmmo.perks.xp.customboost.mining: true
mcmmo.perks.xp.customboost.repair: true
mcmmo.perks.xp.customboost.smelting: true
mcmmo.perks.xp.customboost.spears: true
mcmmo.perks.xp.customboost.swords: true
mcmmo.perks.xp.customboost.taming: true
mcmmo.perks.xp.customboost.tridents: true
@@ -1966,6 +2018,9 @@ permissions:
mcmmo.perks.xp.customboost.repair:
default: false
description: Multiplies incoming Repair XP by the boost amount defined in the experience config
mcmmo.perks.xp.customboost.spears:
default: false
description: Multiplies incoming Smelting XP by the boost amount defined in the experience config
mcmmo.perks.xp.customboost.smelting:
default: false
description: Multiplies incoming Smelting XP by the boost amount defined in the experience config
@@ -2010,6 +2065,7 @@ permissions:
mcmmo.perks.xp.double.mining: true
mcmmo.perks.xp.double.repair: true
mcmmo.perks.xp.double.smelting: true
mcmmo.perks.xp.double.spears: true
mcmmo.perks.xp.double.swords: true
mcmmo.perks.xp.double.taming: true
mcmmo.perks.xp.double.tridents: true
@@ -2048,6 +2104,9 @@ permissions:
mcmmo.perks.xp.double.repair:
default: false
description: Doubles incoming Repair XP
mcmmo.perks.xp.double.spears:
default: false
description: Doubles incoming Smelting XP
mcmmo.perks.xp.double.smelting:
default: false
description: Doubles incoming Smelting XP
@@ -2092,6 +2151,7 @@ permissions:
mcmmo.perks.xp.quadruple.mining: true
mcmmo.perks.xp.quadruple.repair: true
mcmmo.perks.xp.quadruple.smelting: true
mcmmo.perks.xp.quadruple.spears: true
mcmmo.perks.xp.quadruple.swords: true
mcmmo.perks.xp.quadruple.taming: true
mcmmo.perks.xp.quadruple.tridents: true
@@ -2133,6 +2193,9 @@ permissions:
mcmmo.perks.xp.quadruple.smelting:
default: false
description: Quadruples incoming Smelting XP
mcmmo.perks.xp.quadruple.spears:
default: false
description: Quadruples incoming Spears XP
mcmmo.perks.xp.quadruple.swords:
default: false
description: Quadruples incoming Swords XP
@@ -2174,6 +2237,7 @@ permissions:
mcmmo.perks.xp.triple.maces: true
mcmmo.perks.xp.triple.repair: true
mcmmo.perks.xp.triple.smelting: true
mcmmo.perks.xp.triple.spears: true
mcmmo.perks.xp.triple.swords: true
mcmmo.perks.xp.triple.taming: true
mcmmo.perks.xp.triple.tridents: true
@@ -2215,6 +2279,9 @@ permissions:
mcmmo.perks.xp.triple.smelting:
default: false
description: Triples incoming Smelting XP
mcmmo.perks.xp.triple.spears:
default: false
description: Triples incoming Spears XP
mcmmo.perks.xp.triple.swords:
default: false
description: Triples incoming Swords XP
@@ -2257,6 +2324,7 @@ permissions:
mcmmo.skills.salvage: true
mcmmo.skills.swords: true
mcmmo.skills.smelting: true
mcmmo.skills.spears: true
mcmmo.skills.taming: true
mcmmo.skills.unarmed: true
mcmmo.skills.woodcutting: true
@@ -2322,6 +2390,11 @@ permissions:
children:
mcmmo.ability.smelting.all: true
mcmmo.commands.smelting: true
mcmmo.skills.spears:
description: Allows access to the Spears skill
children:
mcmmo.ability.spears.all: true
mcmmo.commands.spears: true
mcmmo.skills.swords:
description: Allows access to the Swords skill
children:

View File

@@ -55,6 +55,9 @@ Repairables:
WOODEN_SWORD:
MinimumLevel: 0
XpMultiplier: .25
WOODEN_SPEAR:
MinimumLevel: 0
XpMultiplier: .25
WOODEN_SHOVEL:
MinimumLevel: 0
XpMultiplier: .16
@@ -74,6 +77,9 @@ Repairables:
STONE_SWORD:
MinimumLevel: 0
XpMultiplier: .25
STONE_SPEAR:
MinimumLevel: 0
XpMultiplier: .25
STONE_SHOVEL:
MinimumLevel: 0
XpMultiplier: .16
@@ -96,6 +102,12 @@ Repairables:
ItemType: TOOL
ItemMaterialCategory: COPPER
RepairMaterial: COPPER_INGOT
COPPER_SPEAR:
MinimumLevel: 0
XpMultiplier: .3
ItemType: TOOL
ItemMaterialCategory: COPPER
RepairMaterial: COPPER_INGOT
COPPER_SHOVEL:
MinimumLevel: 0
XpMultiplier: .2
@@ -152,6 +164,9 @@ Repairables:
IRON_SWORD:
MinimumLevel: 0
XpMultiplier: .5
IRON_SPEAR:
MinimumLevel: 0
XpMultiplier: .5
IRON_SHOVEL:
MinimumLevel: 0
XpMultiplier: .3
@@ -190,6 +205,9 @@ Repairables:
GOLDEN_SWORD:
MinimumLevel: 0
XpMultiplier: 4
GOLDEN_SPEAR:
MinimumLevel: 0
XpMultiplier: 4
GOLDEN_SHOVEL:
MinimumLevel: 0
XpMultiplier: 2.6
@@ -222,6 +240,9 @@ Repairables:
DIAMOND_SWORD:
MinimumLevel: 0
XpMultiplier: .5
DIAMOND_SPEAR:
MinimumLevel: 0
XpMultiplier: .5
DIAMOND_SHOVEL:
MinimumLevel: 0
XpMultiplier: .3
@@ -255,6 +276,9 @@ Repairables:
NETHERITE_SWORD:
MinimumLevel: 0
XpMultiplier: .6
NETHERITE_SPEAR:
MinimumLevel: 0
XpMultiplier: .6
NETHERITE_SHOVEL:
MinimumLevel: 0
XpMultiplier: .4

View File

@@ -50,6 +50,10 @@ Salvageables:
MinimumLevel: 0
XpMultiplier: .25
MaximumQuantity: 2
WOODEN_SPEAR:
MinimumLevel: 0
XpMultiplier: .16
MaximumQuantity: 1
WOODEN_SHOVEL:
MinimumLevel: 0
XpMultiplier: .16
@@ -74,6 +78,10 @@ Salvageables:
MinimumLevel: 0
XpMultiplier: .25
MaximumQuantity: 2
STONE_SPEAR:
MinimumLevel: 0
XpMultiplier: .16
MaximumQuantity: 1
STONE_SHOVEL:
MinimumLevel: 0
XpMultiplier: .16
@@ -98,6 +106,10 @@ Salvageables:
MinimumLevel: 0
XpMultiplier: .4
MaximumQuantity: 2
COPPER_SPEAR:
MinimumLevel: 0
XpMultiplier: .25
MaximumQuantity: 1
COPPER_SHOVEL:
MinimumLevel: 0
XpMultiplier: .25
@@ -139,6 +151,10 @@ Salvageables:
MinimumLevel: 0
XpMultiplier: .5
MaximumQuantity: 2
IRON_SPEAR:
MinimumLevel: 0
XpMultiplier: .3
MaximumQuantity: 1
IRON_SHOVEL:
MinimumLevel: 0
XpMultiplier: .3
@@ -186,6 +202,10 @@ Salvageables:
MinimumLevel: 0
XpMultiplier: 4
MaximumQuantity: 2
GOLDEN_SPEAR:
MinimumLevel: 0
XpMultiplier: 4
MaximumQuantity: 1
GOLDEN_SHOVEL:
MinimumLevel: 0
XpMultiplier: 2.6
@@ -227,6 +247,10 @@ Salvageables:
MinimumLevel: 50
XpMultiplier: .5
MaximumQuantity: 2
DIAMOND_SPEAR:
MinimumLevel: 50
XpMultiplier: .5
MaximumQuantity: 1
DIAMOND_SHOVEL:
MinimumLevel: 50
XpMultiplier: .3
@@ -268,6 +292,10 @@ Salvageables:
MinimumLevel: 100
XpMultiplier: .5
MaximumQuantity: 4
NETHERITE_SPEAR:
MinimumLevel: 100
XpMultiplier: .3
MaximumQuantity: 4
NETHERITE_SHOVEL:
MinimumLevel: 100
XpMultiplier: .3

View File

@@ -404,6 +404,72 @@ Smelting:
Rank_6: 750
Rank_7: 850
Rank_8: 1000
Spears:
SpearsLimitBreak:
Standard:
Rank_1: 10
Rank_2: 20
Rank_3: 30
Rank_4: 40
Rank_5: 50
Rank_6: 60
Rank_7: 70
Rank_8: 80
Rank_9: 90
Rank_10: 100
RetroMode:
Rank_1: 100
Rank_2: 200
Rank_3: 300
Rank_4: 400
Rank_5: 500
Rank_6: 600
Rank_7: 700
Rank_8: 800
Rank_9: 900
Rank_10: 1000
SpearMastery:
Standard:
Rank_1: 5
Rank_2: 15
Rank_3: 30
Rank_4: 45
Rank_5: 60
Rank_6: 75
Rank_7: 90
Rank_8: 100
RetroMode:
Rank_1: 50
Rank_2: 150
Rank_3: 300
Rank_4: 450
Rank_5: 600
Rank_6: 750
Rank_7: 900
Rank_8: 1000
Momentum:
Standard:
Rank_1: 1
Rank_2: 10
Rank_3: 15
Rank_4: 20
Rank_5: 25
Rank_6: 40
Rank_7: 50
Rank_8: 60
Rank_9: 80
Rank_10: 95
RetroMode:
Rank_1: 1
Rank_2: 100
Rank_3: 150
Rank_4: 200
Rank_5: 250
Rank_6: 400
Rank_7: 500
Rank_8: 600
Rank_9: 800
Rank_10: 950
Salvage:
ScrapCollector:
Standard:

View File

@@ -0,0 +1,371 @@
package com.gmail.nossr50.util.skills;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import com.gmail.nossr50.config.GeneralConfig;
import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
import com.gmail.nossr50.datatypes.skills.SubSkillType;
import com.gmail.nossr50.datatypes.skills.SuperAbilityType;
import com.gmail.nossr50.datatypes.skills.ToolType;
import com.gmail.nossr50.locale.LocaleLoader;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.util.compat.CompatibilityManager;
import com.gmail.nossr50.util.platform.MinecraftGameVersion;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestInstance.Lifecycle;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
@TestInstance(Lifecycle.PER_CLASS)
class SkillToolsTest {
private static final @NotNull Logger logger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
private static MockedStatic<mcMMO> mockedMcMMO;
private static MockedStatic<LocaleLoader> mockedLocaleLoader;
private GeneralConfig generalConfig;
private CompatibilityManager compatibilityManager;
@BeforeAll
void setUpAll() {
// Static mcMMO + LocaleLoader mocks
mockedMcMMO = Mockito.mockStatic(mcMMO.class);
mockedLocaleLoader = Mockito.mockStatic(LocaleLoader.class);
// Plugin instance
mcMMO.p = mock(mcMMO.class);
when(mcMMO.p.getLogger()).thenReturn(logger);
// General config
generalConfig = mock(GeneralConfig.class);
when(mcMMO.p.getGeneralConfig()).thenReturn(generalConfig);
when(generalConfig.getLocale()).thenReturn("en_US");
// Compatibility manager + game version
compatibilityManager = mock(CompatibilityManager.class);
when(mcMMO.getCompatibilityManager()).thenReturn(compatibilityManager);
// LocaleLoader just echo key back to keep things simple/deterministic
mockedLocaleLoader.when(() -> LocaleLoader.getString(anyString()))
.thenAnswer(invocation -> invocation.getArgument(0));
}
@AfterAll
void tearDownAll() {
mockedLocaleLoader.close();
mockedMcMMO.close();
}
private SkillTools newSkillToolsForVersion(int major, int minor, int patch) throws Exception {
when(compatibilityManager.getMinecraftGameVersion())
.thenReturn(new MinecraftGameVersion(major, minor, patch));
return new SkillTools(mcMMO.p);
}
// ------------------------------------------------------------------------
// NON_CHILD_SKILLS / isChildSkill / CHILD_SKILLS
// ------------------------------------------------------------------------
@Test
void nonChildSkillsShouldContainAllPrimarySkillsExceptSalvageAndSmelting() {
List<PrimarySkillType> expected = Arrays.stream(PrimarySkillType.values())
.filter(t -> t != PrimarySkillType.SALVAGE && t != PrimarySkillType.SMELTING)
.collect(Collectors.toList());
assertThat(SkillTools.NON_CHILD_SKILLS)
.containsExactlyInAnyOrderElementsOf(expected);
}
@Test
void isChildSkillShouldReturnTrueOnlyForSalvageAndSmelting() {
for (PrimarySkillType type : PrimarySkillType.values()) {
boolean isChild = SkillTools.isChildSkill(type);
if (type == PrimarySkillType.SALVAGE || type == PrimarySkillType.SMELTING) {
assertThat(isChild)
.as("%s should be considered a child skill", type)
.isTrue();
} else {
assertThat(isChild)
.as("%s should NOT be considered a child skill", type)
.isFalse();
}
}
}
@Test
void childSkillsListShouldMatchIsChildSkillClassification() throws Exception {
SkillTools skillTools = newSkillToolsForVersion(1, 21, 11);
List<PrimarySkillType> expectedChildren = Arrays.stream(PrimarySkillType.values())
.filter(SkillTools::isChildSkill)
.collect(Collectors.toList());
assertThat(skillTools.getChildSkills())
.containsExactlyInAnyOrderElementsOf(expectedChildren);
}
// ------------------------------------------------------------------------
// Child skill parents (SALVAGE_PARENTS / SMELTING_PARENTS / getChildSkillParents)
// ------------------------------------------------------------------------
@Test
void childSkillParentsShouldMatchStaticParentLists() throws Exception {
SkillTools skillTools = newSkillToolsForVersion(1, 21, 11);
assertThat(skillTools.getChildSkillParents(PrimarySkillType.SALVAGE))
.as("SALVAGE parents")
.containsExactlyElementsOf(SkillTools.SALVAGE_PARENTS);
assertThat(skillTools.getChildSkillParents(PrimarySkillType.SMELTING))
.as("SMELTING parents")
.containsExactlyElementsOf(SkillTools.SMELTING_PARENTS);
}
@Test
void getChildSkillParentsShouldThrowForNonChildSkill() throws Exception {
SkillTools skillTools = newSkillToolsForVersion(1, 21, 11);
assertThatThrownBy(() -> skillTools.getChildSkillParents(PrimarySkillType.MINING))
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("is not a child skill");
}
// ------------------------------------------------------------------------
// Super ability ↔ primary skill relationships
// ------------------------------------------------------------------------
@Test
void superAbilityParentMappingShouldMatchDefinedSwitch() throws Exception {
SkillTools skillTools = newSkillToolsForVersion(1, 21, 11);
assertThat(skillTools.getPrimarySkillBySuperAbility(SuperAbilityType.BERSERK))
.isEqualTo(PrimarySkillType.UNARMED);
assertThat(skillTools.getPrimarySkillBySuperAbility(SuperAbilityType.GREEN_TERRA))
.isEqualTo(PrimarySkillType.HERBALISM);
assertThat(skillTools.getPrimarySkillBySuperAbility(SuperAbilityType.TREE_FELLER))
.isEqualTo(PrimarySkillType.WOODCUTTING);
assertThat(skillTools.getPrimarySkillBySuperAbility(SuperAbilityType.SUPER_BREAKER))
.isEqualTo(PrimarySkillType.MINING);
assertThat(skillTools.getPrimarySkillBySuperAbility(SuperAbilityType.BLAST_MINING))
.isEqualTo(PrimarySkillType.MINING);
assertThat(skillTools.getPrimarySkillBySuperAbility(SuperAbilityType.SKULL_SPLITTER))
.isEqualTo(PrimarySkillType.AXES);
assertThat(skillTools.getPrimarySkillBySuperAbility(SuperAbilityType.SERRATED_STRIKES))
.isEqualTo(PrimarySkillType.SWORDS);
assertThat(skillTools.getPrimarySkillBySuperAbility(SuperAbilityType.GIGA_DRILL_BREAKER))
.isEqualTo(PrimarySkillType.EXCAVATION);
assertThat(skillTools.getPrimarySkillBySuperAbility(SuperAbilityType.SUPER_SHOTGUN))
.isEqualTo(PrimarySkillType.CROSSBOWS);
assertThat(skillTools.getPrimarySkillBySuperAbility(SuperAbilityType.TRIDENTS_SUPER_ABILITY))
.isEqualTo(PrimarySkillType.TRIDENTS);
assertThat(skillTools.getPrimarySkillBySuperAbility(SuperAbilityType.EXPLOSIVE_SHOT))
.isEqualTo(PrimarySkillType.ARCHERY);
assertThat(skillTools.getPrimarySkillBySuperAbility(SuperAbilityType.MACES_SUPER_ABILITY))
.isEqualTo(PrimarySkillType.MACES);
assertThat(skillTools.getPrimarySkillBySuperAbility(SuperAbilityType.SPEARS_SUPER_ABILITY))
.isEqualTo(PrimarySkillType.SPEARS);
}
@Test
void mainActivatedAbilityChildMapShouldOmitBlastMiningAndMapOthersBackToAbility() throws Exception {
SkillTools skillTools = newSkillToolsForVersion(1, 21, 11);
// All super abilities EXCEPT BLAST_MINING should be discoverable via getSuperAbility()
assertThat(skillTools.getSuperAbility(PrimarySkillType.MINING))
.as("MINING should not expose BLAST_MINING as the 'main' tool-readied ability")
.isEqualTo(SuperAbilityType.SUPER_BREAKER);
assertThat(skillTools.getSuperAbility(PrimarySkillType.UNARMED))
.isEqualTo(SuperAbilityType.BERSERK);
assertThat(skillTools.getSuperAbility(PrimarySkillType.HERBALISM))
.isEqualTo(SuperAbilityType.GREEN_TERRA);
assertThat(skillTools.getSuperAbility(PrimarySkillType.WOODCUTTING))
.isEqualTo(SuperAbilityType.TREE_FELLER);
assertThat(skillTools.getSuperAbility(PrimarySkillType.AXES))
.isEqualTo(SuperAbilityType.SKULL_SPLITTER);
assertThat(skillTools.getSuperAbility(PrimarySkillType.SWORDS))
.isEqualTo(SuperAbilityType.SERRATED_STRIKES);
assertThat(skillTools.getSuperAbility(PrimarySkillType.EXCAVATION))
.isEqualTo(SuperAbilityType.GIGA_DRILL_BREAKER);
assertThat(skillTools.getSuperAbility(PrimarySkillType.CROSSBOWS))
.isEqualTo(SuperAbilityType.SUPER_SHOTGUN);
assertThat(skillTools.getSuperAbility(PrimarySkillType.TRIDENTS))
.isEqualTo(SuperAbilityType.TRIDENTS_SUPER_ABILITY);
assertThat(skillTools.getSuperAbility(PrimarySkillType.ARCHERY))
.isEqualTo(SuperAbilityType.EXPLOSIVE_SHOT);
assertThat(skillTools.getSuperAbility(PrimarySkillType.MACES))
.isEqualTo(SuperAbilityType.MACES_SUPER_ABILITY);
assertThat(skillTools.getSuperAbility(PrimarySkillType.SPEARS))
.isEqualTo(SuperAbilityType.SPEARS_SUPER_ABILITY);
// Skills without a main activated ability should return null
assertThat(skillTools.getSuperAbility(PrimarySkillType.REPAIR)).isNull();
assertThat(skillTools.getSuperAbility(PrimarySkillType.FISHING)).isNull();
}
// ------------------------------------------------------------------------
// Sub-skill → primary-skill mapping (name prefix convention)
// ------------------------------------------------------------------------
@Test
void primarySkillBySubSkillShouldFollowNamePrefixConvention() throws Exception {
SkillTools skillTools = newSkillToolsForVersion(1, 21, 11);
for (SubSkillType sub : SubSkillType.values()) {
PrimarySkillType parent = skillTools.getPrimarySkillBySubSkill(sub);
assertThat(parent)
.as("SubSkill %s should have a parent PrimarySkillType", sub)
.isNotNull();
String subName = sub.name().toUpperCase(Locale.ENGLISH);
String parentPrefix = parent.name().toUpperCase(Locale.ENGLISH);
assertThat(subName.startsWith(parentPrefix))
.as("SubSkill %s should start with its parent skill name %s", subName, parentPrefix)
.isTrue();
}
}
// ------------------------------------------------------------------------
// primarySkillToolMap
// ------------------------------------------------------------------------
@Test
void primarySkillToolTypeMappingShouldMatchDefinition() throws Exception {
SkillTools skillTools = newSkillToolsForVersion(1, 21, 11);
assertThat(skillTools.getPrimarySkillToolType(PrimarySkillType.AXES))
.isEqualTo(ToolType.AXE);
assertThat(skillTools.getPrimarySkillToolType(PrimarySkillType.WOODCUTTING))
.isEqualTo(ToolType.AXE);
assertThat(skillTools.getPrimarySkillToolType(PrimarySkillType.UNARMED))
.isEqualTo(ToolType.FISTS);
assertThat(skillTools.getPrimarySkillToolType(PrimarySkillType.SWORDS))
.isEqualTo(ToolType.SWORD);
assertThat(skillTools.getPrimarySkillToolType(PrimarySkillType.EXCAVATION))
.isEqualTo(ToolType.SHOVEL);
assertThat(skillTools.getPrimarySkillToolType(PrimarySkillType.HERBALISM))
.isEqualTo(ToolType.HOE);
assertThat(skillTools.getPrimarySkillToolType(PrimarySkillType.MINING))
.isEqualTo(ToolType.PICKAXE);
// And any skill not explicitly mapped should currently return null
assertThat(skillTools.getPrimarySkillToolType(PrimarySkillType.FISHING)).isNull();
assertThat(skillTools.getPrimarySkillToolType(PrimarySkillType.TAMING)).isNull();
}
// ------------------------------------------------------------------------
// Combat / Gathering / Misc groupings by Minecraft version
// ------------------------------------------------------------------------
@Test
void combatGatheringMiscGroupingsShouldMatchDefinitionForModernSpearsAndMacesVersion()
throws Exception {
SkillTools skillTools = newSkillToolsForVersion(1, 21, 11);
assertThat(skillTools.getCombatSkills())
.containsExactly(
PrimarySkillType.ARCHERY,
PrimarySkillType.AXES,
PrimarySkillType.CROSSBOWS,
PrimarySkillType.MACES,
PrimarySkillType.SWORDS,
PrimarySkillType.SPEARS,
PrimarySkillType.TAMING,
PrimarySkillType.TRIDENTS,
PrimarySkillType.UNARMED
);
assertThat(skillTools.getGatheringSkills())
.containsExactly(
PrimarySkillType.EXCAVATION,
PrimarySkillType.FISHING,
PrimarySkillType.HERBALISM,
PrimarySkillType.MINING,
PrimarySkillType.WOODCUTTING
);
assertThat(skillTools.getMiscSkills())
.containsExactly(
PrimarySkillType.ACROBATICS,
PrimarySkillType.ALCHEMY,
PrimarySkillType.REPAIR,
PrimarySkillType.SALVAGE,
PrimarySkillType.SMELTING
);
}
@Test
void combatSkillsShouldMatchDefinitionForVersionWithMacesButWithoutSpears() throws Exception {
SkillTools skillTools = newSkillToolsForVersion(1, 21, 0);
assertThat(skillTools.getCombatSkills())
.containsExactly(
PrimarySkillType.ARCHERY,
PrimarySkillType.AXES,
PrimarySkillType.CROSSBOWS,
PrimarySkillType.MACES,
PrimarySkillType.SWORDS,
PrimarySkillType.TAMING,
PrimarySkillType.TRIDENTS,
PrimarySkillType.UNARMED
);
}
@Test
void combatSkillsShouldMatchDefinitionForVersionWithoutMacesOrSpears() throws Exception {
SkillTools skillTools = newSkillToolsForVersion(1, 20, 4);
assertThat(skillTools.getCombatSkills())
.containsExactly(
PrimarySkillType.ARCHERY,
PrimarySkillType.AXES,
PrimarySkillType.CROSSBOWS,
PrimarySkillType.SWORDS,
PrimarySkillType.TAMING,
PrimarySkillType.TRIDENTS,
PrimarySkillType.UNARMED
);
}
// ------------------------------------------------------------------------
// LOCALIZED_SKILL_NAMES basic sanity (size + uniqueness, not content)
// ------------------------------------------------------------------------
@Test
void localizedSkillNamesShouldContainOneEntryPerPrimarySkillAndBeSorted() throws Exception {
SkillTools skillTools = newSkillToolsForVersion(1, 21, 11);
List<String> names = new ArrayList<>(skillTools.LOCALIZED_SKILL_NAMES);
// One per PrimarySkillType
assertThat(names).hasSize(PrimarySkillType.values().length);
// No duplicates
assertThat(new HashSet<>(names)).hasSize(names.size());
// Sorted ascending
List<String> sorted = new ArrayList<>(names);
Collections.sort(sorted);
assertThat(names).isEqualTo(sorted);
}
}

View File

@@ -1,3 +1,3 @@
nossr50:1:IGNORED:IGNORED:10:2:20:3:4:5:6:7:8:9:10:30:40:50:60:70:80:90:100:IGNORED:11:110:111:222:333:444:555:666:777:IGNORED:12:120:888:IGNORED:HEARTS:13:130:588fe472-1c82-4c4e-9aa1-7eefccb277e3:1111:999:2020:140:14:150:15:1111:2222:3333:160:16:4444:
mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906:3030:0:0:0:0:0:0:0:0:0:0:
powerless:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:1337:HEARTS:0:0:e0d07db8-f7e8-43c7-9ded-864dfc6f3b7c:5:1600906906:4040:0:0:0:0:0:0:0:0:0:0:
nossr50:1:IGNORED:IGNORED:10:2:20:3:4:5:6:7:8:9:10:30:40:50:60:70:80:90:100:IGNORED:11:110:111:222:333:444:555:666:777:IGNORED:12:120:888:IGNORED:HEARTS:13:130:588fe472-1c82-4c4e-9aa1-7eefccb277e3:1111:999:2020:140:14:150:15:1111:2222:3333:160:16:4444:170:17:5555:
mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906:3030:0:0:0:0:0:0:0:0:0:0:0:0:0:
powerless:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:1337:HEARTS:0:0:e0d07db8-f7e8-43c7-9ded-864dfc6f3b7c:5:1600906906:4040:0:0:0:0:0:0:0:0:0:0:0:0:0: