Fluid creation hexes can insert partial, destroy fluid can drain tanks
Closes #216
This commit is contained in:
parent
6418e9b95e
commit
240f021194
8 changed files with 107 additions and 126 deletions
|
@ -38,6 +38,10 @@ import at.petrak.hexcasting.common.casting.operators.stack.*;
|
|||
import at.petrak.hexcasting.common.lib.HexItems;
|
||||
import it.unimi.dsi.fastutil.booleans.BooleanArrayList;
|
||||
import net.minecraft.world.effect.MobEffects;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.LayeredCauldronBlock;
|
||||
import net.minecraft.world.level.material.Fluids;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
import static at.petrak.hexcasting.api.HexAPI.modLoc;
|
||||
|
@ -201,10 +205,13 @@ public class RegisterPatterns {
|
|||
modLoc("colorize"),
|
||||
OpColorize.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("aqawqadaq", HexDir.SOUTH_EAST), modLoc("create_water"),
|
||||
OpCreateWater.INSTANCE);
|
||||
new OpCreateFluid(false, ManaConstants.DUST_UNIT,
|
||||
Items.WATER_BUCKET,
|
||||
Blocks.WATER_CAULDRON.defaultBlockState().setValue(LayeredCauldronBlock.LEVEL, LayeredCauldronBlock.MAX_FILL_LEVEL),
|
||||
Fluids.WATER));
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("dedwedade", HexDir.SOUTH_WEST),
|
||||
modLoc("destroy_water"),
|
||||
OpDestroyWater.INSTANCE);
|
||||
OpDestroyFluid.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("aaqawawa", HexDir.SOUTH_EAST), modLoc("ignite"),
|
||||
OpIgnite.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("ddedwdwd", HexDir.SOUTH_WEST), modLoc("extinguish"),
|
||||
|
@ -292,7 +299,10 @@ public class RegisterPatterns {
|
|||
PatternRegistry.mapPattern(HexPattern.fromAngles("eawwaeawawaa", HexDir.NORTH_WEST),
|
||||
modLoc("flight"), OpFlight.INSTANCE, true);
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("eaqawqadaqd", HexDir.EAST),
|
||||
modLoc("create_lava"), OpCreateLava.INSTANCE, true);
|
||||
modLoc("create_lava"), new OpCreateFluid(true, ManaConstants.CRYSTAL_UNIT,
|
||||
Items.LAVA_BUCKET,
|
||||
Blocks.LAVA_CAULDRON.defaultBlockState(),
|
||||
Fluids.LAVA), true);
|
||||
PatternRegistry.mapPattern(
|
||||
HexPattern.fromAngles("wwwqqqwwwqqeqqwwwqqwqqdqqqqqdqq", HexDir.EAST),
|
||||
modLoc("teleport"), OpTeleport.INSTANCE, true);
|
||||
|
|
|
@ -1,22 +1,19 @@
|
|||
package at.petrak.hexcasting.common.casting.operators.spells.great
|
||||
package at.petrak.hexcasting.common.casting.operators.spells
|
||||
|
||||
import at.petrak.hexcasting.api.HexAPI
|
||||
import at.petrak.hexcasting.api.misc.ManaConstants
|
||||
import at.petrak.hexcasting.api.spell.*
|
||||
import at.petrak.hexcasting.api.spell.casting.CastingContext
|
||||
import at.petrak.hexcasting.xplat.IXplatAbstractions
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.world.item.BucketItem
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.Items
|
||||
import net.minecraft.world.level.block.AbstractCauldronBlock
|
||||
import net.minecraft.world.level.block.Blocks
|
||||
import net.minecraft.world.level.material.Fluids
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.material.Fluid
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
object OpCreateLava : SpellOperator {
|
||||
class OpCreateFluid(override val isGreat: Boolean, val cost: Int, val bucket: Item, val cauldron: BlockState, val fluid: Fluid) : SpellOperator {
|
||||
override val argc = 1
|
||||
override val isGreat = true
|
||||
override fun execute(
|
||||
args: List<SpellDatum<*>>,
|
||||
ctx: CastingContext
|
||||
|
@ -25,20 +22,20 @@ object OpCreateLava : SpellOperator {
|
|||
ctx.assertVecInRange(target)
|
||||
|
||||
return Triple(
|
||||
Spell(target),
|
||||
ManaConstants.CRYSTAL_UNIT,
|
||||
listOf(ParticleSpray.burst(Vec3.atCenterOf(BlockPos(target)), 1.0)),
|
||||
Spell(target, bucket, cauldron, fluid),
|
||||
cost,
|
||||
listOf(ParticleSpray.burst(Vec3.atCenterOf(BlockPos(target)), 1.0))
|
||||
)
|
||||
}
|
||||
|
||||
private data class Spell(val target: Vec3) : RenderedSpell {
|
||||
private data class Spell(val target: Vec3, val bucket: Item, val cauldron: BlockState, val fluid: Fluid) : RenderedSpell {
|
||||
override fun cast(ctx: CastingContext) {
|
||||
val pos = BlockPos(target)
|
||||
|
||||
if (!ctx.canEditBlockAt(pos) || !IXplatAbstractions.INSTANCE.isPlacingAllowed(
|
||||
ctx.world,
|
||||
pos,
|
||||
ItemStack(Items.LAVA_BUCKET),
|
||||
ItemStack(bucket),
|
||||
ctx.caster
|
||||
)
|
||||
)
|
||||
|
@ -46,24 +43,16 @@ object OpCreateLava : SpellOperator {
|
|||
|
||||
val state = ctx.world.getBlockState(pos)
|
||||
|
||||
if (state.block is AbstractCauldronBlock)
|
||||
ctx.world.setBlock(pos, Blocks.LAVA_CAULDRON.defaultBlockState(), 3)
|
||||
if (state.block == Blocks.CAULDRON)
|
||||
ctx.world.setBlock(pos, cauldron, 3)
|
||||
else if (!IXplatAbstractions.INSTANCE.tryPlaceFluid(
|
||||
ctx.world,
|
||||
ctx.castingHand,
|
||||
pos,
|
||||
ItemStack(Items.LAVA_BUCKET),
|
||||
Fluids.LAVA
|
||||
)
|
||||
) {
|
||||
// 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, pos, null)
|
||||
} else {
|
||||
HexAPI.LOGGER.warn("Items.LAVA_BUCKET wasn't a BucketItem?")
|
||||
}
|
||||
fluid
|
||||
) && bucket is BucketItem) {
|
||||
// make the player null so we don't give them a usage statistic for example
|
||||
bucket.emptyContents(null, ctx.world, pos, null)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
package at.petrak.hexcasting.common.casting.operators.spells
|
||||
|
||||
import at.petrak.hexcasting.api.HexAPI
|
||||
import at.petrak.hexcasting.api.misc.ManaConstants
|
||||
import at.petrak.hexcasting.api.spell.*
|
||||
import at.petrak.hexcasting.api.spell.casting.CastingContext
|
||||
import at.petrak.hexcasting.xplat.IXplatAbstractions
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.world.item.BucketItem
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.Items
|
||||
import net.minecraft.world.level.block.AbstractCauldronBlock
|
||||
import net.minecraft.world.level.block.Blocks
|
||||
import net.minecraft.world.level.block.LayeredCauldronBlock
|
||||
import net.minecraft.world.level.material.Fluids
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
object OpCreateWater : SpellOperator {
|
||||
override val argc = 1
|
||||
override fun execute(
|
||||
args: List<SpellDatum<*>>,
|
||||
ctx: CastingContext
|
||||
): Triple<RenderedSpell, Int, List<ParticleSpray>> {
|
||||
val target = args.getChecked<Vec3>(0, argc)
|
||||
ctx.assertVecInRange(target)
|
||||
|
||||
return Triple(
|
||||
Spell(target),
|
||||
ManaConstants.DUST_UNIT,
|
||||
listOf(ParticleSpray.burst(Vec3.atCenterOf(BlockPos(target)), 1.0))
|
||||
)
|
||||
}
|
||||
|
||||
private data class Spell(val target: Vec3) : RenderedSpell {
|
||||
override fun cast(ctx: CastingContext) {
|
||||
val pos = BlockPos(target)
|
||||
|
||||
if (!ctx.canEditBlockAt(pos)
|
||||
|| !IXplatAbstractions.INSTANCE.isPlacingAllowed(
|
||||
ctx.world,
|
||||
pos,
|
||||
ItemStack(Items.WATER_BUCKET),
|
||||
ctx.caster
|
||||
)
|
||||
)
|
||||
return
|
||||
val state = ctx.world.getBlockState(pos)
|
||||
|
||||
if (state.block is AbstractCauldronBlock)
|
||||
ctx.world.setBlock(
|
||||
pos,
|
||||
Blocks.WATER_CAULDRON.defaultBlockState().setValue(LayeredCauldronBlock.LEVEL, 3),
|
||||
3
|
||||
)
|
||||
else if (!IXplatAbstractions.INSTANCE.tryPlaceFluid(
|
||||
ctx.world,
|
||||
ctx.castingHand,
|
||||
pos,
|
||||
ItemStack(Items.WATER_BUCKET),
|
||||
Fluids.WATER
|
||||
)
|
||||
) {
|
||||
// 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, pos, null)
|
||||
} else {
|
||||
HexAPI.LOGGER.warn("Items.WATER_BUCKET wasn't a BucketItem?")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,16 +9,13 @@ import net.minecraft.core.Direction
|
|||
import net.minecraft.core.particles.ParticleTypes
|
||||
import net.minecraft.sounds.SoundEvents
|
||||
import net.minecraft.sounds.SoundSource
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.level.block.Blocks
|
||||
import net.minecraft.world.level.block.BucketPickup
|
||||
import net.minecraft.world.level.block.LiquidBlock
|
||||
import net.minecraft.world.level.block.*
|
||||
import net.minecraft.world.level.block.entity.BlockEntity
|
||||
import net.minecraft.world.level.material.Fluids
|
||||
import net.minecraft.world.level.material.Material
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
object OpDestroyWater : SpellOperator {
|
||||
object OpDestroyFluid : SpellOperator {
|
||||
override val argc = 1
|
||||
override fun execute(
|
||||
args: List<SpellDatum<*>>,
|
||||
|
@ -39,10 +36,24 @@ object OpDestroyWater : SpellOperator {
|
|||
private data class Spell(val target: Vec3) : RenderedSpell {
|
||||
|
||||
override fun cast(ctx: CastingContext) {
|
||||
val basePos = BlockPos(target)
|
||||
|
||||
// Try draining from fluid handlers first, and if so, don't do the normal behavior
|
||||
if (ctx.canEditBlockAt(basePos)) {
|
||||
if (IXplatAbstractions.INSTANCE.drainAllFluid(ctx.world, basePos)) {
|
||||
return
|
||||
} else {
|
||||
val state = ctx.world.getBlockState(basePos)
|
||||
if (state.block is AbstractCauldronBlock && state.block != Blocks.CAULDRON) {
|
||||
ctx.world.setBlock(basePos, Blocks.CAULDRON.defaultBlockState(), 3)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SpongeBlock.java
|
||||
val todo = ArrayDeque<BlockPos>()
|
||||
val seen = HashSet<BlockPos>()
|
||||
val basePos = BlockPos(target)
|
||||
|
||||
// a little extra range on the initial cast to make it feel more intuitive
|
||||
for (xShift in -2..2) for (yShift in -2..2) for (zShift in -2..2) {
|
|
@ -120,8 +120,9 @@ public interface IXplatAbstractions {
|
|||
<T extends BlockEntity> BlockEntityType<T> createBlockEntityType(BiFunction<BlockPos, BlockState, T> func,
|
||||
Block... blocks);
|
||||
|
||||
boolean tryPlaceFluid(Level level, InteractionHand hand, BlockPos pos, ItemStack stack, Fluid fluid);
|
||||
boolean tryPlaceFluid(Level level, InteractionHand hand, BlockPos pos, Fluid fluid);
|
||||
|
||||
boolean drainAllFluid(Level level, BlockPos pos);
|
||||
|
||||
// misc
|
||||
|
||||
|
|
|
@ -310,7 +310,7 @@
|
|||
"hexcasting.spell.hexcasting:recharge": "Recharge Item",
|
||||
"hexcasting.spell.hexcasting:erase": "Erase Item",
|
||||
"hexcasting.spell.hexcasting:create_water": "Create Water",
|
||||
"hexcasting.spell.hexcasting:destroy_water": "Destroy Water",
|
||||
"hexcasting.spell.hexcasting:destroy_water": "Destroy Liquid",
|
||||
"hexcasting.spell.hexcasting:ignite": "Ignite Block",
|
||||
"hexcasting.spell.hexcasting:extinguish": "Extinguish Area",
|
||||
"hexcasting.spell.hexcasting:conjure_block": "Conjure Block",
|
||||
|
@ -920,8 +920,8 @@
|
|||
"hexcasting.entry.blockworks": "Blockworks",
|
||||
"hexcasting.page.blockworks.place_block": "Remove a location from the stack, then pick a block item and place it at the given location.$(br)Costs a negligible amount of _media.",
|
||||
"hexcasting.page.blockworks.break_block": "Remove a location from the stack, then break the block at the given location. This spell can break nearly anything a Diamond Pickaxe can break.$(br)Costs a bit more than one $(l:items/amethyst)$(item)Amethyst Dust/$.",
|
||||
"hexcasting.page.blockworks.create_water": "Summon a block of water (or insert a bucket's worth) into a block at the given position. Costs about one $(l:items/amethyst)$(item)Amethyst Dust/$.",
|
||||
"hexcasting.page.blockworks.destroy_water": "Destroy a great deal of liquid (not just water) around the given position. Costs about two $(l:items/amethyst)$(item)Charged Amethyst/$.",
|
||||
"hexcasting.page.blockworks.create_water": "Summon a block of water (or insert up to a bucket's worth) into a block at the given position. Costs about one $(l:items/amethyst)$(item)Amethyst Dust/$.",
|
||||
"hexcasting.page.blockworks.destroy_water": "Drains either a liquid container at, or a body of liquid around, the given position. Costs about two $(l:items/amethyst)$(item)Charged Amethyst/$.",
|
||||
"hexcasting.page.blockworks.conjure_block": "Conjure an ethereal, but solid, block that sparkles with my pigment at the given position. Costs about one $(l:items/amethyst)$(item)Amethyst Dust/$.",
|
||||
"hexcasting.page.blockworks.conjure_light": "Conjure a magical light that softly glows with my pigment at the given position. Costs about one $(l:items/amethyst)$(item)Amethyst Dust/$.",
|
||||
"hexcasting.page.blockworks.bonemeal": "Encourage a plant or sapling at the target position to grow, as if $(item)Bonemeal/$ was applied. Costs a bit more than one $(l:items/amethyst)$(item)Amethyst Dust/$.",
|
||||
|
@ -958,7 +958,7 @@
|
|||
|
||||
"hexcasting.page.colorize": "I must be holding a $(l:items/pigments)$(item)Pigment/$ in my other hand to cast this spell. When I do, it will consume the dye and permanently change my mind's coloration (at least, until I cast the spell again). Costs about one $(l:items/amethyst)$(item)Amethyst Dust/$.",
|
||||
|
||||
"hexcasting.page.create_lava.1": "Summon a block of lava or insert a bucket's worth into a block at the given position. Costs about one $(l:items/amethyst)$(item)Charged Amethyst/$.",
|
||||
"hexcasting.page.create_lava.1": "Summon a block of lava (or insert up to a bucket's worth) into a block at the given position. Costs about one $(l:items/amethyst)$(item)Charged Amethyst/$.",
|
||||
"hexcasting.page.create_lava.2": "It may be advisable to keep my knowledge of this spell secret. A certain faction of botanists get... touchy about it, or so I've heard.$(br2)Well, no one said tracing the deep secrets of the universe was going to be an easy time.",
|
||||
|
||||
"hexcasting.entry.weather_manip": "Weather Manipulation",
|
||||
|
|
|
@ -31,12 +31,11 @@ import net.fabricmc.fabric.api.item.v1.FabricItemSettings;
|
|||
import net.fabricmc.fabric.api.networking.v1.PlayerLookup;
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
|
||||
import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder;
|
||||
import net.fabricmc.fabric.api.transfer.v1.context.ContainerItemContext;
|
||||
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidConstants;
|
||||
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidStorage;
|
||||
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant;
|
||||
import net.fabricmc.fabric.api.transfer.v1.storage.Storage;
|
||||
import net.fabricmc.fabric.api.transfer.v1.storage.StorageUtil;
|
||||
import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.fabricmc.loader.api.ModContainer;
|
||||
import net.minecraft.advancements.critereon.ItemPredicate;
|
||||
|
@ -252,10 +251,41 @@ public class FabricXplatImpl implements IXplatAbstractions {
|
|||
|
||||
@Override
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
public boolean tryPlaceFluid(Level level, InteractionHand hand, BlockPos pos, ItemStack stack, Fluid fluid) {
|
||||
public boolean tryPlaceFluid(Level level, InteractionHand hand, BlockPos pos, Fluid fluid) {
|
||||
Storage<FluidVariant> target = FluidStorage.SIDED.find(level, pos, Direction.UP);
|
||||
Storage<FluidVariant> emptyFrom = FluidStorage.ITEM.find(stack, ContainerItemContext.withInitial(stack));
|
||||
return StorageUtil.move(emptyFrom, target, (f) -> true, FluidConstants.BUCKET, null) > 0;
|
||||
if (target == null)
|
||||
return false;
|
||||
try (Transaction transaction = Transaction.openOuter()) {
|
||||
long insertedAmount = target.insert(FluidVariant.of(fluid), FluidConstants.BUCKET, transaction);
|
||||
if (insertedAmount > 0) {
|
||||
transaction.commit();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
public boolean drainAllFluid(Level level, BlockPos pos) {
|
||||
Storage<FluidVariant> target = FluidStorage.SIDED.find(level, pos, Direction.UP);
|
||||
if (target == null)
|
||||
return false;
|
||||
try (Transaction transaction = Transaction.openOuter()) {
|
||||
boolean any = false;
|
||||
for (var view : target.iterable(transaction)) {
|
||||
long extracted = view.extract(view.getResource(), view.getAmount(), transaction);
|
||||
if (extracted > 0) {
|
||||
any = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (any) {
|
||||
transaction.commit();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -82,6 +82,8 @@ import java.util.List;
|
|||
import java.util.Optional;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import static net.minecraftforge.fluids.capability.IFluidHandler.FluidAction.EXECUTE;
|
||||
|
||||
public class ForgeXplatImpl implements IXplatAbstractions {
|
||||
@Override
|
||||
public Platform platform() {
|
||||
|
@ -310,14 +312,26 @@ public class ForgeXplatImpl implements IXplatAbstractions {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean tryPlaceFluid(Level level, InteractionHand hand, BlockPos pos, ItemStack stack, Fluid fluid) {
|
||||
public boolean tryPlaceFluid(Level level, InteractionHand hand, BlockPos pos, Fluid fluid) {
|
||||
Optional<IFluidHandler> handler = FluidUtil.getFluidHandler(level, pos, Direction.UP).resolve();
|
||||
if (handler.isPresent() &&
|
||||
FluidUtil.tryEmptyContainer(stack, handler.get(), FluidAttributes.BUCKET_VOLUME, null, true).isSuccess()) {
|
||||
return true;
|
||||
return handler.isPresent() &&
|
||||
handler.get().fill(new FluidStack(fluid, FluidAttributes.BUCKET_VOLUME), EXECUTE) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean drainAllFluid(Level level, BlockPos pos) {
|
||||
Optional<IFluidHandler> handler = FluidUtil.getFluidHandler(level, pos, Direction.UP).resolve();
|
||||
if (handler.isPresent()) {
|
||||
boolean any = false;
|
||||
IFluidHandler pool = handler.get();
|
||||
for (int i = 0; i < pool.getTanks(); i++) {
|
||||
if (!pool.drain(pool.getFluidInTank(i), EXECUTE).isEmpty()) {
|
||||
any = true;
|
||||
}
|
||||
}
|
||||
return any;
|
||||
}
|
||||
return FluidUtil.tryPlaceFluid(null, level, hand, pos, stack, new FluidStack(
|
||||
fluid, FluidAttributes.BUCKET_VOLUME)).isSuccess();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Reference in a new issue