Geyser/core/src/main/java/org/geysermc/geyser/util/StructureBlockUtils.java

165 lines
7.4 KiB
Java
Raw Normal View History

Feature: Structure block translation (#4521) * ported camotoy's attempt of implementing structure blocks, removal of a few TODO's * no more parsing of java structure templates * Don't attempt to re-request structure size * ensure we can load structures in even if we know the size * init: send correct structure size/offset/rotation to java, not fully working yet * restore offsets so we are sending correct values to the java server regarding where we want the structure to be placed * something something mirror * attempt at proper offsets for mirroring AND rotations. this was not fun at all * rotation, mirror, offsetting all seem to work * undo import changes * fix NPE * Proper handling of empty structures, ensure that we can clear the structure block outline when a zero vector was sent for structure size * oops * Update core/src/main/java/org/geysermc/geyser/session/cache/StructureBlockCache.java Co-authored-by: rtm516 <rtm516@users.noreply.github.com> * Update core/src/main/java/org/geysermc/geyser/translator/level/block/entity/StructureBlockBlockEntityTranslator.java Co-authored-by: rtm516 <rtm516@users.noreply.github.com> * Update core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockStructureBlockUpdateTranslator.java Co-authored-by: rtm516 <rtm516@users.noreply.github.com> * Update core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockStructureTemplateDataRequestTranslator.java Co-authored-by: rtm516 <rtm516@users.noreply.github.com> * consolidate java structure sending into one method * fix merge conflict --------- Co-authored-by: rtm516 <rtm516@users.noreply.github.com>
2024-04-17 21:21:25 +00:00
/*
* Copyright (c) 2019-2024 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.util;
import com.github.steveice10.mc.protocol.data.game.inventory.UpdateStructureBlockAction;
import com.github.steveice10.mc.protocol.data.game.inventory.UpdateStructureBlockMode;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundSetStructureBlockPacket;
import org.cloudburstmc.math.vector.Vector3i;
import org.cloudburstmc.nbt.NbtList;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtType;
import org.cloudburstmc.protocol.bedrock.data.structure.StructureMirror;
import org.cloudburstmc.protocol.bedrock.data.structure.StructureRotation;
import org.cloudburstmc.protocol.bedrock.data.structure.StructureSettings;
import org.cloudburstmc.protocol.bedrock.data.structure.StructureTemplateResponseType;
import org.cloudburstmc.protocol.bedrock.packet.StructureTemplateDataResponsePacket;
import org.geysermc.geyser.session.GeyserSession;
public class StructureBlockUtils {
private static final NbtMap EMPTY_STRUCTURE_DATA;
static {
NbtMapBuilder builder = NbtMap.builder();
builder.putInt("format_version", 1);
builder.putCompound("structure", NbtMap.builder()
.putList("block_indices", NbtType.LIST, NbtList.EMPTY, NbtList.EMPTY)
.putList("entities", NbtType.COMPOUND)
.putCompound("palette", NbtMap.EMPTY)
.build());
builder.putList("structure_world_origin", NbtType.INT, 0, 0, 0);
EMPTY_STRUCTURE_DATA = builder.build();
}
public static void sendEmptyStructureData(GeyserSession session) {
StructureTemplateDataResponsePacket responsePacket = new StructureTemplateDataResponsePacket();
responsePacket.setName("");
responsePacket.setSave(false);
responsePacket.setType(StructureTemplateResponseType.QUERY);
session.sendUpstreamPacket(responsePacket);
}
public static void sendStructureData(GeyserSession session,Vector3i size, String name) {
StructureTemplateDataResponsePacket responsePacket = new StructureTemplateDataResponsePacket();
responsePacket.setName(name);
responsePacket.setSave(true);
responsePacket.setTag(EMPTY_STRUCTURE_DATA.toBuilder()
// Bedrock does not like negative sizes here
.putList("size", NbtType.INT, Math.abs(size.getX()), size.getY(), Math.abs(size.getZ()))
.build());
responsePacket.setType(StructureTemplateResponseType.QUERY);
session.sendUpstreamPacket(responsePacket);
}
public static Vector3i calculateOffset(StructureRotation structureRotation, StructureMirror structureMirror,
int sizeX, int sizeZ) {
int newOffsetX = 0;
int newOffsetZ = 0;
switch (structureRotation) {
case ROTATE_90 -> {
switch (structureMirror) {
case NONE -> newOffsetX -= sizeZ - 1;
case X -> {
newOffsetZ -= sizeX - 1;
newOffsetX -= sizeZ - 1;
}
}
}
case ROTATE_180 -> {
switch (structureMirror) {
case NONE -> {
newOffsetX -= sizeX - 1;
newOffsetZ -= sizeZ - 1;
}
case Z -> newOffsetX -= sizeX - 1;
case X -> newOffsetZ -= sizeZ - 1;
}
}
case ROTATE_270 -> {
switch (structureMirror) {
case NONE -> newOffsetZ -= sizeX - 1;
case Z -> {
newOffsetZ -= sizeX - 1;
newOffsetX -= sizeZ - 1;
}
}
}
default -> {
switch (structureMirror) {
case Z -> newOffsetZ -= sizeZ - 1;
case X -> newOffsetX -= sizeX - 1;
}
}
}
return Vector3i.from(newOffsetX, 0, newOffsetZ);
}
public static void sendJavaStructurePacket(GeyserSession session, Vector3i blockPosition, Vector3i size, UpdateStructureBlockMode mode, UpdateStructureBlockAction action,
StructureSettings settings, boolean boundingBoxVisible, String structureName) {
com.github.steveice10.mc.protocol.data.game.level.block.StructureMirror mirror = switch (settings.getMirror()) {
case X -> com.github.steveice10.mc.protocol.data.game.level.block.StructureMirror.FRONT_BACK;
case Z -> com.github.steveice10.mc.protocol.data.game.level.block.StructureMirror.LEFT_RIGHT;
default -> com.github.steveice10.mc.protocol.data.game.level.block.StructureMirror.NONE;
};
com.github.steveice10.mc.protocol.data.game.level.block.StructureRotation rotation = switch (settings.getRotation()) {
case ROTATE_90 -> com.github.steveice10.mc.protocol.data.game.level.block.StructureRotation.CLOCKWISE_90;
case ROTATE_180 -> com.github.steveice10.mc.protocol.data.game.level.block.StructureRotation.CLOCKWISE_180;
case ROTATE_270 -> com.github.steveice10.mc.protocol.data.game.level.block.StructureRotation.COUNTERCLOCKWISE_90;
default -> com.github.steveice10.mc.protocol.data.game.level.block.StructureRotation.NONE;
};
Vector3i offset = settings.getOffset();
if (session.getStructureBlockCache().getBedrockOffset() != null) {
offset = settings.getOffset().sub(session.getStructureBlockCache().getBedrockOffset());
}
ServerboundSetStructureBlockPacket structureBlockPacket = new ServerboundSetStructureBlockPacket(
blockPosition,
action,
mode,
structureName,
offset,
settings.getSize(),
mirror,
rotation,
"",
settings.getIntegrityValue(),
settings.getIntegritySeed(),
settings.isIgnoringEntities(),
false,
boundingBoxVisible
);
session.sendDownstreamPacket(structureBlockPacket);
}
}