media can now be drawn from trinkets, armor, and offhand

also, armor can no longer keep you safe from the subsuming of your mind
This commit is contained in:
yrsegal@gmail.com 2022-08-16 22:11:51 -04:00
parent 3a1bd29658
commit 8c13fc22dc
15 changed files with 353 additions and 55 deletions

View file

@ -0,0 +1,42 @@
package at.petrak.hexcasting.api.misc;
import at.petrak.hexcasting.api.addldata.ManaHolder;
import at.petrak.hexcasting.api.spell.casting.CastingHarness;
import com.google.common.collect.Lists;
import net.minecraft.world.entity.player.Player;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;
public class DiscoveryHandlers {
private static final List<Predicate<Player>> HAS_LENS_PREDICATE = new ArrayList<>();
private static final List<Function<CastingHarness, List<ManaHolder>>> MANA_HOLDER_DISCOVERY = new ArrayList<>();
public static boolean hasLens(Player player) {
for (var predicate : HAS_LENS_PREDICATE) {
if (predicate.test(player)) {
return true;
}
}
return false;
}
public static List<ManaHolder> collectManaHolders(CastingHarness harness) {
List<ManaHolder> holders = Lists.newArrayList();
for (var discoverer : MANA_HOLDER_DISCOVERY) {
holders.addAll(discoverer.apply(harness));
}
return holders;
}
public static void addLensPredicate(Predicate<Player> predicate) {
HAS_LENS_PREDICATE.add(predicate);
}
public static void addManaHolderDiscoverer(Function<CastingHarness, List<ManaHolder>> discoverer) {
MANA_HOLDER_DISCOVERY.add(discoverer);
}
}

View file

