This commit is contained in:
gamma-delta 2022-04-20 09:22:16 -05:00
commit 6632c5597b
24 changed files with 163 additions and 18 deletions

View file

@ -219,6 +219,7 @@ public abstract class BlockEntityAbstractImpetus extends PaucalBlockEntity imple
}
if (this.foundAll) {
this.clearEnergized();
this.castSpell();
this.stopCasting();
return;
@ -424,7 +425,7 @@ public abstract class BlockEntityAbstractImpetus extends PaucalBlockEntity imple
level.playSound(null, vpos.x, vpos.y, vpos.z, sound, SoundSource.BLOCKS, 1f, pitch);
}
protected void stopCasting() {
protected void clearEnergized() {
if (this.trackedBlocks != null) {
for (var tracked : this.trackedBlocks) {
var bs = this.level.getBlockState(tracked);
@ -433,6 +434,10 @@ public abstract class BlockEntityAbstractImpetus extends PaucalBlockEntity imple
}
}
}
}
protected void stopCasting() {
clearEnergized();
this.activator = null;
this.nextBlock = null;

View file

@ -44,6 +44,7 @@ public class BlockStoredPlayerImpetus extends BlockAbstractImpetus {
if (entity instanceof Player) {
// phew, we got something
tile.setPlayer(entity.getUUID());
tile.setChanged();
pLevel.playSound(pPlayer, pPos, HexSounds.IMPETUS_STOREDPLAYER_DING.get(), SoundSource.BLOCKS,
1f, 1f);

View file

@ -26,7 +26,7 @@ object OpEval : Operator {
val pattern = if (pat.payload is HexPattern) {
pat.payload
} else {
throw MishapInvalidIota(pat, 0, TranslatableComponent("hexcasting.mishap.invalid_value.list.pattern"))
throw MishapInvalidIota(SpellDatum.make(instrs), 0, TranslatableComponent("hexcasting.mishap.invalid_value.list.pattern"))
}
val res = harness.getUpdate(pattern, ctx.world)
sideEffects.addAll(res.sideEffects)

View file

@ -43,7 +43,7 @@ object OpForEach : Operator {
val res = harness.getUpdate(pattern, ctx.world)
sideEffects.addAll(res.sideEffects)
if (res.sideEffects.any { it is OperatorSideEffect.DoMishap }) {
break
return OperationResult(harness.stack, sideEffects)
}
harness.applyFunctionalData(res.newData)
}

View file

@ -34,6 +34,9 @@ object OpBreakBlock : SpellOperator {
override fun cast(ctx: CastingContext) {
val pos = BlockPos(v)
if (!ctx.world.mayInteract(ctx.caster, pos))
return
val blockstate = ctx.world.getBlockState(pos)
val tier =
HexConfig.Server.getOpBreakHarvestLevelBecauseForgeThoughtItWasAGoodIdeaToImplementHarvestTiersUsingAnHonestToGodTopoSort()

View file

@ -33,7 +33,7 @@ object OpColorize : SpellOperator {
private object Spell : RenderedSpell {
override fun cast(ctx: CastingContext) {
val (handStack) = ctx.getHeldItemToOperateOn { FrozenColorizer.isColorizer(it) }
val (handStack) = ctx.getHeldItemToOperateOn { FrozenColorizer.isColorizer(it) }.copy()
if (FrozenColorizer.isColorizer(handStack)) {
if (ctx.withdrawItem(handStack.item, 1, true)) {
HexPlayerDataHelper.setColorizer(ctx.caster,

View file

@ -34,6 +34,10 @@ class OpConjure(val light: Boolean) : SpellOperator {
private data class Spell(val target: Vec3, val light: Boolean) : RenderedSpell {
override fun cast(ctx: CastingContext) {
val pos = BlockPos(target)
if (!ctx.world.mayInteract(ctx.caster, pos))
return
val placeContext = DirectionalPlaceContext(ctx.world, pos, Direction.DOWN, ItemStack.EMPTY, Direction.UP)
val worldState = ctx.world.getBlockState(pos)

View file

@ -30,11 +30,15 @@ object OpCreateWater : SpellOperator {
private data class Spell(val target: Vec3) : RenderedSpell {
override fun cast(ctx: CastingContext) {
val pos = BlockPos(target)
if (!ctx.world.mayInteract(ctx.caster, pos))
return
// Just steal bucket code lmao
val charlie = Items.WATER_BUCKET
if (charlie is BucketItem) {
// make the player null so we don't give them a usage statistic for example
charlie.emptyContents(null, ctx.world, BlockPos(target), null)
charlie.emptyContents(null, ctx.world, pos, null)
} else {
HexMod.getLogger().warn("Items.WATER_BUCKET wasn't a BucketItem?")
}

View file

@ -51,7 +51,7 @@ object OpDestroyWater : SpellOperator {
val here = todo.removeFirst()
val distFromFocus =
ctx.caster.position().distanceToSqr(Vec3(here.x.toDouble(), here.y.toDouble(), here.z.toDouble()))
if (distFromFocus < Operator.MAX_DISTANCE * Operator.MAX_DISTANCE && seen.add(here)) {
if (distFromFocus < Operator.MAX_DISTANCE * Operator.MAX_DISTANCE && seen.add(here) && ctx.world.mayInteract(ctx.caster, here)) {
// never seen this pos in my life
val fluid = ctx.world.getFluidState(here)
if (fluid != Fluids.EMPTY.defaultFluidState()) {

View file

@ -36,6 +36,9 @@ object OpEdifySapling : SpellOperator {
private data class Spell(val pos: BlockPos) : RenderedSpell {
override fun cast(ctx: CastingContext) {
if (!ctx.world.mayInteract(ctx.caster, pos))
return
val bs = ctx.world.getBlockState(pos)
for (i in 0 until 8) {
val success = AkashicTreeGrower.INSTANCE.growTree(

View file

@ -6,6 +6,7 @@ import at.petrak.hexcasting.api.spell.RenderedSpell
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.api.spell.SpellOperator
import at.petrak.hexcasting.api.spell.casting.CastingContext
import net.minecraft.core.BlockPos
import net.minecraft.util.Mth
import net.minecraft.world.level.Explosion
import net.minecraft.world.phys.Vec3
@ -30,6 +31,9 @@ class OpExplode(val fire: Boolean) : SpellOperator {
private data class Spell(val pos: Vec3, val strength: Double, val fire: Boolean) : RenderedSpell {
override fun cast(ctx: CastingContext) {
if (!ctx.world.mayInteract(ctx.caster, BlockPos(pos)))
return
ctx.world.explode(
ctx.caster,
pos.x,

View file

@ -55,7 +55,7 @@ object OpExtinguish : SpellOperator {
here.z.toDouble()
)
) // max distance to prevent runaway shenanigans
if (distFromFocus < Operator.MAX_DISTANCE * Operator.MAX_DISTANCE && seen.add(here) && distFromTarget < 10) {
if (distFromFocus < Operator.MAX_DISTANCE * Operator.MAX_DISTANCE && seen.add(here) && distFromTarget < 10 && ctx.world.mayInteract(ctx.caster, here)) {
// never seen this pos in my life
val blockstate = ctx.world.getBlockState(here)
val success =

View file

@ -35,6 +35,10 @@ object OpIgnite : SpellOperator {
private data class Spell(val target: Vec3) : RenderedSpell {
override fun cast(ctx: CastingContext) {
val pos = BlockPos(target)
if (!ctx.world.mayInteract(ctx.caster, pos))
return
// steal petra code that steals bucket code
val maxwell = Items.FIRE_CHARGE
if (maxwell is FireChargeItem) {
@ -45,7 +49,7 @@ object OpIgnite : SpellOperator {
null,
InteractionHand.MAIN_HAND,
ItemStack(maxwell.asItem()),
BlockHitResult(target, Direction.UP, BlockPos(target), false)
BlockHitResult(target, Direction.UP, pos, false)
)
)
} else {

View file

@ -56,7 +56,7 @@ class OpMakePackagedSpell<T : ItemPackagedSpell>(val itemType: T, val cost: Int)
val (handStack) = ctx.getHeldItemToOperateOn { it.`is`(itemType) }
val spellHolder = handStack.getCapability(HexCapabilities.SPELL).resolve()
if (spellHolder.isPresent
&& spellHolder.get().patterns != null
&& spellHolder.get().patterns == null
&& itemEntity.isAlive
) {
val entityStack = itemEntity.item.copy()

View file

@ -39,11 +39,15 @@ object OpPlaceBlock : SpellOperator {
private data class Spell(val vec: Vec3) : RenderedSpell {
override fun cast(ctx: CastingContext) {
val pos = BlockPos(vec)
if (!ctx.world.mayInteract(ctx.caster, pos))
return
val bstate = ctx.world.getBlockState(pos)
if (bstate.isAir || bstate.material.isReplaceable) {
val placeeSlot = ctx.getOperativeSlot { it.item is BlockItem }
if (placeeSlot != null) {
val placeeStack = ctx.caster.inventory.getItem(placeeSlot)
val placeeStack = ctx.caster.inventory.getItem(placeeSlot).copy()
val placee = placeeStack.item as BlockItem
if (ctx.withdrawItem(placee, 1, false)) {
// https://github.com/VazkiiMods/Psi/blob/master/src/main/java/vazkii/psi/common/spell/trick/block/PieceTrickPlaceBlock.java#L143

View file

@ -36,6 +36,10 @@ object OpTheOnlyReasonAnyoneDownloadedPsi : SpellOperator {
override fun cast(ctx: CastingContext) {
// https://github.com/VazkiiMods/Psi/blob/master/src/main/java/vazkii/psi/common/spell/trick/PieceTrickOvergrow.java
val pos = BlockPos(target)
if (!ctx.world.mayInteract(ctx.caster, pos))
return
val hit = BlockHitResult(Vec3.ZERO, Direction.UP, pos, false)
val save: ItemStack = ctx.caster.getItemInHand(InteractionHand.MAIN_HAND)
ctx.caster.setItemInHand(InteractionHand.MAIN_HAND, ItemStack(Items.BONE_MEAL))

View file

@ -31,11 +31,16 @@ object OpCreateLava : SpellOperator {
private data class Spell(val target: Vec3) : RenderedSpell {
override fun cast(ctx: CastingContext) {
val pos = BlockPos(target)
if (!ctx.world.mayInteract(ctx.caster, pos))
return
// Just steal bucket code lmao
val charlie = Items.LAVA_BUCKET
if (charlie is BucketItem) {
// make the player null so we don't give them a usage statistic for example
charlie.emptyContents(null, ctx.world, BlockPos(target), null)
charlie.emptyContents(null, ctx.world, pos, null)
} else {
HexMod.getLogger().warn("Items.LAVA_BUCKET wasn't a BucketItem?")
}

View file

@ -6,6 +6,7 @@ import at.petrak.hexcasting.api.spell.RenderedSpell
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.api.spell.SpellOperator
import at.petrak.hexcasting.api.spell.casting.CastingContext
import net.minecraft.core.BlockPos
import net.minecraft.world.entity.EntityType
import net.minecraft.world.entity.LightningBolt
import net.minecraft.world.phys.Vec3
@ -29,6 +30,9 @@ object OpLightning : SpellOperator {
private data class Spell(val target: Vec3) : RenderedSpell {
override fun cast(ctx: CastingContext) {
if (!ctx.world.mayInteract(ctx.caster, BlockPos(target)))
return
val lightning = LightningBolt(EntityType.LIGHTNING_BOLT, ctx.world)
lightning.setPosRaw(target.x, target.y, target.z)
ctx.world.addWithUUID(lightning) // why the hell is it called this it doesnt even involve a uuid

View file

@ -11,8 +11,11 @@ import net.minecraft.nbt.Tag;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import org.jetbrains.annotations.Nullable;
@ -39,6 +42,21 @@ public class ItemSlate extends BlockItem implements DataHolderItem {
return false;
}
@Override
public boolean onEntityItemUpdate(ItemStack stack, ItemEntity entity) {
var tag = stack.getTagElement("BlockEntityTag");
if (tag != null && tag.isEmpty())
stack.removeTagKey("BlockEntityTag");
return super.onEntityItemUpdate(stack, entity);
}
@Override
public void inventoryTick(ItemStack pStack, Level pLevel, Entity pEntity, int pSlotId, boolean pIsSelected) {
var tag = pStack.getTagElement("BlockEntityTag");
if (tag != null && tag.isEmpty())
pStack.removeTagKey("BlockEntityTag");
}
@Override
public @Nullable CompoundTag readDatumTag(ItemStack stack) {
var stackTag = stack.getTag();
@ -61,14 +79,20 @@ public class ItemSlate extends BlockItem implements DataHolderItem {
@Override
public boolean canWrite(ItemStack stack, SpellDatum<?> datum) {
return !(datum == null || datum.getType() != DatumType.PATTERN);
return datum == null || datum.getType() == DatumType.PATTERN;
}
@Override
public void writeDatum(ItemStack stack, SpellDatum<?> datum) {
if (this.canWrite(stack, datum) && datum.getPayload() instanceof HexPattern pat) {
var beTag = stack.getOrCreateTagElement("BlockEntityTag");
beTag.put(BlockEntitySlate.TAG_PATTERN, pat.serializeToNBT());
}
if (this.canWrite(stack, datum))
if (datum == null) {
var beTag = stack.getOrCreateTagElement("BlockEntityTag");
beTag.remove(BlockEntitySlate.TAG_PATTERN);
if (beTag.isEmpty())
stack.removeTagKey("BlockEntityTag");
} else if (datum.getPayload() instanceof HexPattern pat) {
var beTag = stack.getOrCreateTagElement("BlockEntityTag");
beTag.put(BlockEntitySlate.TAG_PATTERN, pat.serializeToNBT());
}
}
}

View file

@ -1,14 +1,20 @@
package at.petrak.hexcasting.common.misc;
import at.petrak.hexcasting.common.network.HexMessages;
import at.petrak.hexcasting.common.network.MsgBrainsweepAck;
import at.petrak.hexcasting.mixin.AccessorLivingEntity;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.Brain;
import net.minecraft.world.entity.npc.Villager;
import net.minecraft.world.entity.npc.VillagerDataHolder;
import net.minecraftforge.event.entity.living.LivingConversionEvent;
import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.network.PacketDistributor;
public class Brainsweeping {
@ -29,6 +35,19 @@ public class Brainsweeping {
}
((AccessorLivingEntity) entity).hex$SetBrain(brain.copyWithoutBehaviors());
}
if (entity.level instanceof ServerLevel) {
HexMessages.getNetwork().send(PacketDistributor.TRACKING_ENTITY.with(() -> entity), MsgBrainsweepAck.of(entity));
}
}
}
@SubscribeEvent
public static void startTracking(PlayerEvent.StartTracking evt) {
Entity target = evt.getTarget();
if (evt.getPlayer() instanceof ServerPlayer serverPlayer &&
target instanceof VillagerDataHolder && target instanceof LivingEntity living && isBrainswept(living)) {
HexMessages.getNetwork().send(PacketDistributor.PLAYER.with(() -> serverPlayer), MsgBrainsweepAck.of(living));
}
}

View file

@ -40,6 +40,8 @@ public class HexMessages {
MsgOpenSpellGuiAck::deserialize, MsgOpenSpellGuiAck::handle);
NETWORK.registerMessage(messageIdx++, MsgBeepAck.class, MsgBeepAck::serialize,
MsgBeepAck::deserialize, MsgBeepAck::handle);
NETWORK.registerMessage(messageIdx++, MsgBrainsweepAck.class, MsgBrainsweepAck::serialize,
MsgBrainsweepAck::deserialize, MsgBrainsweepAck::handle);
HexApiMessages.setSyncChannel(NETWORK, MsgSentinelStatusUpdateAck::new, MsgColorizerUpdateAck::new, MsgCastParticleAck::new);
}

View file

@ -0,0 +1,55 @@
package at.petrak.hexcasting.common.network;
import at.petrak.hexcasting.common.misc.Brainsweeping;
import io.netty.buffer.ByteBuf;
import net.minecraft.client.Minecraft;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.network.NetworkEvent;
import java.util.function.Supplier;
/**
* Sent server->client to synchronize the status of a brainswept mob.
*/
public record MsgBrainsweepAck(int target) {
public static MsgBrainsweepAck deserialize(ByteBuf buffer) {
var buf = new FriendlyByteBuf(buffer);
var target = buf.readInt();
return new MsgBrainsweepAck(target);
}
public void serialize(ByteBuf buffer) {
var buf = new FriendlyByteBuf(buffer);
buf.writeInt(target);
}
public static MsgBrainsweepAck of(Entity target) {
return new MsgBrainsweepAck(target.getId());
}
public void handle(Supplier<NetworkEvent.Context> ctx) {
ctx.get().enqueueWork(() ->
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> {
IHateJava.handle(target);
})
);
ctx.get().setPacketHandled(true);
}
private static class IHateJava {
public static void handle(int target) {
var level = Minecraft.getInstance().level;
if (level != null) {
Entity entity = level.getEntity(target);
if (entity instanceof LivingEntity living) {
Brainsweeping.brainsweep(living);
}
}
}
}
}

View file

@ -690,7 +690,7 @@
"hexcasting.page.math.cos": "Take the cosine of an angle in radians, yielding the horizontal component of that angle drawn on a unit circle.",
"hexcasting.page.math.tan": "Take the tangent of an angle in radians, yielding the slope of that angle drawn on a circle.",
"hexcasting.page.math.arcsin": "Take the inverse sine of a value with absolute value 1 or less, yielding the angle whose sine is that value.",
"hexcasting.page.math.arccos": "Take the inverse cosine of a value with absolute value 1 or less, yielding the angle whose sine is that value.",
"hexcasting.page.math.arccos": "Take the inverse cosine of a value with absolute value 1 or less, yielding the angle whose cosine is that value.",
"hexcasting.page.math.arctan": "Take the inverse tangent of a value, yielding the angle whose tangent is that value.",
"hexcasting.page.math.random": "Creates a random number between 0 and 1.",

View file

@ -1,7 +1,7 @@
{
"name": "hexcasting.entry.101",
"category": "hexcasting:casting",
"icon": "hexcasting:edified_wand",
"icon": "hexcasting:wand_akashic",
"advancement": "hexcasting:root",
"priority": true,
"pages": [