Skip to content

Commit

Permalink
Migrate most modifier hooks to the new hook system
Browse files Browse the repository at this point in the history
Still need to migrate capability related hooks, will do so in a later commit
  • Loading branch information
KnightMiner committed Nov 26, 2022
1 parent 7a9326e commit 16a5d27
Show file tree
Hide file tree
Showing 39 changed files with 654 additions and 202 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -735,7 +735,10 @@ public void onBreakSpeed(IToolStackView tool, int level, BreakSpeed event, Direc
* @param level Modifier level
* @param context Harvest context
* @param consumer Consumer accepting any enchantments
* @deprecated use {@link slimeknights.tconstruct.library.modifiers.hook.HarvestEnchantmentsModifierHook}
*/
@SuppressWarnings("DeprecatedIsStillUsed")
@Deprecated
public void applyHarvestEnchantments(IToolStackView tool, int level, ToolHarvestContext context, BiConsumer<Enchantment,Integer> consumer) {}

/**
Expand All @@ -747,7 +750,10 @@ public void applyHarvestEnchantments(IToolStackView tool, int level, ToolHarvest
* @param damageSource Damage source that killed the entity. May be null if this hook is called without attacking anything (e.g. shearing)
* @param looting Luck value set from previous modifiers
* @return New luck value
* @deprecated use {@link slimeknights.tconstruct.library.modifiers.hook.LootingModifierHook}
*/
@SuppressWarnings("DeprecatedIsStillUsed")
@Deprecated
public int getLootingValue(IToolStackView tool, int level, LivingEntity holder, Entity target, @Nullable DamageSource damageSource, int looting) {
return looting;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package slimeknights.tconstruct.library.modifiers;

import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.player.Player;
import slimeknights.mantle.client.TooltipKey;
import slimeknights.tconstruct.TConstruct;
import slimeknights.tconstruct.library.modifiers.hook.ArmorWalkModifierHook;
import slimeknights.tconstruct.library.modifiers.hook.ElytraFlightModifierHook;
import slimeknights.tconstruct.library.modifiers.hook.HarvestEnchantmentsModifierHook;
import slimeknights.tconstruct.library.modifiers.hook.InteractModifierHook;
import slimeknights.tconstruct.library.modifiers.hook.LootingModifierHook;
import slimeknights.tconstruct.library.modifiers.hook.PlantHarvestModifierHook;
import slimeknights.tconstruct.library.modifiers.hook.ShearsModifierHook;
import slimeknights.tconstruct.library.modifiers.hooks.IArmorInteractModifier;
import slimeknights.tconstruct.library.modifiers.hooks.IArmorLootModifier;
import slimeknights.tconstruct.library.modifiers.hooks.IArmorWalkModifier;
import slimeknights.tconstruct.library.modifiers.hooks.IElytraFlightModifier;
import slimeknights.tconstruct.library.modifiers.hooks.IHarvestModifier;
import slimeknights.tconstruct.library.modifiers.hooks.IShearModifier;
import slimeknights.tconstruct.library.tools.nbt.IToolStackView;

import javax.annotation.Nullable;
import java.util.Collection;
import java.util.function.Function;

/** Collection of all hooks implemented by the mod natively */
@SuppressWarnings("deprecation")
public class TinkerHooks {
private TinkerHooks() {}

/* Loot */

/** Hook for a tool boosting the looting value */
public static final ModifierHook<LootingModifierHook> TOOL_LOOTING = register("tool_looting", LootingModifierHook.class, LootingModifierHook.SUM_MERGER,
(tool, modifier, holder, target, damageSource, looting) -> modifier.getModifier().getLootingValue(tool, modifier.getLevel(), holder, target, damageSource, looting));

/** Hook for leggings boosting the tool's looting level */
public static final ModifierHook<LootingModifierHook> LEGGINGS_LOOTING = register("leggings_looting", LootingModifierHook.class, LootingModifierHook.SUM_MERGER, (tool, modifier, holder, target, damageSource, looting) -> {
IArmorLootModifier armorLoot = modifier.getModifier().getModule(IArmorLootModifier.class);
if (armorLoot != null) {
return armorLoot.getLootingValue(tool, modifier.getLevel(), holder, target, damageSource, looting);
}
return looting;
});

/** Hook for adding harvest enchantments to a held tool based on the tool's modifiers */
public static final ModifierHook<HarvestEnchantmentsModifierHook> TOOL_HARVEST_ENCHANTMENTS = register("tool_harvest_enchantments", HarvestEnchantmentsModifierHook.class, HarvestEnchantmentsModifierHook.ALL_MERGER,
(tool, modifier, context, consumer) -> modifier.getModifier().applyHarvestEnchantments(tool, modifier.getLevel(), context, consumer));

/** Hook for adding harvest enchantments to a held tool based on the legging's modifiers */
public static final ModifierHook<HarvestEnchantmentsModifierHook> LEGGINGS_HARVEST_ENCHANTMENTS = register("leggings_harvest_enchantments", HarvestEnchantmentsModifierHook.class, HarvestEnchantmentsModifierHook.ALL_MERGER, (tool, modifier, context, consumer) -> {
IArmorLootModifier armorLoot = modifier.getModifier().getModule(IArmorLootModifier.class);
if (armorLoot != null) {
armorLoot.applyHarvestEnchantments(tool, modifier.getLevel(), context, consumer);
}
});


/* Misc Armor */

/** Hook for when the player flies using an elytra, called on the chestplate slot */
public static final ModifierHook<ElytraFlightModifierHook> ELYTRA_FLIGHT = register("elytra_flight", ElytraFlightModifierHook.class, ElytraFlightModifierHook.FIRST_MERGER, (tool, modifier, entity, flightTicks) -> {
IElytraFlightModifier elytraFlight = modifier.getModifier().getModule(IElytraFlightModifier.class);
return elytraFlight != null && !elytraFlight.elytraFlightTick(tool, modifier.getLevel(), entity, flightTicks);
});

/** Hook for when the player walks from one position to another, called on the boots slot */
public static final ModifierHook<ArmorWalkModifierHook> BOOT_WALK = register("boot_walk", ArmorWalkModifierHook.class, ArmorWalkModifierHook.ALL_MERGER, (tool, modifier, living, prevPos, newPos) -> {
IArmorWalkModifier armorWalk = modifier.getModifier().getModule(IArmorWalkModifier.class);
if (armorWalk != null) {
armorWalk.onWalk(tool, modifier.getLevel(), living, prevPos, newPos);
}
});


/* Interaction */

/** Hook for when the player interacts with an armor slot. Currently only impleented for helmets and leggings */
public static final ModifierHook<InteractModifierHook> ARMOR_INTERACT = register("armor_interact", InteractModifierHook.class, InteractModifierHook.MERGER, new InteractModifierHook() {
@Override
public boolean startInteract(IToolStackView tool, ModifierEntry modifier, Player player, EquipmentSlot slot, TooltipKey keyModifier) {
IArmorInteractModifier interact = modifier.getModifier().getModule(IArmorInteractModifier.class);
if (interact != null) {
return interact.startArmorInteract(tool, modifier.getLevel(), player, slot, keyModifier);
}
return false;
}

@Override
public void stopInteract(IToolStackView tool, ModifierEntry modifier, Player player, EquipmentSlot slot) {
IArmorInteractModifier interact = modifier.getModifier().getModule(IArmorInteractModifier.class);
if (interact != null) {
interact.stopArmorInteract(tool, modifier.getLevel(), player, slot);
}
}
});

/* Modifier sub-hooks */

/** Hook called on all tool modifiers after the harvest modifier harvests a crop */
public static final ModifierHook<PlantHarvestModifierHook> PLANT_HARVEST = register("plant_harvest", PlantHarvestModifierHook.class, PlantHarvestModifierHook.ALL_MERGER, (tool, modifier, context, world, state, pos) -> {
IHarvestModifier plantHarvest = modifier.getModifier().getModule(IHarvestModifier.class);
if (plantHarvest != null) {
plantHarvest.afterHarvest(tool, modifier.getLevel(), context, world, state, pos);
}
});

/** Hook called on all tool modifiers after shearing an entity */
public static final ModifierHook<ShearsModifierHook> SHEAR_ENTITY = register("shear_entity", ShearsModifierHook.class, ShearsModifierHook.ALL_MERGER, new ShearsModifierHook() {
@Override
public void afterShearEntity(IToolStackView tool, ModifierEntry modifier, Player player, Entity entity, boolean isTarget) {
IShearModifier shearModifier = modifier.getModifier().getModule(IShearModifier.class);
if (shearModifier != null) {
shearModifier.afterShearEntity(tool, modifier.getLevel(), player, entity, isTarget);
}
}
});


/** Registers a new modifier hook under {@code tconstruct} */
private static <T> ModifierHook<T> register(String name, Class<T> filter, @Nullable Function<Collection<T>,T> merger, T defaultInstance) {
return ModifierHooks.register(TConstruct.getResource(name), filter, defaultInstance, merger);
}

/** Registers a new modifier hook under {@code tconstruct} that cannot merge */
private static <T> ModifierHook<T> register(String name, Class<T> filter, T defaultInstance) {
return register(name, filter, null, defaultInstance);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@
import slimeknights.mantle.data.GenericIntSerializer;
import slimeknights.mantle.data.GenericLoaderRegistry.IGenericLoader;
import slimeknights.tconstruct.library.modifiers.Modifier;
import slimeknights.tconstruct.library.modifiers.hooks.IArmorInteractModifier;
import slimeknights.tconstruct.library.modifiers.ModifierEntry;
import slimeknights.tconstruct.library.modifiers.TinkerHooks;
import slimeknights.tconstruct.library.modifiers.hook.InteractModifierHook;
import slimeknights.tconstruct.library.modifiers.impl.InventoryModifier;
import slimeknights.tconstruct.library.modifiers.util.ModifierHookMap.Builder;
import slimeknights.tconstruct.library.tools.capability.ToolInventoryCapability;
import slimeknights.tconstruct.library.tools.nbt.IToolStackView;

import javax.annotation.Nullable;

public class InventoryMenuModifier extends InventoryModifier implements IArmorInteractModifier {
public class InventoryMenuModifier extends InventoryModifier implements InteractModifierHook {
/** Loader instance */
public static final GenericIntSerializer<InventoryMenuModifier> LOADER = new GenericIntSerializer<>("size", InventoryMenuModifier::new, t -> t.slotsPerLevel);

Expand All @@ -32,18 +33,14 @@ public int getPriority() {
}

@Override
public boolean startArmorInteract(IToolStackView tool, int level, Player player, EquipmentSlot slot, TooltipKey modifier) {
public boolean startInteract(IToolStackView tool, ModifierEntry modifier, Player player, EquipmentSlot slot, TooltipKey keyModifier) {
return ToolInventoryCapability.tryOpenContainer(player.getItemBySlot(slot), tool, player, slot).consumesAction();
}

@SuppressWarnings("unchecked")
@Nullable
@Override
public <T> T getModule(Class<T> type) {
if (type == IArmorInteractModifier.class) {
return (T) this;
}
return super.getModule(type);
protected void registerHooks(Builder hookBuilder) {
super.registerHooks(hookBuilder);
hookBuilder.addHook(this, TinkerHooks.ARMOR_INTERACT);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@
import slimeknights.mantle.data.GenericLoaderRegistry.IGenericLoader;
import slimeknights.mantle.util.JsonHelper;
import slimeknights.tconstruct.library.modifiers.Modifier;
import slimeknights.tconstruct.library.modifiers.hooks.IArmorLootModifier;
import slimeknights.tconstruct.library.modifiers.ModifierEntry;
import slimeknights.tconstruct.library.modifiers.TinkerHooks;
import slimeknights.tconstruct.library.modifiers.hook.HarvestEnchantmentsModifierHook;
import slimeknights.tconstruct.library.modifiers.hook.LootingModifierHook;
import slimeknights.tconstruct.library.modifiers.util.ModifierHookMap.Builder;
import slimeknights.tconstruct.library.modifiers.util.ModifierLevelDisplay;
import slimeknights.tconstruct.library.tools.context.ToolHarvestContext;
import slimeknights.tconstruct.library.tools.nbt.IToolStackView;
Expand All @@ -24,7 +28,7 @@

/** Modifier to boost loot, from mobs or blocks */
@RequiredArgsConstructor
public class LootModifier extends Modifier implements IArmorLootModifier {
public class LootModifier extends Modifier implements LootingModifierHook, HarvestEnchantmentsModifierHook {
@Nullable
private final Enchantment enchantment;
private final int enchantmentLevel;
Expand All @@ -39,29 +43,29 @@ public LootModifier(int lootingLevel, ModifierLevelDisplay levelDisplay) {
this(null, 0, lootingLevel, levelDisplay);
}

@Override
protected void registerHooks(Builder hookBuilder) {
super.registerHooks(hookBuilder);
hookBuilder.addHook(this, TinkerHooks.TOOL_LOOTING, TinkerHooks.LEGGINGS_LOOTING, TinkerHooks.TOOL_HARVEST_ENCHANTMENTS, TinkerHooks.LEGGINGS_HARVEST_ENCHANTMENTS);
}

@Override
public Component getDisplayName(int level) {
return levelDisplay.nameForLevel(this, level);
}

@Override
public int getLootingValue(IToolStackView tool, int level, LivingEntity holder, Entity target, @org.jetbrains.annotations.Nullable DamageSource damageSource, int looting) {
return looting + (this.lootingLevel * level);
public int getLootingValue(IToolStackView tool, ModifierEntry modifier, LivingEntity holder, Entity target, @Nullable DamageSource damageSource, int looting) {
return looting + (this.lootingLevel * modifier.getLevel());
}

@Override
public void applyHarvestEnchantments(IToolStackView tool, int level, ToolHarvestContext context, BiConsumer<Enchantment,Integer> consumer) {
public void applyHarvestEnchantments(IToolStackView tool, ModifierEntry modifier, ToolHarvestContext context, BiConsumer<Enchantment,Integer> consumer) {
if (enchantment != null && enchantmentLevel > 0) {
consumer.accept(enchantment, enchantmentLevel * level);
consumer.accept(enchantment, enchantmentLevel * modifier.getLevel());
}
}

@Nullable
@Override
public <T> T getModule(Class<T> type) {
return tryModuleMatch(type, IArmorLootModifier.class, this);
}

@Override
public IGenericLoader<? extends Modifier> getLoader() {
return LOADER;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package slimeknights.tconstruct.library.modifiers.hook;

import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.LivingEntity;
import slimeknights.tconstruct.library.modifiers.ModifierEntry;
import slimeknights.tconstruct.library.tools.nbt.IToolStackView;

import java.util.Collection;
import java.util.function.Function;

/**
* Modifier hook for boots when the player walks
*/
public interface ArmorWalkModifierHook {
/** Empty implementation for the sake of default behavior */
ArmorWalkModifierHook EMPTY = (tool, modifier, living, prevPos, newPos) -> {};

/** Constructor for a merger that runs all hooks from the children */
Function<Collection<ArmorWalkModifierHook>, ArmorWalkModifierHook> ALL_MERGER = AllMerger::new;


/**
* Called when an entity's block position changes
* @param tool Tool in boots slot
* @param modifier Entry calling this hook
* @param living Living entity instance
* @param prevPos Previous block position
* @param newPos New block position, will match the entity's position
*/
void onWalk(IToolStackView tool, ModifierEntry modifier, LivingEntity living, BlockPos prevPos, BlockPos newPos);


/** Walk modifier hook merger: runs hooks of all children */
record AllMerger(Collection<ArmorWalkModifierHook> modules) implements ArmorWalkModifierHook {
@Override
public void onWalk(IToolStackView tool, ModifierEntry modifier, LivingEntity living, BlockPos prevPos, BlockPos newPos) {
for (ArmorWalkModifierHook module : modules) {
module.onWalk(tool, modifier, living, prevPos, newPos);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package slimeknights.tconstruct.library.modifiers.hook;

import net.minecraft.world.entity.LivingEntity;
import slimeknights.tconstruct.library.modifiers.ModifierEntry;
import slimeknights.tconstruct.library.tools.nbt.IToolStackView;

import java.util.Collection;
import java.util.function.Function;

/** Hook for chestplate modifiers to control eltyra flight behavior */
public interface ElytraFlightModifierHook {
/** Default implementation */
ElytraFlightModifierHook DEFAULT = (tool, modifier, entity, flightTicks) -> true;

/** Constructor for a merger that stops after the first hook returns */
Function<Collection<ElytraFlightModifierHook>, ElytraFlightModifierHook> FIRST_MERGER = FirstMerger::new;


/**
* Call on elytra flight tick to run any update effects
* @param tool Elytra instance
* @param modifier Entry calling this hook
* @param entity Entity flying
* @param flightTicks Number of ticks the elytra has been in the air
* @return True if the elytra should stop flying
*/
boolean elytraFlightTick(IToolStackView tool, ModifierEntry modifier, LivingEntity entity, int flightTicks);


/** Flight merger: stops once the first hook says to stop flying */
record FirstMerger(Collection<ElytraFlightModifierHook> modules) implements ElytraFlightModifierHook {
@Override
public boolean elytraFlightTick(IToolStackView tool, ModifierEntry modifier, LivingEntity entity, int flightTicks) {
for (ElytraFlightModifierHook module : modules) {
if (module.elytraFlightTick(tool, modifier, entity, flightTicks)) {
return true;
}
}
return false;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package slimeknights.tconstruct.library.modifiers.hook;

import net.minecraft.world.item.enchantment.Enchantment;
import slimeknights.tconstruct.library.modifiers.ModifierEntry;
import slimeknights.tconstruct.library.tools.context.ToolHarvestContext;
import slimeknights.tconstruct.library.tools.nbt.IToolStackView;

import java.util.Collection;
import java.util.function.BiConsumer;
import java.util.function.Function;

/** Modifier hook implementing bonus enchantments from a tool, applied directly before block break. Can implement separately for leggings and tools if desired via the different hooks */
public interface HarvestEnchantmentsModifierHook {
HarvestEnchantmentsModifierHook EMPTY = (tool, modifier, context, consumer) -> {};

/** Merger that runs all submodules */
Function<Collection<HarvestEnchantmentsModifierHook>,HarvestEnchantmentsModifierHook> ALL_MERGER = AllMerger::new;

/**
* Adds harvest loot table related enchantments from this modifier's effect to the tool, called before breaking a block.
* Needed to add enchantments for silk touch and fortune. Can add conditionally if needed. Only affects tinker tools
* For looting, see {@link LootingModifierHook}
* @param tool Tool used
* @param modifier Modifier used
* @param context Harvest context
* @param consumer Consumer accepting any enchantments
*/
void applyHarvestEnchantments(IToolStackView tool, ModifierEntry modifier, ToolHarvestContext context, BiConsumer<Enchantment,Integer> consumer);


/** Merger that runs all submodules */
record AllMerger(Collection<HarvestEnchantmentsModifierHook> modules) implements HarvestEnchantmentsModifierHook {
@Override
public void applyHarvestEnchantments(IToolStackView tool, ModifierEntry modifier, ToolHarvestContext context, BiConsumer<Enchantment,Integer> consumer) {
for (HarvestEnchantmentsModifierHook module : modules) {
module.applyHarvestEnchantments(tool, modifier, context, consumer);
}
}
}
}

0 comments on commit 16a5d27

Please sign in to comment.