@ -3,6 +3,7 @@ package at.petrak.hexcasting.api.spell.casting
import at.petrak.hexcasting.api.PatternRegistry import at.petrak.hexcasting.api.PatternRegistry
import at.petrak.hexcasting.api.advancements.HexAdvancementTriggers import at.petrak.hexcasting.api.advancements.HexAdvancementTriggers
import at.petrak.hexcasting.api.block.circle.BlockEntityAbstractImpetus import at.petrak.hexcasting.api.block.circle.BlockEntityAbstractImpetus
import at.petrak.hexcasting.api.misc.DiscoveryHandlers
import at.petrak.hexcasting.api.misc.FrozenColorizer import at.petrak.hexcasting.api.misc.FrozenColorizer
import at.petrak.hexcasting.api.misc.HexDamageSources import at.petrak.hexcasting.api.misc.HexDamageSources
import at.petrak.hexcasting.api.mod.HexConfig import at.petrak.hexcasting.api.mod.HexConfig
@ -13,7 +14,6 @@ import at.petrak.hexcasting.api.spell.math.HexDir
import at.petrak.hexcasting.api.spell.math.HexPattern import at.petrak.hexcasting.api.spell.math.HexPattern
import at.petrak.hexcasting.api.spell.mishaps.* import at.petrak.hexcasting.api.spell.mishaps.*
import at.petrak.hexcasting.api.utils.* import at.petrak.hexcasting.api.utils.*
import at.petrak.hexcasting.common.items.magic.ItemCreativeUnlocker
import at.petrak.hexcasting.xplat.IXplatAbstractions import at.petrak.hexcasting.xplat.IXplatAbstractions
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.Tag import net.minecraft.nbt.Tag
@ -404,12 +404,12 @@ class CastingHarness private constructor(
} else { } else {
false false
} }
if (casterStack.`is`(HexItemTags.WANDS) || hexHolderDrawsFromInventory) { if (casterStack.`is`(HexItemTags.WANDS) || hexHolderDrawsFromInventory) {
val manableItems = this.ctx.caster.inventory.items val manaSources = DiscoveryHandlers.collectManaHolders(this)
.filter(::isManaItem)
.sortedWith(Comparator(::compareManaItem).reversed()) .sortedWith(Comparator(::compareManaItem).reversed())
for (stack in manableItems) { for (source in manaSources) {
costLeft -= extractMana(stack, costLeft, simulate = fake && !ItemCreativeUnlocker.isDebug(stack)) costLeft -= extractMana(source, costLeft, simulate = fake)
if (costLeft <= 0) if (costLeft <= 0)
break break
} }
@ -421,13 +421,17 @@ class CastingHarness private constructor(
val manaAbleToCastFromHP = this.ctx.caster.health * manaToHealth val manaAbleToCastFromHP = this.ctx.caster.health * manaToHealth
val manaToActuallyPayFor = min(manaAbleToCastFromHP.toInt(), costLeft) val manaToActuallyPayFor = min(manaAbleToCastFromHP.toInt(), costLeft)
if (!fake) { costLeft -= if (!fake) {
HexAdvancementTriggers.OVERCAST_TRIGGER.trigger(this.ctx.caster, manaToActuallyPayFor)
this.ctx.caster.awardStat(HexStatistics.MANA_OVERCASTED, manaCost - costLeft)
Mishap.trulyHurt(this.ctx.caster, HexDamageSources.OVERCAST, healthtoRemove.toFloat()) Mishap.trulyHurt(this.ctx.caster, HexDamageSources.OVERCAST, healthtoRemove.toFloat())
val actuallyTaken = (manaAbleToCastFromHP - (this.ctx.caster.health * manaToHealth)).toInt()
HexAdvancementTriggers.OVERCAST_TRIGGER.trigger(this.ctx.caster, actuallyTaken)
this.ctx.caster.awardStat(HexStatistics.MANA_OVERCASTED, manaCost - costLeft)
actuallyTaken
} else {
manaToActuallyPayFor
} }
costLeft -= manaToActuallyPayFor
} }
} }
} }
@ -475,6 +479,24 @@ class CastingHarness private constructor(
const val TAG_ESCAPE_NEXT = "escape_next" const val TAG_ESCAPE_NEXT = "escape_next"
const val TAG_PREPACKAGED_COLORIZER = "prepackaged_colorizer" const val TAG_PREPACKAGED_COLORIZER = "prepackaged_colorizer"
init {
DiscoveryHandlers.addManaHolderDiscoverer {
it.ctx.caster.inventory.items
.filter(::isManaItem)
.mapNotNull(IXplatAbstractions.INSTANCE::findManaHolder)
}
DiscoveryHandlers.addManaHolderDiscoverer {
it.ctx.caster.armorSlots
.filter(::isManaItem)
.mapNotNull(IXplatAbstractions.INSTANCE::findManaHolder)
}
DiscoveryHandlers.addManaHolderDiscoverer {
listOf(it.ctx.caster.offhandItem)
.filter(::isManaItem)
.mapNotNull(IXplatAbstractions.INSTANCE::findManaHolder)
}
}
@JvmStatic @JvmStatic
fun fromNBT(nbt: CompoundTag, ctx: CastingContext): CastingHarness { fun fromNBT(nbt: CompoundTag, ctx: CastingContext): CastingHarness {
return try { return try {

View file

@ -10,7 +10,7 @@ import at.petrak.hexcasting.api.spell.math.HexPattern
import at.petrak.hexcasting.api.utils.asTranslatedComponent import at.petrak.hexcasting.api.utils.asTranslatedComponent
import at.petrak.hexcasting.api.utils.lightPurple import at.petrak.hexcasting.api.utils.lightPurple
import at.petrak.hexcasting.common.lib.HexItems import at.petrak.hexcasting.common.lib.HexItems
import at.petrak.hexcasting.ktxt.lastHurt import at.petrak.hexcasting.ktxt.*
import net.minecraft.Util import net.minecraft.Util
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
@ -109,7 +109,25 @@ sealed class Mishap : Throwable() {
else else
entity.lastHurt -= amount entity.lastHurt -= amount
} }
entity.hurt(source, amount) if (!entity.hurt(source, amount)) {
// Ok, if you REALLY don't want to play nice...
entity.health -= amount
entity.markHurt()
if (entity.isDeadOrDying) {
if (!entity.checkTotemDeathProtection(source)) {
val sound = entity.deathSoundAccessor
if (sound != null) {
entity.playSound(sound, entity.soundVolumeAccessor, entity.voicePitch)
}
entity.die(source)
}
} else {
entity.playHurtSound(source)
}
entity.setHurtWithStamp(source, entity.level.gameTime)
}
} }
} }
} }

