forked from GeyserMC/Geyser
Block entity rewrite (#382)
* Initial attempt * Rewrite of the rewrite * First working implementation * Far better working implementation * Clean up imports * Remove commented code * Cleanup code; change things * Remove unused imports * Cleanup code * Add licenses; add comment * More cleanup * Clarifications * It complained about a JavaDoc comment * Update access permissions * Switch from reflections to iteration over BlockEntityTranslators
This commit is contained in:
parent
3f8d5cc1c5
commit
94ecb2c6c7
17 changed files with 402 additions and 259 deletions
|
@ -116,11 +116,18 @@ public class Translators {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void registerBlockEntityTranslators() {
|
private static void registerBlockEntityTranslators() {
|
||||||
blockEntityTranslators.put("Empty", new EmptyBlockEntityTranslator());
|
Reflections ref = new Reflections("org.geysermc.connector.network.translators.block.entity");
|
||||||
blockEntityTranslators.put("Sign", new SignBlockEntityTranslator());
|
|
||||||
blockEntityTranslators.put("Campfire", new CampfireBlockEntityTranslator());
|
for (Class<?> clazz : ref.getTypesAnnotatedWith(BlockEntity.class)) {
|
||||||
blockEntityTranslators.put("Banner", new BannerBlockEntityTranslator());
|
|
||||||
blockEntityTranslators.put("EndGateway", new EndGatewayBlockEntityTranslator());
|
GeyserConnector.getInstance().getLogger().debug("Found annotated block entity: " + clazz.getCanonicalName());
|
||||||
|
|
||||||
|
try {
|
||||||
|
blockEntityTranslators.put(clazz.getAnnotation(BlockEntity.class).name(), (BlockEntityTranslator) clazz.newInstance());
|
||||||
|
} catch (InstantiationException | IllegalAccessException e) {
|
||||||
|
GeyserConnector.getInstance().getLogger().error("Could not instantiate annotated block entity " + clazz.getCanonicalName() + ".");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void registerInventoryTranslators() {
|
private static void registerInventoryTranslators() {
|
||||||
|
|
|
@ -0,0 +1,127 @@
|
||||||
|
/*
|
||||||
|
* 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.block;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2ByteMap;
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2ByteOpenHashMap;
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used for block entities if the Java block state contains Bedrock block information.
|
||||||
|
*/
|
||||||
|
public class BlockStateValues {
|
||||||
|
|
||||||
|
private static final Object2IntMap<BlockState> BANNER_COLORS = new Object2IntOpenHashMap<>();
|
||||||
|
private static final Object2ByteMap<BlockState> BED_COLORS = new Object2ByteOpenHashMap<>();
|
||||||
|
private static final Object2ByteMap<BlockState> SKULL_VARIANTS = new Object2ByteOpenHashMap<>();
|
||||||
|
private static final Object2ByteMap<BlockState> SKULL_ROTATIONS = new Object2ByteOpenHashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if the block state contains Bedrock block information
|
||||||
|
* @param entry The String -> JsonNode map used in BlockTranslator
|
||||||
|
* @param javaBlockState the Java Block State of the block
|
||||||
|
*/
|
||||||
|
public static void storeBlockStateValues(Map.Entry<String, JsonNode> entry, BlockState javaBlockState) {
|
||||||
|
JsonNode bannerColor = entry.getValue().get("banner_color");
|
||||||
|
if (bannerColor != null) {
|
||||||
|
BlockStateValues.BANNER_COLORS.put(javaBlockState, (byte) bannerColor.intValue());
|
||||||
|
return; // There will never be a banner color and a skull variant
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonNode bedColor = entry.getValue().get("bed_color");
|
||||||
|
if (bedColor != null) {
|
||||||
|
BlockStateValues.BED_COLORS.put(javaBlockState, (byte) bedColor.intValue());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonNode skullVariation = entry.getValue().get("variation");
|
||||||
|
if(skullVariation != null) {
|
||||||
|
BlockStateValues.SKULL_VARIANTS.put(javaBlockState, (byte) skullVariation.intValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonNode skullRotation = entry.getValue().get("skull_rotation");
|
||||||
|
if (skullRotation != null) {
|
||||||
|
BlockStateValues.SKULL_ROTATIONS.put(javaBlockState, (byte) skullRotation.intValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Banner colors are part of the namespaced ID in Java Edition, but part of the block entity tag in Bedrock.
|
||||||
|
* This gives an integer color that Bedrock can use.
|
||||||
|
* @param state BlockState of the block
|
||||||
|
* @return banner color integer or -1 if no color
|
||||||
|
*/
|
||||||
|
public static int getBannerColor(BlockState state) {
|
||||||
|
if (BANNER_COLORS.containsKey(state)) {
|
||||||
|
return BANNER_COLORS.getInt(state);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bed colors are part of the namespaced ID in Java Edition, but part of the block entity tag in Bedrock.
|
||||||
|
* This gives a byte color that Bedrock can use - Bedrock needs a byte in the final tag.
|
||||||
|
* @param state BlockState of the block
|
||||||
|
* @return bed color byte or -1 if no color
|
||||||
|
*/
|
||||||
|
public static byte getBedColor(BlockState state) {
|
||||||
|
if (BED_COLORS.containsKey(state)) {
|
||||||
|
return BED_COLORS.getByte(state);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
* @param state BlockState of the block
|
||||||
|
* @return skull variant byte or -1 if no variant
|
||||||
|
*/
|
||||||
|
public static byte getSkullVariant(BlockState state) {
|
||||||
|
if (SKULL_VARIANTS.containsKey(state)) {
|
||||||
|
return SKULL_VARIANTS.getByte(state);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param state BlockState of the block
|
||||||
|
* @return skull rotation value or -1 if no value
|
||||||
|
*/
|
||||||
|
public static byte getSkullRotation(BlockState state) {
|
||||||
|
if (SKULL_ROTATIONS.containsKey(state)) {
|
||||||
|
return SKULL_ROTATIONS.getByte(state);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -42,12 +42,12 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ByteMap;
|
|
||||||
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 org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
|
import org.geysermc.connector.network.translators.block.entity.BlockEntity;
|
||||||
import org.geysermc.connector.utils.Toolbox;
|
import org.geysermc.connector.utils.Toolbox;
|
||||||
|
import org.reflections.Reflections;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
@ -66,9 +66,6 @@ public class BlockTranslator {
|
||||||
public static final int CARPET = 171;
|
public static final int CARPET = 171;
|
||||||
|
|
||||||
private static final Map<BlockState, String> JAVA_ID_TO_BLOCK_ENTITY_MAP = new HashMap<>();
|
private static final Map<BlockState, String> JAVA_ID_TO_BLOCK_ENTITY_MAP = new HashMap<>();
|
||||||
private static final Object2ByteMap<BlockState> BED_COLORS = new Object2ByteOpenHashMap<>();
|
|
||||||
private static final Object2ByteMap<BlockState> SKULL_VARIANTS = new Object2ByteOpenHashMap<>();
|
|
||||||
private static final Object2ByteMap<BlockState> SKULL_ROTATIONS = new Object2ByteOpenHashMap<>();
|
|
||||||
|
|
||||||
public static final Int2DoubleMap JAVA_RUNTIME_ID_TO_HARDNESS = new Int2DoubleOpenHashMap();
|
public static final Int2DoubleMap JAVA_RUNTIME_ID_TO_HARDNESS = new Int2DoubleOpenHashMap();
|
||||||
public static final Int2BooleanMap JAVA_RUNTIME_ID_TO_CAN_HARVEST_WITH_HAND = new Int2BooleanOpenHashMap();
|
public static final Int2BooleanMap JAVA_RUNTIME_ID_TO_CAN_HARVEST_WITH_HAND = new Int2BooleanOpenHashMap();
|
||||||
|
@ -110,6 +107,9 @@ public class BlockTranslator {
|
||||||
addedStatesMap.defaultReturnValue(-1);
|
addedStatesMap.defaultReturnValue(-1);
|
||||||
List<CompoundTag> paletteList = new ArrayList<>();
|
List<CompoundTag> paletteList = new ArrayList<>();
|
||||||
|
|
||||||
|
Reflections ref = new Reflections("org.geysermc.connector.network.translators.block.entity");
|
||||||
|
ref.getTypesAnnotatedWith(BlockEntity.class);
|
||||||
|
|
||||||
int waterRuntimeId = -1;
|
int waterRuntimeId = -1;
|
||||||
int javaRuntimeId = -1;
|
int javaRuntimeId = -1;
|
||||||
int bedrockRuntimeId = 0;
|
int bedrockRuntimeId = 0;
|
||||||
|
@ -145,28 +145,19 @@ public class BlockTranslator {
|
||||||
|
|
||||||
JAVA_ID_BLOCK_MAP.put(javaId, javaBlockState);
|
JAVA_ID_BLOCK_MAP.put(javaId, javaBlockState);
|
||||||
|
|
||||||
if (javaId.contains("sign[")) {
|
// Used for adding all "special" Java block states to block state map
|
||||||
JAVA_ID_TO_BLOCK_ENTITY_MAP.put(javaBlockState, javaId);
|
String identifier;
|
||||||
|
String bedrock_identifer = entry.getValue().get("bedrock_identifier").asText();
|
||||||
|
for (Class<?> clazz : ref.getTypesAnnotatedWith(BlockEntity.class)) {
|
||||||
|
identifier = clazz.getAnnotation(BlockEntity.class).regex();
|
||||||
|
// Endswith, or else the block bedrock gets picked up for bed
|
||||||
|
if (bedrock_identifer.endsWith(identifier) && !identifier.equals("")) {
|
||||||
|
JAVA_ID_TO_BLOCK_ENTITY_MAP.put(javaBlockState, clazz.getAnnotation(BlockEntity.class).name());
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BlockStateValues.storeBlockStateValues(entry, javaBlockState);
|
||||||
JsonNode skullVariation = entry.getValue().get("variation");
|
|
||||||
if(skullVariation != null) {
|
|
||||||
SKULL_VARIANTS.put(javaBlockState, (byte) skullVariation.intValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
JsonNode skullRotation = entry.getValue().get("skull_rotation");
|
|
||||||
if (skullRotation != null) {
|
|
||||||
SKULL_ROTATIONS.put(javaBlockState, (byte) skullRotation.intValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the Java ID is bed, signal that it needs a tag to show color
|
|
||||||
// The color is in the namespace ID in Java Edition but it's a tag in Bedrock.
|
|
||||||
JsonNode bedColor = entry.getValue().get("bed_color");
|
|
||||||
if (bedColor != null) {
|
|
||||||
// Converting to byte because the final tag value is a byte. bedColor.binaryValue() returns an array
|
|
||||||
BED_COLORS.put(javaBlockState, (byte) bedColor.intValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
if ("minecraft:water[level=0]".equals(javaId)) {
|
if ("minecraft:water[level=0]".equals(javaId)) {
|
||||||
waterRuntimeId = bedrockRuntimeId;
|
waterRuntimeId = bedrockRuntimeId;
|
||||||
|
@ -186,7 +177,7 @@ public class BlockTranslator {
|
||||||
addedStatesMap.put(blockTag, bedrockRuntimeId);
|
addedStatesMap.put(blockTag, bedrockRuntimeId);
|
||||||
paletteList.add(runtimeTag);
|
paletteList.add(runtimeTag);
|
||||||
} else {
|
} else {
|
||||||
int duplicateRuntimeId = addedStatesMap.get(blockTag);
|
int duplicateRuntimeId = addedStatesMap.getOrDefault(blockTag, -1);
|
||||||
if (duplicateRuntimeId == -1) {
|
if (duplicateRuntimeId == -1) {
|
||||||
GeyserConnector.getInstance().getLogger().debug("Mapping " + javaId + " was not found for bedrock edition!");
|
GeyserConnector.getInstance().getLogger().debug("Mapping " + javaId + " was not found for bedrock edition!");
|
||||||
} else {
|
} else {
|
||||||
|
@ -274,27 +265,6 @@ public class BlockTranslator {
|
||||||
return WATERLOGGED.contains(state.getId());
|
return WATERLOGGED.contains(state.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte getBedColor(BlockState state) {
|
|
||||||
if (BED_COLORS.containsKey(state)) {
|
|
||||||
return BED_COLORS.getByte(state);
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static byte getSkullVariant(BlockState state) {
|
|
||||||
if (SKULL_VARIANTS.containsKey(state)) {
|
|
||||||
return SKULL_VARIANTS.getByte(state);
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static byte getSkullRotation(BlockState state) {
|
|
||||||
if (SKULL_ROTATIONS.containsKey(state)) {
|
|
||||||
return SKULL_ROTATIONS.getByte(state);
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BlockState getJavaWaterloggedState(int bedrockId) {
|
public static BlockState getJavaWaterloggedState(int bedrockId) {
|
||||||
return BEDROCK_TO_JAVA_BLOCK_MAP.get(1 << 31 | bedrockId);
|
return BEDROCK_TO_JAVA_BLOCK_MAP.get(1 << 31 | bedrockId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,20 +25,33 @@
|
||||||
|
|
||||||
package org.geysermc.connector.network.translators.block.entity;
|
package org.geysermc.connector.network.translators.block.entity;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
|
||||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||||
import com.github.steveice10.opennbt.tag.builtin.ListTag;
|
import com.github.steveice10.opennbt.tag.builtin.ListTag;
|
||||||
import com.nukkitx.nbt.CompoundTagBuilder;
|
import com.nukkitx.nbt.CompoundTagBuilder;
|
||||||
|
import com.nukkitx.nbt.tag.IntTag;
|
||||||
import com.nukkitx.nbt.tag.StringTag;
|
import com.nukkitx.nbt.tag.StringTag;
|
||||||
import com.nukkitx.nbt.tag.Tag;
|
import com.nukkitx.nbt.tag.Tag;
|
||||||
|
import org.geysermc.connector.network.translators.block.BlockStateValues;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class BannerBlockEntityTranslator extends BlockEntityTranslator {
|
@BlockEntity(name = "Banner", delay = false, regex = "banner")
|
||||||
|
public class BannerBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Tag<?>> translateTag(CompoundTag tag) {
|
public boolean isBlock(BlockState blockState) {
|
||||||
|
return BlockStateValues.getBannerColor(blockState) != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Tag<?>> translateTag(CompoundTag tag, BlockState blockState) {
|
||||||
List<Tag<?>> tags = new ArrayList<>();
|
List<Tag<?>> tags = new ArrayList<>();
|
||||||
|
int bannerColor = BlockStateValues.getBannerColor(blockState);
|
||||||
|
if (bannerColor != -1) {
|
||||||
|
tags.add(new IntTag("Base", 15 - bannerColor));
|
||||||
|
}
|
||||||
ListTag patterns = tag.get("Patterns");
|
ListTag patterns = tag.get("Patterns");
|
||||||
List<com.nukkitx.nbt.tag.CompoundTag> tagsList = new ArrayList<>();
|
List<com.nukkitx.nbt.tag.CompoundTag> tagsList = new ArrayList<>();
|
||||||
if (tag.contains("Patterns")) {
|
if (tag.contains("Patterns")) {
|
||||||
|
@ -71,7 +84,7 @@ public class BannerBlockEntityTranslator extends BlockEntityTranslator {
|
||||||
|
|
||||||
protected com.nukkitx.nbt.tag.CompoundTag getPattern(CompoundTag pattern) {
|
protected com.nukkitx.nbt.tag.CompoundTag getPattern(CompoundTag pattern) {
|
||||||
return CompoundTagBuilder.builder()
|
return CompoundTagBuilder.builder()
|
||||||
.intTag("Color", (int) pattern.get("Color").getValue())
|
.intTag("Color", 15 - (int) pattern.get("Color").getValue())
|
||||||
.stringTag("Pattern", (String) pattern.get("Pattern").getValue())
|
.stringTag("Pattern", (String) pattern.get("Pattern").getValue())
|
||||||
.buildRootTag();
|
.buildRootTag();
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,42 +25,43 @@
|
||||||
|
|
||||||
package org.geysermc.connector.network.translators.block.entity;
|
package org.geysermc.connector.network.translators.block.entity;
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
|
||||||
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.math.vector.Vector3i;
|
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||||
import com.nukkitx.nbt.CompoundTagBuilder;
|
import com.nukkitx.nbt.CompoundTagBuilder;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import com.nukkitx.nbt.tag.ByteTag;
|
||||||
import org.geysermc.connector.network.translators.block.BlockTranslator;
|
import com.nukkitx.nbt.tag.Tag;
|
||||||
import org.geysermc.connector.utils.BlockEntityUtils;
|
import org.geysermc.connector.network.translators.block.BlockStateValues;
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class BedBlockEntityTranslator {
|
@BlockEntity(name = "Bed", delay = false, regex = "bed")
|
||||||
|
public class BedBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState {
|
||||||
|
|
||||||
public static void checkForBedColor(GeyserSession session, BlockState blockState, Vector3i position) {
|
@Override
|
||||||
byte bedcolor = BlockTranslator.getBedColor(blockState);
|
public boolean isBlock(BlockState blockState) {
|
||||||
// If Bed Color is not -1 then it is indeed a bed with a color.
|
return BlockStateValues.getBedColor(blockState) != -1;
|
||||||
if (bedcolor > -1) {
|
|
||||||
Position pos = new Position(position.getX(), position.getY(), position.getZ());
|
|
||||||
com.nukkitx.nbt.tag.CompoundTag finalbedTag = getBedTag(bedcolor, pos);
|
|
||||||
// Delay needed, otherwise newly placed beds will not get their color
|
|
||||||
// Delay is not needed for beds already placed on login
|
|
||||||
session.getConnector().getGeneralThreadPool().schedule(() ->
|
|
||||||
BlockEntityUtils.updateBlockEntity(session, finalbedTag, pos),
|
|
||||||
500,
|
|
||||||
TimeUnit.MILLISECONDS
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static com.nukkitx.nbt.tag.CompoundTag getBedTag(byte bedcolor, Position pos) {
|
@Override
|
||||||
CompoundTagBuilder tagBuilder = CompoundTagBuilder.builder()
|
public List<Tag<?>> translateTag(CompoundTag tag, BlockState blockState) {
|
||||||
.intTag("x", pos.getX())
|
List<Tag<?>> tags = new ArrayList<>();
|
||||||
.intTag("y", pos.getY())
|
byte bedcolor = BlockStateValues.getBedColor(blockState);
|
||||||
.intTag("z", pos.getZ())
|
// Just in case...
|
||||||
.stringTag("id", "Bed");
|
if (bedcolor == -1) bedcolor = 0;
|
||||||
tagBuilder.byteTag("color", bedcolor);
|
tags.add(new ByteTag("color", bedcolor));
|
||||||
|
return tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompoundTag getDefaultJavaTag(String javaId, int x, int y, int z) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public com.nukkitx.nbt.tag.CompoundTag getDefaultBedrockTag(String bedrockId, int x, int y, int z) {
|
||||||
|
CompoundTagBuilder tagBuilder = getConstantBedrockTag(bedrockId, x, y, z).toBuilder();
|
||||||
|
tagBuilder.byteTag("color", (byte) 0);
|
||||||
return tagBuilder.buildRootTag();
|
return tagBuilder.buildRootTag();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* 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.block.entity;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
|
@Retention(value = RetentionPolicy.RUNTIME)
|
||||||
|
public @interface BlockEntity {
|
||||||
|
/**
|
||||||
|
* Whether to delay the sending of the block entity
|
||||||
|
*/
|
||||||
|
boolean delay();
|
||||||
|
/**
|
||||||
|
* The block entity name
|
||||||
|
*/
|
||||||
|
String name();
|
||||||
|
/**
|
||||||
|
* The search term used in BlockTranslator
|
||||||
|
*/
|
||||||
|
String regex();
|
||||||
|
}
|
|
@ -25,32 +25,32 @@
|
||||||
|
|
||||||
package org.geysermc.connector.network.translators.block.entity;
|
package org.geysermc.connector.network.translators.block.entity;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
|
||||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||||
import com.github.steveice10.opennbt.tag.builtin.IntTag;
|
import com.github.steveice10.opennbt.tag.builtin.IntTag;
|
||||||
import com.github.steveice10.opennbt.tag.builtin.StringTag;
|
import com.github.steveice10.opennbt.tag.builtin.StringTag;
|
||||||
import com.nukkitx.nbt.CompoundTagBuilder;
|
import com.nukkitx.nbt.CompoundTagBuilder;
|
||||||
import com.nukkitx.nbt.tag.Tag;
|
import com.nukkitx.nbt.tag.Tag;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import org.geysermc.connector.utils.BlockEntityUtils;
|
import org.geysermc.connector.utils.BlockEntityUtils;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public abstract class BlockEntityTranslator {
|
public abstract class BlockEntityTranslator {
|
||||||
|
|
||||||
public abstract List<Tag<?>> translateTag(CompoundTag tag);
|
public abstract List<Tag<?>> translateTag(CompoundTag tag, BlockState blockState);
|
||||||
|
|
||||||
public abstract CompoundTag getDefaultJavaTag(String javaId, int x, int y, int z);
|
public abstract CompoundTag getDefaultJavaTag(String javaId, int x, int y, int z);
|
||||||
|
|
||||||
public abstract com.nukkitx.nbt.tag.CompoundTag getDefaultBedrockTag(String bedrockId, int x, int y, int z);
|
public abstract com.nukkitx.nbt.tag.CompoundTag getDefaultBedrockTag(String bedrockId, int x, int y, int z);
|
||||||
|
|
||||||
public com.nukkitx.nbt.tag.CompoundTag getBlockEntityTag(String id, CompoundTag tag) {
|
public com.nukkitx.nbt.tag.CompoundTag getBlockEntityTag(String id, CompoundTag tag, BlockState blockState) {
|
||||||
int x = Integer.parseInt(String.valueOf(tag.getValue().get("x").getValue()));
|
int x = Integer.parseInt(String.valueOf(tag.getValue().get("x").getValue()));
|
||||||
int y = Integer.parseInt(String.valueOf(tag.getValue().get("y").getValue()));
|
int y = Integer.parseInt(String.valueOf(tag.getValue().get("y").getValue()));
|
||||||
int z = Integer.parseInt(String.valueOf(tag.getValue().get("z").getValue()));
|
int z = Integer.parseInt(String.valueOf(tag.getValue().get("z").getValue()));
|
||||||
|
|
||||||
CompoundTagBuilder tagBuilder = getConstantBedrockTag(BlockEntityUtils.getBedrockBlockEntityId(id), x, y, z).toBuilder();
|
CompoundTagBuilder tagBuilder = getConstantBedrockTag(BlockEntityUtils.getBedrockBlockEntityId(id), x, y, z).toBuilder();
|
||||||
translateTag(tag).forEach(tagBuilder::tag);
|
translateTag(tag, blockState).forEach(tagBuilder::tag);
|
||||||
return tagBuilder.buildRootTag();
|
return tagBuilder.buildRootTag();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
package org.geysermc.connector.network.translators.block.entity;
|
package org.geysermc.connector.network.translators.block.entity;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
|
||||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||||
import com.github.steveice10.opennbt.tag.builtin.ListTag;
|
import com.github.steveice10.opennbt.tag.builtin.ListTag;
|
||||||
import com.nukkitx.nbt.CompoundTagBuilder;
|
import com.nukkitx.nbt.CompoundTagBuilder;
|
||||||
|
@ -37,10 +38,11 @@ import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@BlockEntity(name = "Campfire", delay = false, regex = "campfire")
|
||||||
public class CampfireBlockEntityTranslator extends BlockEntityTranslator {
|
public class CampfireBlockEntityTranslator extends BlockEntityTranslator {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Tag<?>> translateTag(CompoundTag tag) {
|
public List<Tag<?>> translateTag(CompoundTag tag, BlockState blockState) {
|
||||||
List<Tag<?>> tags = new ArrayList<>();
|
List<Tag<?>> tags = new ArrayList<>();
|
||||||
ListTag items = tag.get("Items");
|
ListTag items = tag.get("Items");
|
||||||
int i = 1;
|
int i = 1;
|
||||||
|
|
|
@ -1,80 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.block.entity;
|
|
||||||
|
|
||||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
|
||||||
import com.github.steveice10.opennbt.tag.builtin.ListTag;
|
|
||||||
import com.nukkitx.nbt.CompoundTagBuilder;
|
|
||||||
import com.nukkitx.nbt.tag.Tag;
|
|
||||||
|
|
||||||
import org.geysermc.connector.network.translators.Translators;
|
|
||||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class ContainerBlockEntityTranslator extends BlockEntityTranslator {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<Tag<?>> translateTag(CompoundTag tag) {
|
|
||||||
List<Tag<?>> tags = new ArrayList<>();
|
|
||||||
ListTag items = tag.get("Items");
|
|
||||||
List<com.nukkitx.nbt.tag.CompoundTag> tagsList = new ArrayList<>();
|
|
||||||
for (com.github.steveice10.opennbt.tag.builtin.Tag itemTag : items.getValue()) {
|
|
||||||
tagsList.add(getItem((CompoundTag) itemTag));
|
|
||||||
}
|
|
||||||
|
|
||||||
com.nukkitx.nbt.tag.ListTag<com.nukkitx.nbt.tag.CompoundTag> bedrockItems =
|
|
||||||
new com.nukkitx.nbt.tag.ListTag<>("Items", com.nukkitx.nbt.tag.CompoundTag.class, tagsList);
|
|
||||||
tags.add(bedrockItems);
|
|
||||||
return tags;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CompoundTag getDefaultJavaTag(String javaId, int x, int y, int z) {
|
|
||||||
CompoundTag tag = getConstantJavaTag(javaId, x, y, z);
|
|
||||||
tag.put(new ListTag("Items"));
|
|
||||||
return tag;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public com.nukkitx.nbt.tag.CompoundTag getDefaultBedrockTag(String bedrockId, int x, int y, int z) {
|
|
||||||
CompoundTagBuilder tagBuilder = getConstantBedrockTag(bedrockId, x, y, z).toBuilder();
|
|
||||||
tagBuilder.listTag("Items", com.nukkitx.nbt.tag.CompoundTag.class, new ArrayList<>());
|
|
||||||
return tagBuilder.buildRootTag();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected com.nukkitx.nbt.tag.CompoundTag getItem(CompoundTag tag) {
|
|
||||||
ItemEntry entry = Translators.getItemTranslator().getItemEntry((String) tag.get("id").getValue());
|
|
||||||
CompoundTagBuilder tagBuilder = CompoundTagBuilder.builder()
|
|
||||||
.shortTag("id", (short) entry.getBedrockId())
|
|
||||||
.byteTag("Count", (byte) tag.get("Count").getValue())
|
|
||||||
.shortTag("Damage", (short) entry.getBedrockData())
|
|
||||||
.byteTag("Slot", (byte) tag.get("Slot").getValue())
|
|
||||||
.tag(CompoundTagBuilder.builder().build("tag"));
|
|
||||||
return tagBuilder.buildRootTag();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -25,16 +25,18 @@
|
||||||
|
|
||||||
package org.geysermc.connector.network.translators.block.entity;
|
package org.geysermc.connector.network.translators.block.entity;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
|
||||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||||
import com.nukkitx.nbt.tag.Tag;
|
import com.nukkitx.nbt.tag.Tag;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@BlockEntity(name = "Empty", delay = false, regex = "")
|
||||||
public class EmptyBlockEntityTranslator extends BlockEntityTranslator {
|
public class EmptyBlockEntityTranslator extends BlockEntityTranslator {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Tag<?>> translateTag(CompoundTag tag) {
|
public List<Tag<?>> translateTag(CompoundTag tag, BlockState blockState) {
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
package org.geysermc.connector.network.translators.block.entity;
|
package org.geysermc.connector.network.translators.block.entity;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
|
||||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||||
import com.github.steveice10.opennbt.tag.builtin.LongTag;
|
import com.github.steveice10.opennbt.tag.builtin.LongTag;
|
||||||
import com.nukkitx.nbt.CompoundTagBuilder;
|
import com.nukkitx.nbt.CompoundTagBuilder;
|
||||||
|
@ -35,9 +36,11 @@ import java.util.ArrayList;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@BlockEntity(name = "EndGateway", delay = true, regex = "end_gateway")
|
||||||
public class EndGatewayBlockEntityTranslator extends BlockEntityTranslator {
|
public class EndGatewayBlockEntityTranslator extends BlockEntityTranslator {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Tag<?>> translateTag(CompoundTag tag) {
|
public List<Tag<?>> translateTag(CompoundTag tag, BlockState blockState) {
|
||||||
List<Tag<?>> tags = new ArrayList<>();
|
List<Tag<?>> tags = new ArrayList<>();
|
||||||
tags.add(new IntTag("Age", (int) (long) tag.get("Age").getValue()));
|
tags.add(new IntTag("Age", (int) (long) tag.get("Age").getValue()));
|
||||||
// Java sometimes does not provide this tag, but Bedrock crashes if it doesn't exist
|
// Java sometimes does not provide this tag, but Bedrock crashes if it doesn't exist
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* 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.block.entity;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implemented in block entities if their Java block state is required for additional values in Bedrock
|
||||||
|
*/
|
||||||
|
public interface RequiresBlockState {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if block is part of class
|
||||||
|
* @param blockState BlockState to be compared
|
||||||
|
* @return true if part of the class
|
||||||
|
*/
|
||||||
|
boolean isBlock(BlockState blockState);
|
||||||
|
|
||||||
|
}
|
|
@ -25,21 +25,22 @@
|
||||||
|
|
||||||
package org.geysermc.connector.network.translators.block.entity;
|
package org.geysermc.connector.network.translators.block.entity;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
|
||||||
import com.github.steveice10.mc.protocol.data.message.Message;
|
import com.github.steveice10.mc.protocol.data.message.Message;
|
||||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||||
import com.nukkitx.nbt.CompoundTagBuilder;
|
import com.nukkitx.nbt.CompoundTagBuilder;
|
||||||
import com.nukkitx.nbt.tag.StringTag;
|
import com.nukkitx.nbt.tag.StringTag;
|
||||||
import com.nukkitx.nbt.tag.Tag;
|
import com.nukkitx.nbt.tag.Tag;
|
||||||
|
|
||||||
import org.geysermc.connector.utils.MessageUtils;
|
import org.geysermc.connector.utils.MessageUtils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@BlockEntity(name = "Sign", delay = true, regex = "sign")
|
||||||
public class SignBlockEntityTranslator extends BlockEntityTranslator {
|
public class SignBlockEntityTranslator extends BlockEntityTranslator {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Tag<?>> translateTag(CompoundTag tag) {
|
public List<Tag<?>> translateTag(CompoundTag tag, BlockState blockState) {
|
||||||
List<Tag<?>> tags = new ArrayList<>();
|
List<Tag<?>> tags = new ArrayList<>();
|
||||||
|
|
||||||
String line1 = getOrDefault(tag.getValue().get("Text1"), "");
|
String line1 = getOrDefault(tag.getValue().get("Text1"), "");
|
||||||
|
|
|
@ -25,43 +25,47 @@
|
||||||
|
|
||||||
package org.geysermc.connector.network.translators.block.entity;
|
package org.geysermc.connector.network.translators.block.entity;
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
|
||||||
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.math.vector.Vector3i;
|
|
||||||
import com.nukkitx.nbt.CompoundTagBuilder;
|
import com.nukkitx.nbt.CompoundTagBuilder;
|
||||||
|
import com.nukkitx.nbt.tag.ByteTag;
|
||||||
import com.nukkitx.nbt.tag.CompoundTag;
|
import com.nukkitx.nbt.tag.CompoundTag;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import com.nukkitx.nbt.tag.FloatTag;
|
||||||
import org.geysermc.connector.network.translators.block.BlockTranslator;
|
import com.nukkitx.nbt.tag.Tag;
|
||||||
import org.geysermc.connector.utils.BlockEntityUtils;
|
import org.geysermc.connector.network.translators.block.BlockStateValues;
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class SkullBlockEntityTranslator {
|
@BlockEntity(name = "Skull", delay = false, regex = "skull")
|
||||||
|
public class SkullBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState {
|
||||||
|
|
||||||
public static void checkForSkullVariant(GeyserSession session, BlockState blockState, Vector3i position) {
|
@Override
|
||||||
byte skullVariant = BlockTranslator.getSkullVariant(blockState);
|
public boolean isBlock(BlockState blockState) {
|
||||||
byte rotation = BlockTranslator.getSkullRotation(blockState);
|
return BlockStateValues.getSkullVariant(blockState) != -1;
|
||||||
if (skullVariant > -1) {
|
|
||||||
Position pos = new Position(position.getX(), position.getY(), position.getZ());
|
|
||||||
CompoundTag finalSkullTag = getSkullTag(skullVariant, pos, rotation);
|
|
||||||
// Delay needed, otherwise newly placed skulls will not appear
|
|
||||||
// Delay is not needed for skulls already placed on login
|
|
||||||
session.getConnector().getGeneralThreadPool().schedule(() ->
|
|
||||||
BlockEntityUtils.updateBlockEntity(session, finalSkullTag, pos),
|
|
||||||
500,
|
|
||||||
TimeUnit.MILLISECONDS
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CompoundTag getSkullTag(byte skullvariant, Position pos, byte rotation) {
|
@Override
|
||||||
CompoundTagBuilder tagBuilder = CompoundTagBuilder.builder()
|
public List<Tag<?>> translateTag(com.github.steveice10.opennbt.tag.builtin.CompoundTag tag, BlockState blockState) {
|
||||||
.intTag("x", pos.getX())
|
List<Tag<?>> tags = new ArrayList<>();
|
||||||
.intTag("y", pos.getY())
|
byte skullVariant = BlockStateValues.getSkullVariant(blockState);
|
||||||
.intTag("z", pos.getZ())
|
float rotation = BlockStateValues.getSkullRotation(blockState) * 22.5f;
|
||||||
.stringTag("id", "Skull")
|
// Just in case...
|
||||||
.floatTag("Rotation", rotation * 22.5f);
|
if (skullVariant == -1) skullVariant = 0;
|
||||||
tagBuilder.byteTag("SkullType", skullvariant);
|
tags.add(new FloatTag("Rotation", rotation));
|
||||||
|
tags.add(new ByteTag("SkullType", skullVariant));
|
||||||
|
return tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public com.github.steveice10.opennbt.tag.builtin.CompoundTag getDefaultJavaTag(String javaId, int x, int y, int z) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompoundTag getDefaultBedrockTag(String bedrockId, int x, int y, int z) {
|
||||||
|
CompoundTagBuilder tagBuilder = getConstantBedrockTag(bedrockId, x, y, z).toBuilder();
|
||||||
|
tagBuilder.floatTag("Rotation", 0);
|
||||||
|
tagBuilder.byteTag("SkullType", (byte) 0);
|
||||||
return tagBuilder.buildRootTag();
|
return tagBuilder.buildRootTag();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,7 +85,7 @@ public class JavaChunkDataTranslator extends PacketTranslator<ServerChunkDataPac
|
||||||
|
|
||||||
ByteBufOutputStream stream = new ByteBufOutputStream(Unpooled.buffer());
|
ByteBufOutputStream stream = new ByteBufOutputStream(Unpooled.buffer());
|
||||||
NBTOutputStream nbtStream = NbtUtils.createNetworkWriter(stream);
|
NBTOutputStream nbtStream = NbtUtils.createNetworkWriter(stream);
|
||||||
for (CompoundTag blockEntity : chunkData.blockEntities) {
|
for (CompoundTag blockEntity : chunkData.getBlockEntities()) {
|
||||||
nbtStream.write(blockEntity);
|
nbtStream.write(blockEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,31 +102,15 @@ public class JavaChunkDataTranslator extends PacketTranslator<ServerChunkDataPac
|
||||||
levelChunkPacket.setData(payload);
|
levelChunkPacket.setData(payload);
|
||||||
session.getUpstream().sendPacket(levelChunkPacket);
|
session.getUpstream().sendPacket(levelChunkPacket);
|
||||||
|
|
||||||
// Signs have to be sent after the chunk since in later versions they aren't included in the block entities
|
// Some block entities need to be loaded in later or else text doesn't show (signs) or they crash the game (end gateway blocks)
|
||||||
for (Object2IntMap.Entry<CompoundTag> blockEntityEntry : chunkData.signs.object2IntEntrySet()) {
|
for (Object2IntMap.Entry<CompoundTag> blockEntityEntry : chunkData.getLoadBlockEntitiesLater().object2IntEntrySet()) {
|
||||||
int x = blockEntityEntry.getKey().getInt("x");
|
int x = blockEntityEntry.getKey().getInt("x");
|
||||||
int y = blockEntityEntry.getKey().getInt("y");
|
int y = blockEntityEntry.getKey().getInt("y");
|
||||||
int z = blockEntityEntry.getKey().getInt("z");
|
int z = blockEntityEntry.getKey().getInt("z");
|
||||||
ChunkUtils.updateBlock(session, new BlockState(blockEntityEntry.getIntValue()), new Position(x, y, z));
|
ChunkUtils.updateBlock(session, new BlockState(blockEntityEntry.getIntValue()), new Position(x, y, z));
|
||||||
}
|
}
|
||||||
|
chunkData.getLoadBlockEntitiesLater().clear();
|
||||||
|
|
||||||
for (Object2IntMap.Entry<CompoundTag> blockEntityEntry : chunkData.gateways.object2IntEntrySet()) {
|
|
||||||
int x = blockEntityEntry.getKey().getInt("x");
|
|
||||||
int y = blockEntityEntry.getKey().getInt("y");
|
|
||||||
int z = blockEntityEntry.getKey().getInt("z");
|
|
||||||
ChunkUtils.updateBlock(session, new BlockState(blockEntityEntry.getIntValue()), new Position(x, y, z));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Map.Entry<Position, BlockState> blockEntityEntry: chunkData.beds.entrySet()) {
|
|
||||||
ChunkUtils.updateBlock(session, blockEntityEntry.getValue(), blockEntityEntry.getKey());
|
|
||||||
}
|
|
||||||
for (Map.Entry<Position, BlockState> blockEntityEntry: chunkData.skulls.entrySet()) {
|
|
||||||
ChunkUtils.updateBlock(session, blockEntityEntry.getValue(), blockEntityEntry.getKey());
|
|
||||||
}
|
|
||||||
chunkData.signs.clear();
|
|
||||||
chunkData.gateways.clear();
|
|
||||||
chunkData.beds.clear();
|
|
||||||
chunkData.skulls.clear();
|
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,27 +30,35 @@ import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerUpdate
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||||
import org.geysermc.connector.network.translators.Translator;
|
import org.geysermc.connector.network.translators.Translator;
|
||||||
|
import org.geysermc.connector.network.translators.block.entity.BlockEntity;
|
||||||
import org.geysermc.connector.network.translators.block.entity.BlockEntityTranslator;
|
import org.geysermc.connector.network.translators.block.entity.BlockEntityTranslator;
|
||||||
import org.geysermc.connector.utils.BlockEntityUtils;
|
import org.geysermc.connector.utils.BlockEntityUtils;
|
||||||
|
import org.geysermc.connector.utils.ChunkUtils;
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
@Translator(packet = ServerUpdateTileEntityPacket.class)
|
@Translator(packet = ServerUpdateTileEntityPacket.class)
|
||||||
public class JavaUpdateTileEntityTranslator extends PacketTranslator<ServerUpdateTileEntityPacket> {
|
public class JavaUpdateTileEntityTranslator extends PacketTranslator<ServerUpdateTileEntityPacket> {
|
||||||
|
|
||||||
|
// This should be modified if sign text is not showing up
|
||||||
|
private static final int DELAY = 500;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translate(ServerUpdateTileEntityPacket packet, GeyserSession session) {
|
public void translate(ServerUpdateTileEntityPacket packet, GeyserSession session) {
|
||||||
String id = BlockEntityUtils.getBedrockBlockEntityId(packet.getType().name());
|
String id = BlockEntityUtils.getBedrockBlockEntityId(packet.getType().name());
|
||||||
BlockEntityTranslator translator = BlockEntityUtils.getBlockEntityTranslator(id);
|
BlockEntityTranslator translator = BlockEntityUtils.getBlockEntityTranslator(id);
|
||||||
if (id.equalsIgnoreCase("Sign")) {
|
// If not null then the BlockState is used in BlockEntityTranslator.translateTag()
|
||||||
|
if (ChunkUtils.CACHED_BLOCK_ENTITIES.get(packet.getPosition()) != null) {
|
||||||
|
BlockEntityUtils.updateBlockEntity(session, translator.getBlockEntityTag(id, packet.getNbt(),
|
||||||
|
ChunkUtils.CACHED_BLOCK_ENTITIES.get(packet.getPosition())), packet.getPosition());
|
||||||
|
ChunkUtils.CACHED_BLOCK_ENTITIES.remove(packet.getPosition());
|
||||||
|
} else if (translator.getClass().getAnnotation(BlockEntity.class).delay()) {
|
||||||
// Delay so chunks can finish sending
|
// Delay so chunks can finish sending
|
||||||
session.getConnector().getGeneralThreadPool().schedule(() ->
|
session.getConnector().getGeneralThreadPool().schedule(() ->
|
||||||
BlockEntityUtils.updateBlockEntity(session, translator.getBlockEntityTag("Sign", packet.getNbt()), packet.getPosition()),
|
BlockEntityUtils.updateBlockEntity(session, translator.getBlockEntityTag(id, packet.getNbt(), null), packet.getPosition()),
|
||||||
5,
|
DELAY, TimeUnit.MILLISECONDS);
|
||||||
TimeUnit.SECONDS
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
BlockEntityUtils.updateBlockEntity(session, translator.getBlockEntityTag(id, packet.getNbt()), packet.getPosition());
|
BlockEntityUtils.updateBlockEntity(session, translator.getBlockEntityTag(id, packet.getNbt(), null), packet.getPosition());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,14 +39,13 @@ import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket;
|
||||||
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 lombok.Getter;
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.block.entity.BlockEntityTranslator;
|
import org.geysermc.connector.network.translators.block.entity.*;
|
||||||
import org.geysermc.connector.network.translators.block.entity.SkullBlockEntityTranslator;
|
|
||||||
import org.geysermc.connector.world.chunk.ChunkPosition;
|
|
||||||
import org.geysermc.connector.network.translators.Translators;
|
import org.geysermc.connector.network.translators.Translators;
|
||||||
import org.geysermc.connector.network.translators.block.BlockTranslator;
|
import org.geysermc.connector.network.translators.block.BlockTranslator;
|
||||||
import org.geysermc.connector.network.translators.block.entity.BedBlockEntityTranslator;
|
import org.geysermc.connector.world.chunk.ChunkPosition;
|
||||||
import org.geysermc.connector.world.chunk.ChunkSection;
|
import org.geysermc.connector.world.chunk.ChunkSection;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -56,12 +55,20 @@ import static org.geysermc.connector.network.translators.block.BlockTranslator.B
|
||||||
|
|
||||||
public class ChunkUtils {
|
public class ChunkUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Temporarily stores positions of BlockState values that are needed for certain block entities actively
|
||||||
|
*/
|
||||||
|
public static final Map<Position, BlockState> CACHED_BLOCK_ENTITIES = new HashMap<>();
|
||||||
|
|
||||||
public static ChunkData translateToBedrock(Column column) {
|
public static ChunkData translateToBedrock(Column column) {
|
||||||
ChunkData chunkData = new ChunkData();
|
ChunkData chunkData = new ChunkData();
|
||||||
Chunk[] chunks = column.getChunks();
|
Chunk[] chunks = column.getChunks();
|
||||||
chunkData.sections = new ChunkSection[chunks.length];
|
chunkData.sections = new ChunkSection[chunks.length];
|
||||||
|
|
||||||
CompoundTag[] blockEntities = column.getTileEntities();
|
CompoundTag[] blockEntities = column.getTileEntities();
|
||||||
|
// Temporarily stores positions of BlockState values per chunk load
|
||||||
|
Map<Position, BlockState> blockEntityPositions = new HashMap<>();
|
||||||
|
|
||||||
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];
|
||||||
|
@ -76,21 +83,19 @@ public class ChunkUtils {
|
||||||
BlockState blockState = chunk.get(x, y, z);
|
BlockState blockState = chunk.get(x, y, z);
|
||||||
int id = BlockTranslator.getBedrockBlockId(blockState);
|
int id = BlockTranslator.getBedrockBlockId(blockState);
|
||||||
|
|
||||||
if (BlockTranslator.getBlockEntityString(blockState) != null && BlockTranslator.getBlockEntityString(blockState).contains("sign[")) {
|
// Check to see if the name is in BlockTranslator.getBlockEntityString, and therefore must be handled differently
|
||||||
|
if (BlockTranslator.getBlockEntityString(blockState) != null) {
|
||||||
|
// Get the block entity translator
|
||||||
|
BlockEntityTranslator blockEntityTranslator = BlockEntityUtils.getBlockEntityTranslator(BlockTranslator.getBlockEntityString(blockState));
|
||||||
Position pos = new ChunkPosition(column.getX(), column.getZ()).getBlock(x, (chunkY << 4) + y, z);
|
Position pos = new ChunkPosition(column.getX(), column.getZ()).getBlock(x, (chunkY << 4) + y, z);
|
||||||
chunkData.signs.put(Translators.getBlockEntityTranslators().get("Sign").getDefaultBedrockTag("Sign", pos.getX(), pos.getY(), pos.getZ()), blockState.getId());
|
blockEntityPositions.put(pos, blockState);
|
||||||
} else if (BlockTranslator.getBlockEntityString(blockState) != null && BlockTranslator.getBlockEntityString(blockState).contains("end_gateway")) {
|
// If there is a delay required for the block, allow it.
|
||||||
Position pos = new ChunkPosition(column.getX(), column.getZ()).getBlock(x, (chunkY << 4) + y, z);
|
if (blockEntityTranslator.getClass().getAnnotation(BlockEntity.class).delay()) {
|
||||||
chunkData.gateways.put(Translators.getBlockEntityTranslators().get("EndGateway").getDefaultBedrockTag("EndGateway", pos.getX(), pos.getY(), pos.getZ()), blockState.getId());
|
chunkData.loadBlockEntitiesLater.put(blockEntityTranslator.getDefaultBedrockTag(BlockEntityUtils.getBedrockBlockEntityId(BlockTranslator.getBlockEntityString(blockState)),
|
||||||
} else if (BlockTranslator.getBedColor(blockState) > -1) {
|
pos.getX(), pos.getY(), pos.getZ()), blockState.getId());
|
||||||
Position pos = new ChunkPosition(column.getX(), column.getZ()).getBlock(x, (chunkY << 4) + y, z);
|
} else {
|
||||||
// Beds need to be updated separately to add the bed color tag
|
section.getBlockStorageArray()[0].setFullBlock(ChunkSection.blockPosition(x, y, z), id);
|
||||||
// Previously this was done by matching block state but this resulted in only one bed per color+orientation showing
|
}
|
||||||
chunkData.beds.put(pos, blockState);
|
|
||||||
} else if (BlockTranslator.getSkullVariant(blockState) > 0) {
|
|
||||||
Position pos = new ChunkPosition(column.getX(), column.getZ()).getBlock(x, (chunkY << 4) + y, z);
|
|
||||||
//Doing the same stuff as beds
|
|
||||||
chunkData.skulls.put(pos, blockState);
|
|
||||||
} else {
|
} else {
|
||||||
section.getBlockStorageArray()[0].setFullBlock(ChunkSection.blockPosition(x, y, z), id);
|
section.getBlockStorageArray()[0].setFullBlock(ChunkSection.blockPosition(x, y, z), id);
|
||||||
}
|
}
|
||||||
|
@ -101,6 +106,7 @@ 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];
|
||||||
|
@ -116,7 +122,8 @@ public class ChunkUtils {
|
||||||
|
|
||||||
String id = BlockEntityUtils.getBedrockBlockEntityId(tagName);
|
String id = BlockEntityUtils.getBedrockBlockEntityId(tagName);
|
||||||
BlockEntityTranslator blockEntityTranslator = BlockEntityUtils.getBlockEntityTranslator(id);
|
BlockEntityTranslator blockEntityTranslator = BlockEntityUtils.getBlockEntityTranslator(id);
|
||||||
bedrockBlockEntities[i] = blockEntityTranslator.getBlockEntityTag(tagName, tag);
|
BlockState blockState = blockEntityPositions.get(new Position((int) tag.get("x").getValue(), (int) tag.get("y").getValue(), (int) tag.get("z").getValue()));
|
||||||
|
bedrockBlockEntities[i] = blockEntityTranslator.getBlockEntityTag(tagName, tag, blockState);
|
||||||
}
|
}
|
||||||
|
|
||||||
chunkData.blockEntities = bedrockBlockEntities;
|
chunkData.blockEntities = bedrockBlockEntities;
|
||||||
|
@ -162,10 +169,18 @@ public class ChunkUtils {
|
||||||
}
|
}
|
||||||
session.getUpstream().sendPacket(waterPacket);
|
session.getUpstream().sendPacket(waterPacket);
|
||||||
|
|
||||||
// Since Java stores bed colors as part of the namespaced ID and Bedrock stores it as a tag
|
// Since Java stores bed colors/skull information as part of the namespaced ID and Bedrock stores it as a tag
|
||||||
// This is the only place I could find that interacts with the Java block state and block updates
|
// This is the only place I could find that interacts with the Java block state and block updates
|
||||||
BedBlockEntityTranslator.checkForBedColor(session, blockState, position);
|
// Iterates through all block entity translators and determines if the block state needs to be saved
|
||||||
SkullBlockEntityTranslator.checkForSkullVariant(session, blockState, position);
|
for (Map.Entry<String, BlockEntityTranslator> entry : Translators.getBlockEntityTranslators().entrySet()) {
|
||||||
|
if (entry.getValue() instanceof RequiresBlockState) {
|
||||||
|
RequiresBlockState requiresBlockState = (RequiresBlockState) entry.getValue();
|
||||||
|
if (requiresBlockState.isBlock(blockState)) {
|
||||||
|
CACHED_BLOCK_ENTITIES.put(new Position(position.getX(), position.getY(), position.getZ()), blockState);
|
||||||
|
break; //No block will be a part of two classes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void sendEmptyChunks(GeyserSession session, Vector3i position, int radius, boolean forceUpdate) {
|
public static void sendEmptyChunks(GeyserSession session, Vector3i position, int radius, boolean forceUpdate) {
|
||||||
|
@ -196,10 +211,9 @@ public class ChunkUtils {
|
||||||
public static final class ChunkData {
|
public static final class ChunkData {
|
||||||
public ChunkSection[] sections;
|
public ChunkSection[] sections;
|
||||||
|
|
||||||
public com.nukkitx.nbt.tag.CompoundTag[] blockEntities = new com.nukkitx.nbt.tag.CompoundTag[0];
|
@Getter
|
||||||
public Object2IntMap<com.nukkitx.nbt.tag.CompoundTag> signs = new Object2IntOpenHashMap<>();
|
private com.nukkitx.nbt.tag.CompoundTag[] blockEntities = new com.nukkitx.nbt.tag.CompoundTag[0];
|
||||||
public Object2IntMap<com.nukkitx.nbt.tag.CompoundTag> gateways = new Object2IntOpenHashMap<>();
|
@Getter
|
||||||
public Map<Position, BlockState> beds = new HashMap<>();
|
private Object2IntMap<com.nukkitx.nbt.tag.CompoundTag> loadBlockEntitiesLater = new Object2IntOpenHashMap<>();
|
||||||
public Map<Position, BlockState> skulls = new HashMap<>();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue