hytale-server/com/hypixel/hytale/builtin/fluid/FluidCommand.java

252 lines
14 KiB
Java

package com.hypixel.hytale.builtin.fluid;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.math.util.ChunkUtil;
import com.hypixel.hytale.math.util.MathUtil;
import com.hypixel.hytale.math.vector.Vector3i;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.server.core.asset.type.fluid.Fluid;
import com.hypixel.hytale.server.core.command.system.CommandContext;
import com.hypixel.hytale.server.core.command.system.arguments.system.OptionalArg;
import com.hypixel.hytale.server.core.command.system.arguments.system.RequiredArg;
import com.hypixel.hytale.server.core.command.system.arguments.types.ArgTypes;
import com.hypixel.hytale.server.core.command.system.arguments.types.AssetArgumentType;
import com.hypixel.hytale.server.core.command.system.arguments.types.RelativeIntPosition;
import com.hypixel.hytale.server.core.command.system.arguments.types.SingleArgumentType;
import com.hypixel.hytale.server.core.command.system.basecommands.AbstractCommandCollection;
import com.hypixel.hytale.server.core.command.system.basecommands.AbstractPlayerCommand;
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.WorldChunk;
import com.hypixel.hytale.server.core.universe.world.chunk.section.ChunkSection;
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 com.hypixel.hytale.server.core.util.TargetUtil;
import javax.annotation.Nonnull;
public class FluidCommand extends AbstractCommandCollection {
private static final SingleArgumentType<Fluid> FLUID_ARG = new AssetArgumentType("Fluid", Fluid.class, "");
public FluidCommand() {
super("fluid", "Fluid debug commands");
this.addSubCommand(new FluidCommand.SetCommand());
this.addSubCommand(new FluidCommand.GetCommand());
this.addSubCommand(new FluidCommand.SetRadiusCommand());
}
public static class GetCommand extends AbstractPlayerCommand {
@Nonnull
private static final Message MESSAGE_COMMANDS_ERRORS_PLAYER_NOT_LOOKING_AT_BLOCK = Message.translation("server.commands.errors.playerNotLookingAtBlock");
@Nonnull
private static final Message MESSAGE_COMMANDS_NO_SECTION_COMPONENT = Message.translation("server.commands.noSectionComponent");
@Nonnull
private final OptionalArg<RelativeIntPosition> targetOffset = this.withOptionalArg("offset", "", ArgTypes.RELATIVE_BLOCK_POSITION);
public GetCommand() {
super("get", "Gets the fluid at the target position");
}
@Override
protected void execute(
@Nonnull CommandContext context, @Nonnull Store<EntityStore> store, @Nonnull Ref<EntityStore> ref, @Nonnull PlayerRef playerRef, @Nonnull World world
) {
RelativeIntPosition offset = this.targetOffset.get(context);
Vector3i blockTarget = TargetUtil.getTargetBlock(ref, 8.0, store);
if (blockTarget == null) {
playerRef.sendMessage(MESSAGE_COMMANDS_ERRORS_PLAYER_NOT_LOOKING_AT_BLOCK);
} else {
ChunkStore chunkStore = world.getChunkStore();
Vector3i pos = offset == null ? blockTarget : offset.getBlockPosition(blockTarget.toVector3d(), chunkStore);
chunkStore.getChunkSectionReferenceAsync(ChunkUtil.chunkCoordinate(pos.x), ChunkUtil.chunkCoordinate(pos.y), ChunkUtil.chunkCoordinate(pos.z))
.thenAcceptAsync(
section -> {
Store<ChunkStore> sectionStore = section.getStore();
FluidSection fluidSection = sectionStore.getComponent((Ref<ChunkStore>)section, FluidSection.getComponentType());
if (fluidSection == null) {
playerRef.sendMessage(MESSAGE_COMMANDS_NO_SECTION_COMPONENT);
} else {
int index = ChunkUtil.indexBlock(pos.x, pos.y, pos.z);
Fluid fluid = fluidSection.getFluid(index);
byte level = fluidSection.getFluidLevel(index);
playerRef.sendMessage(
Message.translation("server.commands.get.success")
.param("x", pos.x)
.param("y", pos.y)
.param("z", pos.z)
.param("id", fluid.getId())
.param("level", (int)level)
);
}
},
world
);
}
}
}
public static class SetCommand extends AbstractPlayerCommand {
@Nonnull
private static final Message MESSAGE_COMMANDS_ERRORS_PLAYER_NOT_LOOKING_AT_BLOCK = Message.translation("server.commands.errors.playerNotLookingAtBlock");
@Nonnull
private static final Message MESSAGE_COMMANDS_SET_UNKNOWN_FLUID = Message.translation("server.commands.set.unknownFluid");
@Nonnull
private static final Message MESSAGE_COMMANDS_NO_SECTION_COMPONENT = Message.translation("server.commands.noSectionComponent");
@Nonnull
private final RequiredArg<Fluid> fluid = this.withRequiredArg("fluid", "", FluidCommand.FLUID_ARG);
@Nonnull
private final RequiredArg<Integer> level = this.withRequiredArg("level", "", ArgTypes.INTEGER);
@Nonnull
private final OptionalArg<RelativeIntPosition> targetOffset = this.withOptionalArg("offset", "", ArgTypes.RELATIVE_BLOCK_POSITION);
public SetCommand() {
super("set", "Changes the fluid at the target position");
}
@Override
protected void execute(
@Nonnull CommandContext context, @Nonnull Store<EntityStore> store, @Nonnull Ref<EntityStore> ref, @Nonnull PlayerRef playerRef, @Nonnull World world
) {
RelativeIntPosition offset = this.targetOffset.get(context);
Vector3i blockTarget = TargetUtil.getTargetBlock(ref, 8.0, store);
if (blockTarget == null) {
playerRef.sendMessage(MESSAGE_COMMANDS_ERRORS_PLAYER_NOT_LOOKING_AT_BLOCK);
} else {
ChunkStore chunkStore = world.getChunkStore();
Vector3i pos = offset == null ? blockTarget : offset.getBlockPosition(blockTarget.toVector3d(), chunkStore);
Fluid fluid = this.fluid.get(context);
if (fluid == null) {
playerRef.sendMessage(MESSAGE_COMMANDS_SET_UNKNOWN_FLUID);
} else {
Integer level = this.level.get(context);
if (level > fluid.getMaxFluidLevel()) {
level = fluid.getMaxFluidLevel();
playerRef.sendMessage(Message.translation("server.commands.set.maxFluidLevelClamped").param("level", fluid.getMaxFluidLevel()));
}
Integer finalLevel = level;
chunkStore.getChunkSectionReferenceAsync(ChunkUtil.chunkCoordinate(pos.x), ChunkUtil.chunkCoordinate(pos.y), ChunkUtil.chunkCoordinate(pos.z))
.thenAcceptAsync(
section -> {
Store<ChunkStore> sectionStore = section.getStore();
FluidSection fluidSection = sectionStore.getComponent((Ref<ChunkStore>)section, FluidSection.getComponentType());
if (fluidSection == null) {
playerRef.sendMessage(MESSAGE_COMMANDS_NO_SECTION_COMPONENT);
} else {
int index = ChunkUtil.indexBlock(pos.x, pos.y, pos.z);
fluidSection.setFluid(index, fluid, finalLevel.byteValue());
playerRef.sendMessage(
Message.translation("server.commands.set.success")
.param("x", pos.x)
.param("y", pos.y)
.param("z", pos.z)
.param("id", fluid.getId())
.param("level", finalLevel)
);
ChunkSection chunkSection = sectionStore.getComponent((Ref<ChunkStore>)section, ChunkSection.getComponentType());
WorldChunk worldChunk = sectionStore.getComponent(chunkSection.getChunkColumnReference(), WorldChunk.getComponentType());
worldChunk.markNeedsSaving();
worldChunk.setTicking(pos.x, pos.y, pos.z, true);
}
},
world
);
}
}
}
}
public static class SetRadiusCommand extends AbstractPlayerCommand {
@Nonnull
private static final Message MESSAGE_COMMANDS_SET_UNKNOWN_FLUID = Message.translation("server.commands.set.unknownFluid");
@Nonnull
private static final Message MESSAGE_COMMANDS_ERRORS_PLAYER_NOT_LOOKING_AT_BLOCK = Message.translation("server.commands.errors.playerNotLookingAtBlock");
@Nonnull
private final RequiredArg<Integer> radius = this.withRequiredArg("radius", "", ArgTypes.INTEGER);
@Nonnull
private final RequiredArg<Fluid> fluid = this.withRequiredArg("fluid", "", FluidCommand.FLUID_ARG);
@Nonnull
private final RequiredArg<Integer> level = this.withRequiredArg("level", "", ArgTypes.INTEGER);
@Nonnull
private final OptionalArg<RelativeIntPosition> targetOffset = this.withOptionalArg("offset", "", ArgTypes.RELATIVE_BLOCK_POSITION);
public SetRadiusCommand() {
super("setradius", "Changes the fluid at the player position in a given radius");
}
@Override
protected void execute(
@Nonnull CommandContext context, @Nonnull Store<EntityStore> store, @Nonnull Ref<EntityStore> ref, @Nonnull PlayerRef playerRef, @Nonnull World world
) {
RelativeIntPosition offset = this.targetOffset.get(context);
Vector3i blockTarget = TargetUtil.getTargetBlock(ref, 8.0, store);
if (blockTarget == null) {
playerRef.sendMessage(MESSAGE_COMMANDS_ERRORS_PLAYER_NOT_LOOKING_AT_BLOCK);
} else {
ChunkStore chunkStore = world.getChunkStore();
Vector3i pos = offset == null ? blockTarget : offset.getBlockPosition(blockTarget.toVector3d(), chunkStore);
Fluid fluid = this.fluid.get(context);
if (fluid == null) {
playerRef.sendMessage(MESSAGE_COMMANDS_SET_UNKNOWN_FLUID);
} else {
Integer level = this.level.get(context);
if (level > fluid.getMaxFluidLevel()) {
level = fluid.getMaxFluidLevel();
playerRef.sendMessage(Message.translation("server.commands.set.maxFluidLevelClamped").param("level", fluid.getMaxFluidLevel()));
}
Integer radius = this.radius.get(context);
int minX = pos.x - radius;
int maxX = pos.x + radius;
int minY = pos.y - radius;
int maxY = pos.y + radius;
int minZ = pos.z - radius;
int maxZ = pos.z + radius;
int minCX = ChunkUtil.chunkCoordinate(minX);
int maxCX = ChunkUtil.chunkCoordinate(maxX);
int minCY = ChunkUtil.chunkCoordinate(minY);
int maxCY = ChunkUtil.chunkCoordinate(maxY);
int minCZ = ChunkUtil.chunkCoordinate(minZ);
int maxCZ = ChunkUtil.chunkCoordinate(maxZ);
Integer finalLevel = level;
for (int cx = minCX; cx <= maxCX; cx++) {
for (int cz = minCZ; cz <= maxCZ; cz++) {
int relMinX = MathUtil.clamp(minX - ChunkUtil.minBlock(cx), 0, 32);
int relMaxX = MathUtil.clamp(maxX - ChunkUtil.minBlock(cx), 0, 32);
int relMinZ = MathUtil.clamp(minZ - ChunkUtil.minBlock(cz), 0, 32);
int relMaxZ = MathUtil.clamp(maxZ - ChunkUtil.minBlock(cz), 0, 32);
for (int cy = minCY; cy <= maxCY; cy++) {
chunkStore.getChunkSectionReferenceAsync(cx, cy, cz).thenAcceptAsync(section -> {
Store<ChunkStore> sectionStore = section.getStore();
FluidSection fluidSection = sectionStore.getComponent((Ref<ChunkStore>)section, FluidSection.getComponentType());
if (fluidSection != null) {
int relMinY = MathUtil.clamp(minY - ChunkUtil.minBlock(fluidSection.getY()), 0, 32);
int relMaxY = MathUtil.clamp(maxY - ChunkUtil.minBlock(fluidSection.getY()), 0, 32);
ChunkSection sectionComp = sectionStore.getComponent((Ref<ChunkStore>)section, ChunkSection.getComponentType());
WorldChunk worldChunk = sectionStore.getComponent(sectionComp.getChunkColumnReference(), WorldChunk.getComponentType());
for (int y = relMinY; y < relMaxY; y++) {
for (int z = relMinZ; z < relMaxZ; z++) {
for (int x = relMinX; x < relMaxX; x++) {
int index = ChunkUtil.indexBlock(x, y, z);
fluidSection.setFluid(index, fluid, finalLevel.byteValue());
worldChunk.setTicking(pos.x, pos.y, pos.z, true);
}
}
}
worldChunk.markNeedsSaving();
}
}, world);
}
}
}
}
}
}
}
}