View file

@ -1,6 +1,7 @@
@file:JvmName("ManaHelper") @file:JvmName("ManaHelper")
package at.petrak.hexcasting.api.utils package at.petrak.hexcasting.api.utils
import at.petrak.hexcasting.api.addldata.ManaHolder
import at.petrak.hexcasting.xplat.IXplatAbstractions import at.petrak.hexcasting.xplat.IXplatAbstractions
import net.minecraft.util.Mth import net.minecraft.util.Mth
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
@ -30,26 +31,38 @@ fun extractMana(
): Int { ): Int {
val manaHolder = IXplatAbstractions.INSTANCE.findManaHolder(stack) ?: return 0 val manaHolder = IXplatAbstractions.INSTANCE.findManaHolder(stack) ?: return 0
if (drainForBatteries && !manaHolder.canConstructBattery()) return extractMana(manaHolder, cost, drainForBatteries, simulate)
}
/**
* Extract [cost] mana from [holder]. If [cost] is less than zero, extract all mana instead.
* This may mutate the stack underlying [holder] (and may consume it) unless [simulate] is set.
*
* If [drainForBatteries] is false, this will only consider forms of mana that can be used to make new batteries.
*
* Return the amount of mana extracted. This may be over [cost] if mana is wasted.
*/
fun extractMana(
holder: ManaHolder,
cost: Int = -1,
drainForBatteries: Boolean = false,
simulate: Boolean = false
): Int {
if (drainForBatteries && !holder.canConstructBattery())
return 0 return 0
return manaHolder.withdrawMana(cost, simulate) return holder.withdrawMana(cost, simulate)
} }
/** /**
* Sorted from least important to most important * Sorted from least important to most important
*/ */
fun compareManaItem(astack: ItemStack, bstack: ItemStack): Int { fun compareManaItem(aMana: ManaHolder, bMana: ManaHolder): Int {
val aMana = IXplatAbstractions.INSTANCE.findManaHolder(astack) val priority = aMana.consumptionPriority - bMana.consumptionPriority
val bMana = IXplatAbstractions.INSTANCE.findManaHolder(bstack) if (priority != 0)
return priority
return if (astack.item != bstack.item) { return aMana.mana - bMana.mana
(aMana?.consumptionPriority ?: 0) - (bMana?.consumptionPriority ?: 0)
} else if (aMana != null && bMana != null) {
aMana.mana - bMana.mana
} else {
astack.count - bstack.count
}
} }
fun manaBarColor(mana: Int, maxMana: Int): Int { fun manaBarColor(mana: Int, maxMana: Int): Int {

View file

@ -1,8 +1,8 @@
package at.petrak.hexcasting.client; package at.petrak.hexcasting.client;
import at.petrak.hexcasting.api.client.ScryingLensOverlayRegistry; import at.petrak.hexcasting.api.client.ScryingLensOverlayRegistry;
import at.petrak.hexcasting.api.misc.DiscoveryHandlers;
import at.petrak.hexcasting.api.player.Sentinel; import at.petrak.hexcasting.api.player.Sentinel;
import at.petrak.hexcasting.common.items.ItemLens;
import at.petrak.hexcasting.xplat.IXplatAbstractions; import at.petrak.hexcasting.xplat.IXplatAbstractions;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.platform.GlStateManager;
@ -155,7 +155,7 @@ public class HexAdditionalRenderers {
return; return;
} }
if (!ItemLens.hasLensHUD(player)) if (!DiscoveryHandlers.hasLens(player))
return; return;
var hitRes = mc.hitResult; var hitRes = mc.hitResult;

View file

@ -20,7 +20,7 @@ class OpExplode(val fire: Boolean) : SpellOperator {
val strength = args.getChecked<Double>(1, argc) val strength = args.getChecked<Double>(1, argc)
ctx.assertVecInRange(pos) ctx.assertVecInRange(pos)
val clampedStrength = Mth.clamp(strength, 0.0, 10.0) val clampedStrength = Mth.clamp(strength, 0.0, 10.0)
val cost = ManaConstants.DUST_UNIT * (3 * clampedStrength + if (fire) 0.125 else 1.0) val cost = ManaConstants.DUST_UNIT * (3 * clampedStrength + if (fire) 1.0 else 0.125)
return Triple( return Triple(
Spell(pos, clampedStrength, this.fire), Spell(pos, clampedStrength, this.fire),
cost.toInt(), cost.toInt(),

View file

@ -1,6 +1,7 @@
package at.petrak.hexcasting.common.items; package at.petrak.hexcasting.common.items;
import at.petrak.hexcasting.annotations.SoftImplement; import at.petrak.hexcasting.annotations.SoftImplement;
import at.petrak.hexcasting.api.misc.DiscoveryHandlers;
import at.petrak.hexcasting.common.lib.HexItems; import at.petrak.hexcasting.common.lib.HexItems;
import at.petrak.hexcasting.common.network.MsgUpdateComparatorVisualsAck; import at.petrak.hexcasting.common.network.MsgUpdateComparatorVisualsAck;
import at.petrak.hexcasting.xplat.IXplatAbstractions; import at.petrak.hexcasting.xplat.IXplatAbstractions;
@ -14,7 +15,6 @@ import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundEvents;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ArmorItem; import net.minecraft.world.item.ArmorItem;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
@ -29,32 +29,15 @@ import net.minecraft.world.phys.HitResult;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.WeakHashMap; import java.util.WeakHashMap;
import java.util.function.Predicate;
public class ItemLens extends Item implements Wearable { public class ItemLens extends Item implements Wearable {
private static final List<Predicate<Player>> HAS_HUD_PREDICATE = new ArrayList<>();
static { static {
addLensHUDPredicate(player -> player.getItemBySlot(EquipmentSlot.MAINHAND).is(HexItems.SCRYING_LENS)); DiscoveryHandlers.addLensPredicate(player -> player.getItemBySlot(EquipmentSlot.MAINHAND).is(HexItems.SCRYING_LENS));
addLensHUDPredicate(player -> player.getItemBySlot(EquipmentSlot.OFFHAND).is(HexItems.SCRYING_LENS)); DiscoveryHandlers.addLensPredicate(player -> player.getItemBySlot(EquipmentSlot.OFFHAND).is(HexItems.SCRYING_LENS));
addLensHUDPredicate(player -> player.getItemBySlot(EquipmentSlot.HEAD).is(HexItems.SCRYING_LENS)); DiscoveryHandlers.addLensPredicate(player -> player.getItemBySlot(EquipmentSlot.HEAD).is(HexItems.SCRYING_LENS));
}
public static boolean hasLensHUD(Player player) {
for (Predicate<Player> predicate : HAS_HUD_PREDICATE) {
if (predicate.test(player)) {
return true;
}
}
return false;
}
public static void addLensHUDPredicate(Predicate<Player> predicate) {
HAS_HUD_PREDICATE.add(predicate);
} }
public ItemLens(Properties pProperties) { public ItemLens(Properties pProperties) {
@ -82,7 +65,7 @@ public class ItemLens extends Item implements Wearable {
} }
public static void tickLens(Entity pEntity) { public static void tickLens(Entity pEntity) {
if (!pEntity.getLevel().isClientSide() && pEntity instanceof ServerPlayer player && hasLensHUD(player)) { if (!pEntity.getLevel().isClientSide() && pEntity instanceof ServerPlayer player && DiscoveryHandlers.hasLens(player)) {
sendComparatorDataToClient(player); sendComparatorDataToClient(player);
} }
} }

View file

@ -0,0 +1,57 @@
package at.petrak.hexcasting.common.items.magic;
import at.petrak.hexcasting.api.addldata.ManaHolder;
import at.petrak.hexcasting.api.utils.NBTHelper;
import net.minecraft.world.item.ItemStack;
import java.util.Arrays;
public record DebugUnlockerHolder(ItemStack creativeUnlocker) implements ManaHolder {
@Override
public int getMana() {
return Integer.MAX_VALUE;
}
@Override
public int getMaxMana() {
return Integer.MAX_VALUE - 1;
}
@Override
public void setMana(int mana) {
// NO-OP
}
@Override
public boolean canRecharge() {
return false;
}
@Override
public boolean canProvide() {
return true;
}
@Override
public int getConsumptionPriority() {
return 1000;
}
@Override
public boolean canConstructBattery() {
return false;
}
@Override
public int withdrawMana(int cost, boolean simulate) {
int[] arr = NBTHelper.getIntArray(creativeUnlocker, ItemCreativeUnlocker.TAG_EXTRACTIONS);
if (arr == null) {
arr = new int[0];
}
int[] newArr = Arrays.copyOf(arr, arr.length + 1);
newArr[newArr.length - 1] = cost;
NBTHelper.putIntArray(creativeUnlocker, ItemCreativeUnlocker.TAG_EXTRACTIONS, newArr);
return cost < 0 ? 1 : cost;
}
}

View file

@ -1,6 +1,7 @@
package at.petrak.hexcasting.common.items.magic; package at.petrak.hexcasting.common.items.magic;
import at.petrak.hexcasting.api.item.ManaHolderItem; import at.petrak.hexcasting.api.item.ManaHolderItem;
import at.petrak.hexcasting.api.misc.DiscoveryHandlers;
import at.petrak.hexcasting.api.misc.ManaConstants; import at.petrak.hexcasting.api.misc.ManaConstants;
import at.petrak.hexcasting.api.utils.NBTHelper; import at.petrak.hexcasting.api.utils.NBTHelper;
import at.petrak.hexcasting.common.lib.HexItems; import at.petrak.hexcasting.common.lib.HexItems;
@ -29,6 +30,33 @@ import static at.petrak.hexcasting.api.HexAPI.modLoc;
public class ItemCreativeUnlocker extends Item implements ManaHolderItem { public class ItemCreativeUnlocker extends Item implements ManaHolderItem {
static {
DiscoveryHandlers.addManaHolderDiscoverer(harness -> {
var player = harness.getCtx().getCaster();
if (!player.isCreative())
return List.of();
for (ItemStack item : player.inventoryMenu.getItems()) {
if (isDebug(item)) {
return List.of(new DebugUnlockerHolder(item));
}
}
// Technically possible with commands!
for (ItemStack item : player.getArmorSlots()) {
if (isDebug(item)) {
return List.of(new DebugUnlockerHolder(item));
}
}
if (isDebug(player.getOffhandItem())) {
return List.of(new DebugUnlockerHolder(player.getOffhandItem()));
}
return List.of();
});
}
public static boolean isDebug(ItemStack stack) { public static boolean isDebug(ItemStack stack) {
return stack.is(HexItems.CREATIVE_UNLOCKER) return stack.is(HexItems.CREATIVE_UNLOCKER)
&& stack.hasCustomHoverName() && stack.hasCustomHoverName()
@ -47,7 +75,7 @@ public class ItemCreativeUnlocker extends Item implements ManaHolderItem {
return emphasized; return emphasized;
} }
private static final String TAG_EXTRACTIONS = "extractions"; public static final String TAG_EXTRACTIONS = "extractions";
public ItemCreativeUnlocker(Properties properties) { public ItemCreativeUnlocker(Properties properties) {
super(properties); super(properties);
@ -80,6 +108,7 @@ public class ItemCreativeUnlocker extends Item implements ManaHolderItem {
@Override @Override
public int withdrawMana(ItemStack stack, int cost, boolean simulate) { public int withdrawMana(ItemStack stack, int cost, boolean simulate) {
// In case it's withdrawn through other means
if (!simulate && isDebug(stack)) { if (!simulate && isDebug(stack)) {
int[] arr = NBTHelper.getIntArray(stack, TAG_EXTRACTIONS); int[] arr = NBTHelper.getIntArray(stack, TAG_EXTRACTIONS);
if (arr == null) { if (arr == null) {

View file

@ -1,10 +1,13 @@
@file:JvmName("AccessorWrappers") @file:JvmName("AccessorWrappers")
package at.petrak.hexcasting.ktxt package at.petrak.hexcasting.ktxt
import at.petrak.hexcasting.mixin.accessor.AccessorEntity
import at.petrak.hexcasting.mixin.accessor.AccessorLivingEntity import at.petrak.hexcasting.mixin.accessor.AccessorLivingEntity
import at.petrak.hexcasting.mixin.accessor.AccessorUseOnContext import at.petrak.hexcasting.mixin.accessor.AccessorUseOnContext
import at.petrak.hexcasting.mixin.accessor.AccessorVillager import at.petrak.hexcasting.mixin.accessor.AccessorVillager
import net.minecraft.sounds.SoundEvent
import net.minecraft.world.InteractionHand import net.minecraft.world.InteractionHand
import net.minecraft.world.damagesource.DamageSource
import net.minecraft.world.entity.Entity import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.LivingEntity import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.npc.Villager import net.minecraft.world.entity.npc.Villager
@ -18,6 +21,18 @@ var LivingEntity.lastHurt: Float
get() = (this as AccessorLivingEntity).`hex$getLastHurt`() get() = (this as AccessorLivingEntity).`hex$getLastHurt`()
set(value) = (this as AccessorLivingEntity).`hex$setLastHurt`(value) set(value) = (this as AccessorLivingEntity).`hex$setLastHurt`(value)
fun LivingEntity.playHurtSound(source: DamageSource) = (this as AccessorLivingEntity).`hex$playHurtSound`(source)
fun LivingEntity.checkTotemDeathProtection(source: DamageSource) = (this as AccessorLivingEntity).`hex$checkTotemDeathProtection`(source)
val LivingEntity.deathSoundAccessor: SoundEvent? get() = (this as AccessorLivingEntity).`hex$getDeathSound`()
val LivingEntity.soundVolumeAccessor get() = (this as AccessorLivingEntity).`hex$getSoundVolume`()
fun LivingEntity.setHurtWithStamp(source: DamageSource, stamp: Long) = (this as AccessorLivingEntity).apply {
`hex$setLastDamageSource`(source)
`hex$setLastDamageStamp`(stamp)
}
fun Entity.markHurt() = (this as AccessorEntity).`hex$markHurt`()
fun Villager.tellWitnessesThatIWasMurdered(murderer: Entity) = (this as AccessorVillager).`hex$tellWitnessesThatIWasMurdered`(murderer) fun Villager.tellWitnessesThatIWasMurdered(murderer: Entity) = (this as AccessorVillager).`hex$tellWitnessesThatIWasMurdered`(murderer)
@Suppress("FunctionName") @Suppress("FunctionName")

View file

@ -0,0 +1,11 @@
package at.petrak.hexcasting.mixin.accessor;
import net.minecraft.world.entity.Entity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(Entity.class)
public interface AccessorEntity {
@Invoker("markHurt")
void hex$markHurt();
}

View file

@ -1,8 +1,11 @@
package at.petrak.hexcasting.mixin.accessor; package at.petrak.hexcasting.mixin.accessor;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.LivingEntity;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor; import org.spongepowered.asm.mixin.gen.Accessor;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(LivingEntity.class) @Mixin(LivingEntity.class)
public interface AccessorLivingEntity { public interface AccessorLivingEntity {
@ -11,4 +14,22 @@ public interface AccessorLivingEntity {
@Accessor("lastHurt") @Accessor("lastHurt")
void hex$setLastHurt(float lastHurt); void hex$setLastHurt(float lastHurt);
@Invoker("playHurtSound")
void hex$playHurtSound(DamageSource source);
@Invoker("checkTotemDeathProtection")
boolean hex$checkTotemDeathProtection(DamageSource source);
@Invoker("getDeathSound")
SoundEvent hex$getDeathSound();
@Invoker("getSoundVolume")
float hex$getSoundVolume();
@Accessor("lastDamageSource")
void hex$setLastDamageSource(DamageSource source);
@Accessor("lastDamageStamp")
void hex$setLastDamageStamp(long stamp);
} }

View file

@ -11,6 +11,7 @@
"MixinReloadableServerResources", "MixinReloadableServerResources",
"MixinVillager", "MixinVillager",
"MixinWitch", "MixinWitch",
"accessor.AccessorEntity",
"accessor.AccessorLivingEntity", "accessor.AccessorLivingEntity",
"accessor.AccessorLootTable", "accessor.AccessorLootTable",
"accessor.AccessorPoiType", "accessor.AccessorPoiType",

View file

@ -1,18 +1,25 @@
package at.petrak.hexcasting.fabric.interop.trinkets; package at.petrak.hexcasting.fabric.interop.trinkets;
import at.petrak.hexcasting.common.items.ItemLens; import at.petrak.hexcasting.api.misc.DiscoveryHandlers;
import at.petrak.hexcasting.api.utils.ManaHelper;
import at.petrak.hexcasting.common.items.magic.DebugUnlockerHolder;
import at.petrak.hexcasting.common.items.magic.ItemCreativeUnlocker;
import at.petrak.hexcasting.common.lib.HexItems; import at.petrak.hexcasting.common.lib.HexItems;
import at.petrak.hexcasting.xplat.IXplatAbstractions;
import dev.emi.trinkets.api.TrinketComponent; import dev.emi.trinkets.api.TrinketComponent;
import dev.emi.trinkets.api.TrinketsApi; import dev.emi.trinkets.api.TrinketsApi;
import dev.emi.trinkets.api.client.TrinketRendererRegistry; import dev.emi.trinkets.api.client.TrinketRendererRegistry;
import net.fabricmc.api.EnvType; import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment; import net.fabricmc.api.Environment;
import net.minecraft.util.Tuple;
import java.util.List;
import java.util.Objects;
import java.util.Optional; import java.util.Optional;
public class TrinketsApiInterop { public class TrinketsApiInterop {
public static void init() { public static void init() {
ItemLens.addLensHUDPredicate(player -> { DiscoveryHandlers.addLensPredicate(player -> {
Optional<TrinketComponent> optional = TrinketsApi.getTrinketComponent(player); Optional<TrinketComponent> optional = TrinketsApi.getTrinketComponent(player);
if (optional.isPresent()) { if (optional.isPresent()) {
TrinketComponent component = optional.get(); TrinketComponent component = optional.get();
@ -20,6 +27,31 @@ public class TrinketsApiInterop {
} }
return false; return false;
}); });
DiscoveryHandlers.addManaHolderDiscoverer(harness -> {
Optional<TrinketComponent> optional = TrinketsApi.getTrinketComponent(harness.getCtx().getCaster());
if (optional.isPresent()) {
TrinketComponent component = optional.get();
return component.getEquipped(ManaHelper::isManaItem).stream()
.map(Tuple::getB)
.map(IXplatAbstractions.INSTANCE::findManaHolder)
.filter(Objects::nonNull)
.toList();
}
return List.of();
});
DiscoveryHandlers.addManaHolderDiscoverer(harness -> {
Optional<TrinketComponent> optional = TrinketsApi.getTrinketComponent(harness.getCtx().getCaster());
if (optional.isPresent()) {
TrinketComponent component = optional.get();
var equipped = component.getEquipped(ItemCreativeUnlocker::isDebug);
if (!equipped.isEmpty()) {
return List.of(new DebugUnlockerHolder(equipped.get(0).getB()));
}
}
return List.of();
});
} }
@Environment(EnvType.CLIENT) @Environment(EnvType.CLIENT)

View file

@ -1,8 +1,14 @@
package at.petrak.hexcasting.forge.interop.curios; package at.petrak.hexcasting.forge.interop.curios;
import at.petrak.hexcasting.common.items.ItemLens; import at.petrak.hexcasting.api.addldata.ManaHolder;
import at.petrak.hexcasting.api.misc.DiscoveryHandlers;
import at.petrak.hexcasting.api.utils.ManaHelper;
import at.petrak.hexcasting.common.items.magic.DebugUnlockerHolder;
import at.petrak.hexcasting.common.items.magic.ItemCreativeUnlocker;
import at.petrak.hexcasting.common.lib.HexItems; import at.petrak.hexcasting.common.lib.HexItems;
import at.petrak.hexcasting.interop.HexInterop; import at.petrak.hexcasting.interop.HexInterop;
import at.petrak.hexcasting.xplat.IXplatAbstractions;
import com.google.common.collect.Lists;
import net.minecraftforge.fml.InterModComms; import net.minecraftforge.fml.InterModComms;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import net.minecraftforge.fml.event.lifecycle.InterModEnqueueEvent; import net.minecraftforge.fml.event.lifecycle.InterModEnqueueEvent;
@ -11,19 +17,67 @@ import top.theillusivec4.curios.api.SlotTypeMessage;
import top.theillusivec4.curios.api.SlotTypePreset; import top.theillusivec4.curios.api.SlotTypePreset;
import top.theillusivec4.curios.api.type.inventory.ICurioStacksHandler; import top.theillusivec4.curios.api.type.inventory.ICurioStacksHandler;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
public class CuriosApiInterop { public class CuriosApiInterop {
public static void init() { public static void init() {
ItemLens.addLensHUDPredicate(player -> { DiscoveryHandlers.addLensPredicate(player -> {
AtomicBoolean hasLens = new AtomicBoolean(false); AtomicBoolean hasLens = new AtomicBoolean(false);
player.getCapability(CuriosCapability.INVENTORY).ifPresent(handler -> { player.getCapability(CuriosCapability.INVENTORY).ifPresent(handler -> {
ICurioStacksHandler stacksHandler = handler.getCurios().get("head"); ICurioStacksHandler stacksHandler = handler.getCurios().get("head");
if(stacksHandler != null) hasLens.set(stacksHandler.getStacks().getStackInSlot(0).is(HexItems.SCRYING_LENS)); if(stacksHandler != null) {
var stacks = stacksHandler.getStacks();
for (int i = 0; i < stacks.getSlots(); i++) {
if (stacks.getStackInSlot(i).is(HexItems.SCRYING_LENS)) {
hasLens.set(true);
break;
}
}
}
}); });
return hasLens.get(); return hasLens.get();
}); });
DiscoveryHandlers.addManaHolderDiscoverer(harness -> {
List<ManaHolder> holders = Lists.newArrayList();
harness.getCtx().getCaster().getCapability(CuriosCapability.INVENTORY).ifPresent(handler -> {
for (var stacksHandler : handler.getCurios().values()) {
var stacks = stacksHandler.getStacks();
for (int i = 0; i < stacks.getSlots(); i++) {
var stack = stacks.getStackInSlot(i);
if (ManaHelper.isManaItem(stack)) {
var holder = IXplatAbstractions.INSTANCE.findManaHolder(stack);
if (holder != null) {
holders.add(holder);
}
}
}
}
});
return holders;
});
DiscoveryHandlers.addManaHolderDiscoverer(harness -> {
List<ManaHolder> holders = Lists.newArrayList();
harness.getCtx().getCaster().getCapability(CuriosCapability.INVENTORY).ifPresent(handler -> {
for (var stacksHandler : handler.getCurios().values()) {
var stacks = stacksHandler.getStacks();
for (int i = 0; i < stacks.getSlots(); i++) {
var stack = stacks.getStackInSlot(i);
if (ItemCreativeUnlocker.isDebug(stack)) {
holders.add(new DebugUnlockerHolder(stack));
return;
}
}
}
});
return holders;
});
} }
public static void onInterModEnqueue(final InterModEnqueueEvent event) { public static void onInterModEnqueue(final InterModEnqueueEvent event) {