Minestom/demo/src/main/java/net/minestom/scratch/tools/ScratchFeature.java

177 lines
7.5 KiB
Java

package net.minestom.scratch.tools;
import net.kyori.adventure.text.Component;
import net.minestom.server.coordinate.Point;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.instance.block.BlockFace;
import net.minestom.server.item.ItemStack;
import net.minestom.server.network.packet.client.ClientPacket;
import net.minestom.server.network.packet.client.play.*;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.play.*;
import net.minestom.server.utils.Direction;
import net.minestom.server.utils.chunk.ChunkUtils;
import net.minestom.server.utils.inventory.PlayerInventoryUtils;
import java.util.List;
import java.util.function.Consumer;
public interface ScratchFeature extends Consumer<ClientPacket> {
record Messaging(Mapping mapping) implements ScratchFeature {
@Override
public void accept(ClientPacket packet) {
if (packet instanceof ClientChatMessagePacket chatMessagePacket) {
final String message = chatMessagePacket.message();
final Component formatted = mapping.formatMessage(message);
mapping.signal(new SystemChatPacket(formatted, false));
}
}
public interface Mapping {
Component formatMessage(String message);
void signal(ServerPacket.Play packet);
}
}
record Movement(Mapping mapping) implements ScratchFeature {
@Override
public void accept(ClientPacket packet) {
final int id = mapping.id();
if (packet instanceof ClientPlayerPositionAndRotationPacket positionAndRotationPacket) {
final Pos position = positionAndRotationPacket.position();
mapping.updatePosition(position);
mapping.signalMovement(new EntityTeleportPacket(id, position, positionAndRotationPacket.onGround()));
mapping.signalMovement(new EntityHeadLookPacket(id, position.yaw()));
} else if (packet instanceof ClientPlayerPositionPacket positionPacket) {
final Pos position = mapping.position().withCoord(positionPacket.position());
mapping.updatePosition(position);
mapping.signalMovement(new EntityTeleportPacket(id, position, positionPacket.onGround()));
} else if (packet instanceof ClientPlayerRotationPacket rotationPacket) {
final Pos position = mapping.position().withView(rotationPacket.yaw(), rotationPacket.pitch());
mapping.signalMovement(new EntityRotationPacket(id, position.yaw(), position.pitch(), rotationPacket.onGround()));
mapping.signalMovement(new EntityHeadLookPacket(id, position.yaw()));
}
}
public interface Mapping {
int id();
Pos position();
void updatePosition(Pos position);
void signalMovement(ServerPacket.Play packet);
}
}
record ChunkLoading(Mapping mapping) implements ScratchFeature {
@Override
public void accept(ClientPacket packet) {
final Pos oldPosition = mapping.oldPosition();
Pos position = null;
if (packet instanceof ClientPlayerPositionAndRotationPacket positionAndRotationPacket) {
position = positionAndRotationPacket.position();
} else if (packet instanceof ClientPlayerPositionPacket positionPacket) {
position = Pos.fromPoint(positionPacket.position());
}
if (position == null || position.sameChunk(oldPosition)) return;
final int oldChunkX = oldPosition.chunkX();
final int oldChunkZ = oldPosition.chunkZ();
final int newChunkX = position.chunkX();
final int newChunkZ = position.chunkZ();
mapping.sendPacket(new UpdateViewPositionPacket(newChunkX, newChunkZ));
ChunkUtils.forDifferingChunksInRange(newChunkX, newChunkZ, oldChunkX, oldChunkZ,
mapping.viewDistance(),
(x, z) -> mapping.sendPacket(mapping.chunkPacket(x, z)),
(x, z) -> mapping.sendPacket(new UnloadChunkPacket(x, z)));
}
public interface Mapping {
int viewDistance();
Pos oldPosition();
ChunkDataPacket chunkPacket(int chunkX, int chunkZ);
void sendPacket(ServerPacket.Play packet);
}
}
record EntityInteract(Mapping mapping) implements ScratchFeature {
@Override
public void accept(ClientPacket packet) {
if (packet instanceof ClientInteractEntityPacket interactEntityPacket) {
final int targetId = interactEntityPacket.targetId();
final ClientInteractEntityPacket.Type type = interactEntityPacket.type();
if (type instanceof ClientInteractEntityPacket.Interact interact) {
mapping.right(targetId);
} else if (type instanceof ClientInteractEntityPacket.Attack attack) {
mapping.left(targetId);
}
}
}
public interface Mapping {
void left(int id);
void right(int id);
}
}
record BlockInteract(Mapping mapping) implements ScratchFeature {
@Override
public void accept(ClientPacket packet) {
if (packet instanceof ClientPlayerDiggingPacket diggingPacket) {
final ClientPlayerDiggingPacket.Status status = diggingPacket.status();
final Point blockPosition = diggingPacket.blockPosition();
mapping.acknowledge(new AcknowledgeBlockChangePacket(diggingPacket.sequence()));
switch (status) {
case STARTED_DIGGING -> {
if (mapping.creative()) {
mapping.breakBlock(blockPosition);
}
}
}
} else if (packet instanceof ClientPlayerBlockPlacementPacket blockPlacementPacket) {
final Point blockPosition = blockPlacementPacket.blockPosition();
final BlockFace blockFace = blockPlacementPacket.blockFace();
final Direction direction = blockFace.toDirection();
mapping.placeBlock(blockPosition.add(direction.normalX(), direction.normalY(), direction.normalZ()));
}
}
public interface Mapping {
boolean creative();
void breakBlock(Point point);
void placeBlock(Point point);
void acknowledge(ServerPacket.Play packet);
}
}
record InventoryHandling(Mapping mapping) implements ScratchFeature {
@Override
public void accept(ClientPacket packet) {
if (packet instanceof ClientClickWindowPacket(
byte windowId, int stateId, short slot, byte button, ClientClickWindowPacket.ClickType clickType,
List<ClientClickWindowPacket.ChangedSlot> changedSlots, ItemStack clickedItem
)) {
for (ClientClickWindowPacket.ChangedSlot changedSlot : changedSlots) {
final int internalSlot = PlayerInventoryUtils.convertPlayerInventorySlot(changedSlot.slot(), PlayerInventoryUtils.OFFSET);
mapping.setPlayerItem(internalSlot, changedSlot.item());
}
mapping.setCursorItem(clickedItem);
}
}
public interface Mapping {
void setPlayerItem(int slot, ItemStack itemStack);
void setCursorItem(ItemStack itemStack);
}
}
}