fix issues with Alchemy and older MC versions

This commit is contained in:
nossr50
2024-05-03 13:53:53 -07:00
parent 5b822bc626
commit 75561350c1
14 changed files with 165 additions and 128 deletions

View File

@ -15,15 +15,14 @@ import org.bukkit.inventory.meta.PotionMeta;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.potion.PotionType;
import org.codehaus.plexus.util.StringUtils;
import org.jetbrains.annotations.VisibleForTesting;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import static com.gmail.nossr50.util.PotionUtil.*;
import static com.gmail.nossr50.util.text.StringUtils.convertKeyToName;
public class PotionConfig extends LegacyConfigLoader {
@ -130,7 +129,7 @@ public class PotionConfig extends LegacyConfigLoader {
final String key = potion_section.getName();
final String displayName = potion_section.getString("Name") != null
? LocaleLoader.addColors(potion_section.getString("Name"))
: null;
: convertKeyToName(key);
final ConfigurationSection potionData = potion_section.getConfigurationSection("PotionData");
boolean extended = false;
@ -165,12 +164,16 @@ public class PotionConfig extends LegacyConfigLoader {
return null;
}
// Set the name of the potion
potionMeta.setDisplayName(displayName);
// extended and upgraded seem to be mutually exclusive
if (extended && upgraded) {
mcMMO.p.getLogger().warning("Potion " + key + " has both Extended and Upgraded set to true," +
" defaulting to Extended.");
upgraded = false;
}
String potionTypeStr = potionData.getString("PotionType", null);
if (potionTypeStr == null) {
mcMMO.p.getLogger().severe("PotionConfig: Missing PotionType for " + displayName + ", from configuration section:" +
@ -186,7 +189,9 @@ public class PotionConfig extends LegacyConfigLoader {
}
if (potionType == null) {
mcMMO.p.getLogger().severe("PotionConfig: Failed to parse potion type for: " + potionTypeStr);
mcMMO.p.getLogger().severe("PotionConfig: Failed to parse potion type for: " + potionTypeStr
+ ", upgraded: " + upgraded + ", extended: " + extended + " for potion " + displayName
+ ", from configuration section: " + potion_section);
return null;
}
@ -357,5 +362,4 @@ public class PotionConfig extends LegacyConfigLoader {
}
return Color.fromRGB(red / colors.size(), green / colors.size(), blue / colors.size());
}
}

View File

@ -7,7 +7,6 @@ import org.bukkit.inventory.meta.PotionMeta;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
@ -16,18 +15,18 @@ import static com.gmail.nossr50.util.PotionUtil.samePotionType;
import static java.util.Objects.requireNonNull;
public class AlchemyPotion {
private final ItemStack potion;
private final Map<ItemStack, String> alchemyPotionChildren;
private final @NotNull ItemStack potionItemstack;
private final @NotNull Map<ItemStack, String> alchemyPotionChildren;
public AlchemyPotion(ItemStack potion, Map<ItemStack, String> alchemyPotionChildren) {
this.potion = requireNonNull(potion, "potion cannot be null");
public AlchemyPotion(@NotNull ItemStack potionItemStack, @NotNull Map<ItemStack, String> alchemyPotionChildren) {
this.potionItemstack = requireNonNull(potionItemStack, "potionItemStack cannot be null");
this.alchemyPotionChildren = requireNonNull(alchemyPotionChildren, "alchemyPotionChildren cannot be null");
}
public @NotNull ItemStack toItemStack(int amount) {
final ItemStack potion = new ItemStack(this.potion);
potion.setAmount(Math.max(1, amount));
return potion;
final ItemStack clone = potionItemstack.clone();
clone.setAmount(Math.max(1, amount));
return clone;
}
public Map<ItemStack, String> getAlchemyPotionChildren() {
@ -49,7 +48,7 @@ public class AlchemyPotion {
requireNonNull(otherPotion, "otherPotion cannot be null");
// TODO: Investigate?
// We currently don't compare base potion effects, likely because they are derived from the potion type
if (otherPotion.getType() != potion.getType() || !otherPotion.hasItemMeta()) {
if (otherPotion.getType() != potionItemstack.getType() || !otherPotion.hasItemMeta()) {
return false;
}
@ -76,25 +75,19 @@ public class AlchemyPotion {
return false;
}
if (!otherPotionMeta.hasDisplayName() && getAlchemyPotionMeta().hasDisplayName()) {
return false;
}
var alchemyPotionName = getAlchemyPotionMeta().hasDisplayName() ? getAlchemyPotionMeta().getDisplayName() : null;
return (alchemyPotionName == null && !otherPotionMeta.hasDisplayName()) || otherPotionMeta.getDisplayName().equals(alchemyPotionName);
return true;
}
public PotionMeta getAlchemyPotionMeta() {
return (PotionMeta) potion.getItemMeta();
return (PotionMeta) potionItemstack.getItemMeta();
}
public boolean isSplash() {
return potion.getType() == Material.SPLASH_POTION;
return potionItemstack.getType() == Material.SPLASH_POTION;
}
public boolean isLingering() {
return potion.getType() == Material.LINGERING_POTION;
return potionItemstack.getType() == Material.LINGERING_POTION;
}
@Override
@ -102,18 +95,18 @@ public class AlchemyPotion {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
AlchemyPotion that = (AlchemyPotion) o;
return Objects.equals(potion, that.potion) && Objects.equals(alchemyPotionChildren, that.alchemyPotionChildren);
return Objects.equals(potionItemstack, that.potionItemstack) && Objects.equals(alchemyPotionChildren, that.alchemyPotionChildren);
}
@Override
public int hashCode() {
return Objects.hash(potion, alchemyPotionChildren);
return Objects.hash(potionItemstack, alchemyPotionChildren);
}
@Override
public String toString() {
return "AlchemyPotion{" +
"potion=" + potion +
"potion=" + potionItemstack +
", alchemyPotionChildren=" + alchemyPotionChildren +
'}';
}

View File

@ -136,7 +136,7 @@ public class Roll extends AcrobaticsSubSkill {
* Graceful is double the odds of a normal roll
*/
Probability probability = getRollProbability(player);
Probability gracefulProbability = Probability.ofPercent(probability.getValue() * 2);
Probability gracefulProbability = Probability.ofValue(probability.getValue() * 2);
String[] gracefulRollStrings = ProbabilityUtil.getRNGDisplayValues(gracefulProbability);
gracefulRollChance = gracefulRollStrings[0];
gracefulRollChanceLucky = gracefulRollStrings[1];
@ -274,7 +274,7 @@ public class Roll extends AcrobaticsSubSkill {
@NotNull
public static Probability getGracefulProbability(Player player) {
double gracefulOdds = ProbabilityUtil.getSubSkillProbability(SubSkillType.ACROBATICS_ROLL, player).getValue() * 2;
return Probability.ofPercent(gracefulOdds);
return Probability.ofValue(gracefulOdds);
}
/**

View File

@ -0,0 +1,18 @@
package com.gmail.nossr50.protocollib;
import com.gmail.nossr50.mcMMO;
import org.bukkit.plugin.Plugin;
// TODO: Finish this class
public class ProtocolLibManager {
Plugin protocolLibPluginRef;
mcMMO pluginRef;
public ProtocolLibManager(mcMMO pluginRef) {
this.pluginRef = pluginRef;
}
public boolean isProtocolLibPresent() {
protocolLibPluginRef = pluginRef.getServer().getPluginManager().getPlugin("ProtocolLib");
return protocolLibPluginRef != null;
}
}

View File

@ -3,6 +3,7 @@ package com.gmail.nossr50.runnables.skills;
import com.gmail.nossr50.skills.alchemy.Alchemy;
import com.gmail.nossr50.skills.alchemy.AlchemyPotionBrewer;
import com.gmail.nossr50.util.CancellableRunnable;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.block.BrewingStand;
import org.bukkit.entity.Player;
@ -31,8 +32,7 @@ public class AlchemyBrewCheckTask extends CancellableRunnable {
if (oldInventory[Alchemy.INGREDIENT_SLOT] == null || newInventory[Alchemy.INGREDIENT_SLOT] == null || !oldInventory[Alchemy.INGREDIENT_SLOT].isSimilar(newInventory[Alchemy.INGREDIENT_SLOT]) || !validBrew) {
Alchemy.brewingStandMap.get(location).cancelBrew();
}
}
else if (validBrew) {
} else if (validBrew) {
Alchemy.brewingStandMap.put(location, new AlchemyBrewTask(brewingStand, player));
}
}

View File

@ -11,6 +11,7 @@ import com.gmail.nossr50.util.CancellableRunnable;
import com.gmail.nossr50.util.Misc;
import com.gmail.nossr50.util.Permissions;
import com.gmail.nossr50.util.player.UserManager;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.BlockState;
@ -67,33 +68,65 @@ public class AlchemyBrewTask extends CancellableRunnable {
@Override
public void run() {
if (player == null || !player.isValid() || brewingStand == null || brewingStand.getType() != Material.BREWING_STAND || !AlchemyPotionBrewer.isValidIngredient(player, ((BrewingStand) brewingStand).getInventory().getContents()[Alchemy.INGREDIENT_SLOT])) {
// Check if preconditions for brewing are not met
if (shouldCancelBrewing()) {
if (Alchemy.brewingStandMap.containsKey(location)) {
Alchemy.brewingStandMap.remove(location);
}
this.cancel();
return;
}
// Initialize the brewing stand on the first run
initializeBrewing();
// Update the brewing process timer
brewTimer -= brewSpeed;
// Check if the brewing process should finish
if (isBrewingComplete()) {
this.cancel();
finish();
} else {
updateBrewingTime();
}
}
private boolean shouldCancelBrewing() {
if (player == null) {
return true;
}
if (!player.isValid()) {
return true;
}
if (brewingStand == null) {
return true;
}
if (brewingStand.getType() != Material.BREWING_STAND) {
return true;
}
if (!AlchemyPotionBrewer.isValidIngredient(player, ((BrewingStand) brewingStand).getInventory().getContents()[Alchemy.INGREDIENT_SLOT])) {
return true;
}
return false;
}
private void initializeBrewing() {
if (firstRun) {
firstRun = false;
((BrewingStand) brewingStand).setFuelLevel(fuel);
}
brewTimer -= brewSpeed;
// Vanilla potion brewing completes when BrewingTime == 1
if (brewTimer < Math.max(brewSpeed, 2)) {
this.cancel();
finish();
}
else {
((BrewingStand) brewingStand).setBrewingTime((int) brewTimer);
}
}
private boolean isBrewingComplete() {
return brewTimer < Math.max(brewSpeed, 2);
}
private void updateBrewingTime() {
((BrewingStand) brewingStand).setBrewingTime((int) brewTimer);
}
private void finish() {
McMMOPlayerBrewEvent event = new McMMOPlayerBrewEvent(player, brewingStand);
mcMMO.p.getServer().getPluginManager().callEvent(event);

View File

@ -11,40 +11,6 @@ import java.util.List;
import java.util.Map;
public final class Alchemy {
/*public enum Tier {
EIGHT(8),
SEVEN(7),
SIX(6),
FIVE(5),
FOUR(4),
THREE(3),
TWO(2),
ONE(1);
int numerical;
private Tier(int numerical) {
this.numerical = numerical;
}
public int toNumerical() {
return numerical;
}
public static Tier fromNumerical(int numerical) {
for (Tier tier : Tier.values()) {
if (tier.toNumerical() == numerical) {
return tier;
}
}
return null;
}
protected int getLevel() {
return mcMMO.p.getAdvancedConfig().getConcoctionsTierLevel(this);
}
}*/
public static final int INGREDIENT_SLOT = 3;
public static int catalysisMaxBonusLevel = mcMMO.p.getAdvancedConfig().getCatalysisMaxBonusLevel();

View File

@ -9,6 +9,7 @@ import com.gmail.nossr50.runnables.player.PlayerUpdateInventoryTask;
import com.gmail.nossr50.runnables.skills.AlchemyBrewCheckTask;
import com.gmail.nossr50.util.Permissions;
import com.gmail.nossr50.util.player.UserManager;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.block.BlockState;
import org.bukkit.block.BrewingStand;
@ -31,7 +32,9 @@ public final class AlchemyPotionBrewer {
}
for (int i = 0; i < 3; i++) {
if (contents[i] == null || contents[i].getType() != Material.POTION && contents[i].getType() != Material.SPLASH_POTION && contents[i].getType() != Material.LINGERING_POTION) {
if (contents[i] == null || contents[i].getType() != Material.POTION
&& contents[i].getType() != Material.SPLASH_POTION
&& contents[i].getType() != Material.LINGERING_POTION) {
continue;
}
@ -101,52 +104,71 @@ public final class AlchemyPotionBrewer {
}
public static void finishBrewing(BlockState brewingStand, Player player, boolean forced) {
// Check if the brewing stand block state is an actual brewing stand
if (!(brewingStand instanceof BrewingStand)) {
return;
}
BrewerInventory inventory = ((BrewingStand) brewingStand).getInventory();
ItemStack ingredient = inventory.getIngredient() == null ? null : inventory.getIngredient().clone();
// Retrieve the inventory of the brewing stand and clone the current ingredient for safe manipulation
final BrewerInventory inventory = ((BrewingStand) brewingStand).getInventory();
final ItemStack ingredient = inventory.getIngredient() == null ? null : inventory.getIngredient().clone();
// Check if the brewing stand has a valid ingredient; if not, exit the method
if (!hasIngredient(inventory, player)) {
// debug
return;
}
// Initialize lists to hold the potions before and after brewing, initially setting them to null
List<AlchemyPotion> inputList = new ArrayList<>(Collections.nCopies(3, null));
List<ItemStack> outputList = new ArrayList<>(Collections.nCopies(3, null));
// Process each of the three slots in the brewing stand
for (int i = 0; i < 3; i++) {
ItemStack item = inventory.getItem(i);
if (isEmpty(item) || item.getType() == Material.GLASS_BOTTLE || !mcMMO.p.getPotionConfig().isValidPotion(item)) {
// Skip the slot if it's empty, contains a glass bottle, or holds an invalid potion
if (isEmpty(item)
|| item.getType() == Material.GLASS_BOTTLE
|| !mcMMO.p.getPotionConfig().isValidPotion(item)) {
// debug
continue;
}
// Retrieve the potion configurations for the input and resulting output potion
AlchemyPotion input = mcMMO.p.getPotionConfig().getPotion(item);
AlchemyPotion output = input.getChild(ingredient);
// Update the input list with the current potion
inputList.set(i, input);
// If there is a valid output potion, add it to the output list
if (output != null) {
outputList.set(i, output.toItemStack(item.getAmount()).clone());
}
}
// Create a fake brewing event and pass it to the plugin's event system
FakeBrewEvent event = new FakeBrewEvent(brewingStand.getBlock(), inventory, outputList, ((BrewingStand) brewingStand).getFuelLevel());
mcMMO.p.getServer().getPluginManager().callEvent(event);
// If the event is cancelled or there are no potions processed, exit the method
if (event.isCancelled() || inputList.isEmpty()) {
// debug
return;
}
// Update the brewing inventory with the new potions
for (int i = 0; i < 3; i++) {
if(outputList.get(i) != null) {
inventory.setItem(i, outputList.get(i));
}
}
// Remove the used ingredient from the brewing inventory
removeIngredient(inventory, player);
// Handle potion brewing success and related effects for each potion processed
for (AlchemyPotion input : inputList) {
if (input == null) continue;
@ -155,13 +177,14 @@ public final class AlchemyPotionBrewer {
if (output != null && player != null) {
PotionStage potionStage = PotionStage.getPotionStage(input, output);
//TODO: hmm
// Update player alchemy skills or effects based on brewing success
if (UserManager.hasPlayerDataKey(player)) {
UserManager.getPlayer(player).getAlchemyManager().handlePotionBrewSuccesses(potionStage, 1);
}
}
}
// If the brewing was not forced by external conditions, schedule a new update
if (!forced) {
scheduleUpdate(inventory);
}

View File

@ -39,6 +39,7 @@ public class PotionUtil {
static {
// We used to use uncraftable as the potion type
// this type isn't available anymore, so water will do
potionDataClass = getPotionDataClass();
legacyPotionTypes.put("UNCRAFTABLE", "WATER");
legacyPotionTypes.put("JUMP", "LEAPING");
legacyPotionTypes.put("SPEED", "SWIFTNESS");
@ -55,9 +56,8 @@ public class PotionUtil {
methodPotionTypeGetEffectType = getPotionTypeEffectType();
methodPotionTypeGetPotionEffects = getPotionTypeGetPotionEffects();
methodSetBasePotionData = getSetBasePotionData();
potionDataClass = getPotionDataClass();
if (methodPotionMetaGetBasePotionData != null) {
if (potionDataClass != null) {
COMPATIBILITY_MODE = PotionCompatibilityType.PRE_1_20_5;
} else {
COMPATIBILITY_MODE = PotionCompatibilityType.POST_1_20_5;
@ -161,7 +161,7 @@ public class PotionUtil {
*/
private static @Nullable Method getBasePotionData() {
try {
return PotionType.class.getMethod("getBasePotionData");
return PotionMeta.class.getMethod("getBasePotionData");
} catch (NoSuchMethodException e) {
return null;
}
@ -419,7 +419,7 @@ public class PotionUtil {
* @param upgraded true if the potion is upgraded
*/
public static void setBasePotionType(PotionMeta potionMeta, PotionType potionType, boolean extended, boolean upgraded) {
if (COMPATIBILITY_MODE == PotionCompatibilityType.PRE_1_20_5) {
if (methodPotionMetaSetBasePotionType == null) {
setBasePotionTypeLegacy(potionMeta, potionType, extended, upgraded);
} else {
setBasePotionTypeModern(potionMeta, potionType);

View File

@ -186,4 +186,9 @@ public class StringUtils {
}
}
public static String convertKeyToName(@NotNull String key) {
// used when no display name is given for a potion
final String noUnderscores = key.replace("_", " ").toLowerCase(Locale.ENGLISH);
return org.codehaus.plexus.util.StringUtils.capitalise(noUnderscores);
}
}