Add PlaceFluidEvent and patch PlaceFluidInteraction
- PlaceFluidEvent: cancellable ECS event for fluid placement - PlaceFluidInteraction: fire event before placing fluid
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
package com.hypixel.hytale.server.core.event.events.ecs;
|
||||
|
||||
import com.hypixel.hytale.component.system.CancellableEcsEvent;
|
||||
import com.hypixel.hytale.math.vector.Vector3i;
|
||||
import com.hypixel.hytale.server.core.asset.type.fluid.Fluid;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* Event fired when a player attempts to place a fluid (e.g., water bucket).
|
||||
* This event is cancellable - if cancelled, the fluid will not be placed.
|
||||
*/
|
||||
public class PlaceFluidEvent extends CancellableEcsEvent {
|
||||
@Nonnull
|
||||
private final Vector3i targetBlock;
|
||||
@Nonnull
|
||||
private final Fluid fluid;
|
||||
|
||||
public PlaceFluidEvent(@Nonnull Vector3i targetBlock, @Nonnull Fluid fluid) {
|
||||
this.targetBlock = targetBlock;
|
||||
this.fluid = fluid;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public Vector3i getTargetBlock() {
|
||||
return this.targetBlock;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public Fluid getFluid() {
|
||||
return this.fluid;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
package com.hypixel.hytale.server.core.modules.interaction.interaction.config.client;
|
||||
|
||||
import com.hypixel.hytale.codec.Codec;
|
||||
import com.hypixel.hytale.codec.KeyedCodec;
|
||||
import com.hypixel.hytale.codec.builder.BuilderCodec;
|
||||
import com.hypixel.hytale.component.CommandBuffer;
|
||||
import com.hypixel.hytale.component.Ref;
|
||||
import com.hypixel.hytale.component.Store;
|
||||
import com.hypixel.hytale.math.util.ChunkUtil;
|
||||
import com.hypixel.hytale.math.vector.Vector3i;
|
||||
import com.hypixel.hytale.protocol.GameMode;
|
||||
import com.hypixel.hytale.protocol.InteractionType;
|
||||
import com.hypixel.hytale.protocol.WaitForDataFrom;
|
||||
import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockFace;
|
||||
import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType;
|
||||
import com.hypixel.hytale.server.core.asset.type.fluid.Fluid;
|
||||
import com.hypixel.hytale.server.core.asset.type.fluid.FluidTicker;
|
||||
import com.hypixel.hytale.server.core.entity.InteractionContext;
|
||||
import com.hypixel.hytale.server.core.entity.entities.Player;
|
||||
import com.hypixel.hytale.server.core.event.events.ecs.PlaceFluidEvent;
|
||||
import com.hypixel.hytale.server.core.inventory.ItemStack;
|
||||
import com.hypixel.hytale.server.core.modules.interaction.interaction.CooldownHandler;
|
||||
import com.hypixel.hytale.server.core.modules.interaction.interaction.config.SimpleInteraction;
|
||||
import com.hypixel.hytale.server.core.universe.PlayerRef;
|
||||
import com.hypixel.hytale.server.core.universe.world.World;
|
||||
import com.hypixel.hytale.server.core.universe.world.chunk.BlockChunk;
|
||||
import com.hypixel.hytale.server.core.universe.world.chunk.section.FluidSection;
|
||||
import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore;
|
||||
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class PlaceFluidInteraction extends SimpleBlockInteraction {
|
||||
@Nonnull
|
||||
public static final BuilderCodec<PlaceFluidInteraction> CODEC = BuilderCodec.builder(
|
||||
PlaceFluidInteraction.class, PlaceFluidInteraction::new, SimpleInteraction.CODEC
|
||||
)
|
||||
.documentation("Places the current or given block.")
|
||||
.<String>append(
|
||||
new KeyedCodec<>("FluidToPlace", Codec.STRING),
|
||||
(placeBlockInteraction, blockTypeKey) -> placeBlockInteraction.fluidKey = blockTypeKey,
|
||||
placeBlockInteraction -> placeBlockInteraction.fluidKey
|
||||
)
|
||||
.addValidatorLate(() -> Fluid.VALIDATOR_CACHE.getValidator().late())
|
||||
.add()
|
||||
.append(
|
||||
new KeyedCodec<>("RemoveItemInHand", Codec.BOOLEAN),
|
||||
(placeBlockInteraction, aBoolean) -> placeBlockInteraction.removeItemInHand = aBoolean,
|
||||
placeBlockInteraction -> placeBlockInteraction.removeItemInHand
|
||||
)
|
||||
.add()
|
||||
.build();
|
||||
@Nullable
|
||||
protected String fluidKey;
|
||||
protected boolean removeItemInHand = true;
|
||||
|
||||
public PlaceFluidInteraction() {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getFluidKey() {
|
||||
return this.fluidKey;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public WaitForDataFrom getWaitForDataFrom() {
|
||||
return WaitForDataFrom.Client;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void interactWithBlock(
|
||||
@Nonnull World world,
|
||||
@Nonnull CommandBuffer<EntityStore> commandBuffer,
|
||||
@Nonnull InteractionType type,
|
||||
@Nonnull InteractionContext context,
|
||||
@Nullable ItemStack itemInHand,
|
||||
@Nonnull Vector3i targetBlock,
|
||||
@Nonnull CooldownHandler cooldownHandler
|
||||
) {
|
||||
Store<ChunkStore> store = world.getChunkStore().getStore();
|
||||
int fluidIndex = Fluid.getFluidIdOrUnknown(this.fluidKey, "Unknown fluid: %s", this.fluidKey);
|
||||
Fluid fluid = Fluid.getAssetMap().getAsset(fluidIndex);
|
||||
Vector3i target = targetBlock;
|
||||
BlockType targetBlockType = world.getBlockType(targetBlock);
|
||||
if (FluidTicker.isSolid(targetBlockType)) {
|
||||
target = targetBlock.clone();
|
||||
BlockFace face = BlockFace.fromProtocolFace(context.getClientState().blockFace);
|
||||
target.add(face.getDirection());
|
||||
}
|
||||
|
||||
// Fire PlaceFluidEvent and check if cancelled
|
||||
Ref<EntityStore> entityRef = context.getEntity();
|
||||
PlaceFluidEvent event = new PlaceFluidEvent(target, fluid);
|
||||
commandBuffer.invoke(entityRef, event);
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Ref<ChunkStore> section = world.getChunkStore()
|
||||
.getChunkSectionReference(ChunkUtil.chunkCoordinate(target.x), ChunkUtil.chunkCoordinate(target.y), ChunkUtil.chunkCoordinate(target.z));
|
||||
if (section != null) {
|
||||
FluidSection fluidSectionComponent = store.getComponent(section, FluidSection.getComponentType());
|
||||
if (fluidSectionComponent != null) {
|
||||
fluidSectionComponent.setFluid(target.x, target.y, target.z, fluid, (byte) fluid.getMaxFluidLevel());
|
||||
Ref<ChunkStore> chunkColumn = world.getChunkStore().getChunkReference(ChunkUtil.indexChunkFromBlock(target.x, target.z));
|
||||
if (chunkColumn != null) {
|
||||
BlockChunk blockChunkComponent = store.getComponent(chunkColumn, BlockChunk.getComponentType());
|
||||
blockChunkComponent.setTicking(target.x, target.y, target.z, true);
|
||||
Ref<EntityStore> ref = context.getEntity();
|
||||
Player playerComponent = commandBuffer.getComponent(ref, Player.getComponentType());
|
||||
PlayerRef playerRefComponent = commandBuffer.getComponent(ref, PlayerRef.getComponentType());
|
||||
if ((playerRefComponent == null || playerComponent != null && playerComponent.getGameMode() == GameMode.Adventure)
|
||||
&& itemInHand.getQuantity() == 1
|
||||
&& this.removeItemInHand) {
|
||||
context.setHeldItem(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void simulateInteractWithBlock(
|
||||
@Nonnull InteractionType type, @Nonnull InteractionContext context, @Nullable ItemStack itemInHand, @Nonnull World world, @Nonnull Vector3i targetBlock
|
||||
) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean needsRemoteSync() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PlaceBlockInteraction{blockTypeKey=" + this.fluidKey + ", removeItemInHand=" + this.removeItemInHand + "} " + super.toString();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user