forked from GeyserMC/Geyser
Add block entity translators for Bedrock-only block entities (#478)
* Initial work on flower pots * Flowers work in-game, not yet chunk load * Don't overwrite my code before merge * Finish up flower pots; add piston support on chunk load * Clean up * Remove debug line; update mappings
This commit is contained in:
parent
fcf1949b28
commit
b49004ddaf
8 changed files with 306 additions and 5 deletions
|
@ -27,11 +27,17 @@ package org.geysermc.connector.network.translators.world.block;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
|
import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
|
||||||
|
import com.nukkitx.nbt.tag.CompoundTag;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2BooleanMap;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2BooleanOpenHashMap;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ByteMap;
|
import it.unimi.dsi.fastutil.objects.Object2ByteMap;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ByteOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Object2ByteOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -41,7 +47,11 @@ public class BlockStateValues {
|
||||||
|
|
||||||
private static final Object2IntMap<BlockState> BANNER_COLORS = new Object2IntOpenHashMap<>();
|
private static final Object2IntMap<BlockState> BANNER_COLORS = new Object2IntOpenHashMap<>();
|
||||||
private static final Object2ByteMap<BlockState> BED_COLORS = new Object2ByteOpenHashMap<>();
|
private static final Object2ByteMap<BlockState> BED_COLORS = new Object2ByteOpenHashMap<>();
|
||||||
|
private static final Int2ObjectMap<String> FLOWER_POT_VALUES = new Int2ObjectOpenHashMap<>();
|
||||||
|
private static final Map<String, CompoundTag> FLOWER_POT_BLOCKS = new HashMap<>();
|
||||||
private static final Object2IntMap<BlockState> NOTEBLOCK_PITCHES = new Object2IntOpenHashMap<>();
|
private static final Object2IntMap<BlockState> NOTEBLOCK_PITCHES = new Object2IntOpenHashMap<>();
|
||||||
|
private static final Int2BooleanMap IS_STICKY_PISTON = new Int2BooleanOpenHashMap();
|
||||||
|
private static final Int2BooleanMap PISTON_VALUES = new Int2BooleanOpenHashMap();
|
||||||
private static final Object2ByteMap<BlockState> SKULL_VARIANTS = new Object2ByteOpenHashMap<>();
|
private static final Object2ByteMap<BlockState> SKULL_VARIANTS = new Object2ByteOpenHashMap<>();
|
||||||
private static final Object2ByteMap<BlockState> SKULL_ROTATIONS = new Object2ByteOpenHashMap<>();
|
private static final Object2ByteMap<BlockState> SKULL_ROTATIONS = new Object2ByteOpenHashMap<>();
|
||||||
private static final Object2ByteMap<BlockState> SHULKERBOX_DIRECTIONS = new Object2ByteOpenHashMap<>();
|
private static final Object2ByteMap<BlockState> SHULKERBOX_DIRECTIONS = new Object2ByteOpenHashMap<>();
|
||||||
|
@ -64,12 +74,25 @@ public class BlockStateValues {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (entry.getKey().contains("potted_")) {
|
||||||
|
System.out.println(entry.getKey().replace("potted_", ""));
|
||||||
|
FLOWER_POT_VALUES.put(javaBlockState.getId(), entry.getKey().replace("potted_", ""));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
JsonNode notePitch = entry.getValue().get("note_pitch");
|
JsonNode notePitch = entry.getValue().get("note_pitch");
|
||||||
if (notePitch != null) {
|
if (notePitch != null) {
|
||||||
NOTEBLOCK_PITCHES.put(javaBlockState, entry.getValue().get("note_pitch").intValue());
|
NOTEBLOCK_PITCHES.put(javaBlockState, entry.getValue().get("note_pitch").intValue());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (entry.getKey().contains("piston")) {
|
||||||
|
// True if extended, false if not
|
||||||
|
PISTON_VALUES.put(javaBlockState.getId(), entry.getKey().contains("extended=true"));
|
||||||
|
IS_STICKY_PISTON.put(javaBlockState.getId(), entry.getKey().contains("sticky"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
JsonNode skullVariation = entry.getValue().get("variation");
|
JsonNode skullVariation = entry.getValue().get("variation");
|
||||||
if(skullVariation != null) {
|
if(skullVariation != null) {
|
||||||
SKULL_VARIANTS.put(javaBlockState, (byte) skullVariation.intValue());
|
SKULL_VARIANTS.put(javaBlockState, (byte) skullVariation.intValue());
|
||||||
|
@ -114,6 +137,22 @@ public class BlockStateValues {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the Int2ObjectMap of flower pot block states to containing plant
|
||||||
|
* @return Int2ObjectMap of flower pot values
|
||||||
|
*/
|
||||||
|
public static Int2ObjectMap<String> getFlowerPotValues() {
|
||||||
|
return FLOWER_POT_VALUES;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the map of contained flower pot plants to Bedrock CompoundTag
|
||||||
|
* @return Map of flower pot blocks.
|
||||||
|
*/
|
||||||
|
public static Map<String, CompoundTag> getFlowerPotBlocks() {
|
||||||
|
return FLOWER_POT_BLOCKS;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The note that noteblocks output when hit is part of the block state in Java but sent as a BlockEventPacket in Bedrock.
|
* The note that noteblocks output when hit is part of the block state in Java but sent as a BlockEventPacket in Bedrock.
|
||||||
* This gives an integer pitch that Bedrock can use.
|
* This gives an integer pitch that Bedrock can use.
|
||||||
|
@ -127,6 +166,18 @@ public class BlockStateValues {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the Int2BooleanMap showing if a piston block state is extended or not.
|
||||||
|
* @return the Int2BooleanMap of piston extensions.
|
||||||
|
*/
|
||||||
|
public static Int2BooleanMap getPistonValues() {
|
||||||
|
return PISTON_VALUES;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isStickyPiston(BlockState blockState) {
|
||||||
|
return IS_STICKY_PISTON.get(blockState.getId());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Skull variations are part of the namespaced ID in Java Edition, but part of the block entity tag in Bedrock.
|
* Skull variations are part of the namespaced ID in Java Edition, but part of the block entity tag in Bedrock.
|
||||||
* This gives a byte variant ID that Bedrock can use.
|
* This gives a byte variant ID that Bedrock can use.
|
||||||
|
|
|
@ -153,6 +153,11 @@ public class BlockTranslator {
|
||||||
|
|
||||||
BlockStateValues.storeBlockStateValues(entry, javaBlockState);
|
BlockStateValues.storeBlockStateValues(entry, javaBlockState);
|
||||||
|
|
||||||
|
// Get the tag needed for non-empty flower pots
|
||||||
|
if (entry.getValue().get("pottable") != null) {
|
||||||
|
BlockStateValues.getFlowerPotBlocks().put(entry.getKey().split("\\[")[0], buildBedrockState(entry.getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
if ("minecraft:water[level=0]".equals(javaId)) {
|
if ("minecraft:water[level=0]".equals(javaId)) {
|
||||||
waterRuntimeId = bedrockRuntimeId;
|
waterRuntimeId = bedrockRuntimeId;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2020 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.connector.network.translators.world.block.entity;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
|
||||||
|
import com.nukkitx.math.vector.Vector3i;
|
||||||
|
import com.nukkitx.nbt.tag.CompoundTag;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implemented only if a block is a block entity in Bedrock and not Java Edition.
|
||||||
|
*/
|
||||||
|
public interface BedrockOnlyBlockEntity {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the block on Bedrock Edition.
|
||||||
|
* @param session GeyserSession.
|
||||||
|
* @param blockState The Java block state.
|
||||||
|
* @param position The Bedrock block position.
|
||||||
|
*/
|
||||||
|
void updateBlock(GeyserSession session, BlockState blockState, Vector3i position);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the tag of the Bedrock-only block entity
|
||||||
|
* @param position Bedrock position of block.
|
||||||
|
* @param blockState Java BlockState of block.
|
||||||
|
* @return Bedrock tag, or null if not a Bedrock-only Block Entity
|
||||||
|
*/
|
||||||
|
static CompoundTag getTag(Vector3i position, BlockState blockState) {
|
||||||
|
if (new FlowerPotBlockEntityTranslator().isBlock(blockState)) {
|
||||||
|
return FlowerPotBlockEntityTranslator.getTag(blockState, position);
|
||||||
|
} else if (PistonBlockEntityTranslator.isBlock(blockState)) {
|
||||||
|
return PistonBlockEntityTranslator.getTag(blockState, position);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2020 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.connector.network.translators.world.block.entity;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
|
||||||
|
import com.nukkitx.math.vector.Vector3i;
|
||||||
|
import com.nukkitx.nbt.CompoundTagBuilder;
|
||||||
|
import com.nukkitx.nbt.tag.CompoundTag;
|
||||||
|
import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
import org.geysermc.connector.network.translators.world.block.BlockStateValues;
|
||||||
|
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||||
|
import org.geysermc.connector.utils.BlockEntityUtils;
|
||||||
|
|
||||||
|
public class FlowerPotBlockEntityTranslator implements BedrockOnlyBlockEntity, RequiresBlockState {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isBlock(BlockState blockState) {
|
||||||
|
return (BlockStateValues.getFlowerPotValues().containsKey(blockState.getId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateBlock(GeyserSession session, BlockState blockState, Vector3i position) {
|
||||||
|
BlockEntityUtils.updateBlockEntity(session, getTag(blockState, position), position);
|
||||||
|
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
|
||||||
|
updateBlockPacket.setDataLayer(0);
|
||||||
|
updateBlockPacket.setRuntimeId(BlockTranslator.getBedrockBlockId(blockState));
|
||||||
|
updateBlockPacket.setBlockPosition(position);
|
||||||
|
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY);
|
||||||
|
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NONE);
|
||||||
|
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS);
|
||||||
|
session.getUpstream().sendPacket(updateBlockPacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the Nukkit CompoundTag of the flower pot.
|
||||||
|
* @param blockState Java BlockState of flower pot.
|
||||||
|
* @param position Bedrock position of flower pot.
|
||||||
|
* @return Bedrock tag of flower pot.
|
||||||
|
*/
|
||||||
|
public static CompoundTag getTag(BlockState blockState, Vector3i position) {
|
||||||
|
CompoundTagBuilder tagBuilder = CompoundTagBuilder.builder()
|
||||||
|
.intTag("x", position.getX())
|
||||||
|
.intTag("y", position.getY())
|
||||||
|
.intTag("z", position.getZ())
|
||||||
|
.byteTag("isMovable", (byte) 1)
|
||||||
|
.stringTag("id", "FlowerPot");
|
||||||
|
// Get the Java name of the plant inside. e.g. minecraft:oak_sapling
|
||||||
|
String name = BlockStateValues.getFlowerPotValues().get(blockState.getId());
|
||||||
|
if (name != null) {
|
||||||
|
// Get the Bedrock CompoundTag of the block.
|
||||||
|
// This is where we need to store the *Java* name because Bedrock has six minecraft:sapling blocks with different block states.
|
||||||
|
CompoundTag plant = BlockStateValues.getFlowerPotBlocks().get(name);
|
||||||
|
if (plant != null) {
|
||||||
|
tagBuilder.tag(plant.toBuilder().build("PlantBlock"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tagBuilder.buildRootTag();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2020 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.connector.network.translators.world.block.entity;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
|
||||||
|
import com.nukkitx.math.vector.Vector3i;
|
||||||
|
import com.nukkitx.nbt.CompoundTagBuilder;
|
||||||
|
import com.nukkitx.nbt.tag.CompoundTag;
|
||||||
|
import org.geysermc.connector.network.translators.world.block.BlockStateValues;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pistons are a special case where they are only a block entity on Bedrock.
|
||||||
|
*/
|
||||||
|
public class PistonBlockEntityTranslator {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used in ChunkUtils to determine if the block is a piston.
|
||||||
|
* @param blockState Java BlockState of block.
|
||||||
|
* @return if block is a piston or not.
|
||||||
|
*/
|
||||||
|
public static boolean isBlock(BlockState blockState) {
|
||||||
|
return BlockStateValues.getPistonValues().containsKey(blockState.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the Nukkit CompoundTag to send to the client on chunk
|
||||||
|
* @param blockState Java BlockState of block.
|
||||||
|
* @param position Bedrock position of piston.
|
||||||
|
* @return Bedrock tag of piston.
|
||||||
|
*/
|
||||||
|
public static CompoundTag getTag(BlockState blockState, Vector3i position) {
|
||||||
|
CompoundTagBuilder tagBuilder = CompoundTagBuilder.builder()
|
||||||
|
.intTag("x", position.getX())
|
||||||
|
.intTag("y", position.getY())
|
||||||
|
.intTag("z", position.getZ())
|
||||||
|
.byteTag("isMovable", (byte) 1)
|
||||||
|
.stringTag("id", "PistonArm");
|
||||||
|
if (BlockStateValues.getPistonValues().containsKey(blockState.getId())) {
|
||||||
|
boolean extended = BlockStateValues.getPistonValues().get(blockState.getId());
|
||||||
|
// 1f if extended, otherwise 0f
|
||||||
|
tagBuilder.floatTag("Progress", (extended) ? 1.0f : 0.0f);
|
||||||
|
// 1 if sticky, 0 if not
|
||||||
|
tagBuilder.byteTag("Sticky", (byte)((BlockStateValues.isStickyPiston(blockState)) ? 1 : 0));
|
||||||
|
}
|
||||||
|
return tagBuilder.buildRootTag();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -42,8 +42,12 @@ public class BlockEntityUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void updateBlockEntity(GeyserSession session, com.nukkitx.nbt.tag.CompoundTag blockEntity, Position position) {
|
public static void updateBlockEntity(GeyserSession session, com.nukkitx.nbt.tag.CompoundTag blockEntity, Position position) {
|
||||||
|
updateBlockEntity(session, blockEntity, Vector3i.from(position.getX(), position.getY(), position.getZ()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void updateBlockEntity(GeyserSession session, com.nukkitx.nbt.tag.CompoundTag blockEntity, Vector3i position) {
|
||||||
BlockEntityDataPacket blockEntityPacket = new BlockEntityDataPacket();
|
BlockEntityDataPacket blockEntityPacket = new BlockEntityDataPacket();
|
||||||
blockEntityPacket.setBlockPosition(Vector3i.from(position.getX(), position.getY(), position.getZ()));
|
blockEntityPacket.setBlockPosition(position);
|
||||||
blockEntityPacket.setData(blockEntity);
|
blockEntityPacket.setData(blockEntity);
|
||||||
session.getUpstream().sendPacket(blockEntityPacket);
|
session.getUpstream().sendPacket(blockEntityPacket);
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,11 +35,13 @@ import com.nukkitx.math.vector.Vector3i;
|
||||||
import com.nukkitx.protocol.bedrock.packet.*;
|
import com.nukkitx.protocol.bedrock.packet.*;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||||
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
import org.geysermc.connector.entity.Entity;
|
import org.geysermc.connector.entity.Entity;
|
||||||
import org.geysermc.connector.entity.ItemFrameEntity;
|
import org.geysermc.connector.entity.ItemFrameEntity;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
import org.geysermc.connector.network.translators.world.block.BlockStateValues;
|
||||||
import org.geysermc.connector.network.translators.world.block.entity.*;
|
import org.geysermc.connector.network.translators.world.block.entity.*;
|
||||||
import org.geysermc.connector.network.translators.Translators;
|
import org.geysermc.connector.network.translators.Translators;
|
||||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||||
|
@ -68,6 +70,9 @@ public class ChunkUtils {
|
||||||
// Temporarily stores positions of BlockState values per chunk load
|
// Temporarily stores positions of BlockState values per chunk load
|
||||||
Map<Position, BlockState> blockEntityPositions = new HashMap<>();
|
Map<Position, BlockState> blockEntityPositions = new HashMap<>();
|
||||||
|
|
||||||
|
// Temporarily stores compound tags of Bedrock-only block entities
|
||||||
|
ObjectArrayList<com.nukkitx.nbt.tag.CompoundTag> bedrockOnlyBlockEntities = new ObjectArrayList<>();
|
||||||
|
|
||||||
for (int chunkY = 0; chunkY < chunks.length; chunkY++) {
|
for (int chunkY = 0; chunkY < chunks.length; chunkY++) {
|
||||||
chunkData.sections[chunkY] = new ChunkSection();
|
chunkData.sections[chunkY] = new ChunkSection();
|
||||||
Chunk chunk = chunks[chunkY];
|
Chunk chunk = chunks[chunkY];
|
||||||
|
@ -99,6 +104,13 @@ public class ChunkUtils {
|
||||||
section.getBlockStorageArray()[0].setFullBlock(ChunkSection.blockPosition(x, y, z), id);
|
section.getBlockStorageArray()[0].setFullBlock(ChunkSection.blockPosition(x, y, z), id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if block is piston or flower - only block entities in Bedrock
|
||||||
|
if (BlockStateValues.getFlowerPotValues().containsKey(blockState.getId()) ||
|
||||||
|
BlockStateValues.getPistonValues().containsKey(blockState.getId())) {
|
||||||
|
Position pos = new ChunkPosition(column.getX(), column.getZ()).getBlock(x, (chunkY << 4) + y, z);
|
||||||
|
bedrockOnlyBlockEntities.add(BedrockOnlyBlockEntity.getTag(Vector3i.from(pos.getX(), pos.getY(), pos.getZ()), blockState));
|
||||||
|
}
|
||||||
|
|
||||||
if (BlockTranslator.isWaterlogged(blockState)) {
|
if (BlockTranslator.isWaterlogged(blockState)) {
|
||||||
section.getBlockStorageArray()[1].setFullBlock(ChunkSection.blockPosition(x, y, z), BEDROCK_WATER_ID);
|
section.getBlockStorageArray()[1].setFullBlock(ChunkSection.blockPosition(x, y, z), BEDROCK_WATER_ID);
|
||||||
}
|
}
|
||||||
|
@ -108,8 +120,9 @@ public class ChunkUtils {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
com.nukkitx.nbt.tag.CompoundTag[] bedrockBlockEntities = new com.nukkitx.nbt.tag.CompoundTag[blockEntities.length];
|
com.nukkitx.nbt.tag.CompoundTag[] bedrockBlockEntities = new com.nukkitx.nbt.tag.CompoundTag[blockEntities.length + bedrockOnlyBlockEntities.size()];
|
||||||
for (int i = 0; i < blockEntities.length; i++) {
|
int i = 0;
|
||||||
|
while (i < blockEntities.length) {
|
||||||
CompoundTag tag = blockEntities[i];
|
CompoundTag tag = blockEntities[i];
|
||||||
String tagName;
|
String tagName;
|
||||||
if (!tag.contains("id")) {
|
if (!tag.contains("id")) {
|
||||||
|
@ -121,8 +134,14 @@ public class ChunkUtils {
|
||||||
|
|
||||||
String id = BlockEntityUtils.getBedrockBlockEntityId(tagName);
|
String id = BlockEntityUtils.getBedrockBlockEntityId(tagName);
|
||||||
BlockEntityTranslator blockEntityTranslator = BlockEntityUtils.getBlockEntityTranslator(id);
|
BlockEntityTranslator blockEntityTranslator = BlockEntityUtils.getBlockEntityTranslator(id);
|
||||||
BlockState blockState = blockEntityPositions.get(new Position((int) tag.get("x").getValue(), (int) tag.get("y").getValue(), (int) tag.get("z").getValue()));
|
Position pos = new Position((int) tag.get("x").getValue(), (int) tag.get("y").getValue(), (int) tag.get("z").getValue());
|
||||||
|
BlockState blockState = blockEntityPositions.get(pos);
|
||||||
bedrockBlockEntities[i] = blockEntityTranslator.getBlockEntityTag(tagName, tag, blockState);
|
bedrockBlockEntities[i] = blockEntityTranslator.getBlockEntityTag(tagName, tag, blockState);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
for (com.nukkitx.nbt.tag.CompoundTag tag : bedrockOnlyBlockEntities) {
|
||||||
|
bedrockBlockEntities[i] = tag;
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
chunkData.blockEntities = bedrockBlockEntities;
|
chunkData.blockEntities = bedrockBlockEntities;
|
||||||
|
@ -186,6 +205,11 @@ public class ChunkUtils {
|
||||||
// Iterates through all block entity translators and determines if the block state needs to be saved
|
// Iterates through all block entity translators and determines if the block state needs to be saved
|
||||||
for (RequiresBlockState requiresBlockState : Translators.getRequiresBlockStateMap()) {
|
for (RequiresBlockState requiresBlockState : Translators.getRequiresBlockStateMap()) {
|
||||||
if (requiresBlockState.isBlock(blockState)) {
|
if (requiresBlockState.isBlock(blockState)) {
|
||||||
|
// Flower pots are block entities only in Bedrock and are not updated anywhere else like note blocks
|
||||||
|
if (requiresBlockState instanceof BedrockOnlyBlockEntity) {
|
||||||
|
((BedrockOnlyBlockEntity) requiresBlockState).updateBlock(session, blockState, position);
|
||||||
|
break;
|
||||||
|
}
|
||||||
CACHED_BLOCK_ENTITIES.put(new Position(position.getX(), position.getY(), position.getZ()), blockState);
|
CACHED_BLOCK_ENTITIES.put(new Position(position.getX(), position.getY(), position.getZ()), blockState);
|
||||||
break; //No block will be a part of two classes
|
break; //No block will be a part of two classes
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit ddb62693f878a99f106a0d6ea16a92ec7c4c7cd0
|
Subproject commit 5b3a9ad1d2ef76105fb318e63126a096844b3195
|
Loading…
Reference in a new issue