From 7710261b70d864429edcb887254f20be60ffc4ff Mon Sep 17 00:00:00 2001 From: rtm516 Date: Tue, 30 Jun 2020 00:52:32 +0100 Subject: [PATCH] Add Loadstone Compass tracking --- ...tionTrackingDBClientRequestTranslator.java | 82 ++++++++++++ .../translators/item/ItemRegistry.java | 3 + .../item/translators/CompassTranslator.java | 121 ++++++++++++++++++ .../connector/utils/LoadstoneTracker.java | 84 ++++++++++++ 4 files changed, 290 insertions(+) create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockPositionTrackingDBClientRequestTranslator.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/item/translators/CompassTranslator.java create mode 100644 connector/src/main/java/org/geysermc/connector/utils/LoadstoneTracker.java diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockPositionTrackingDBClientRequestTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockPositionTrackingDBClientRequestTranslator.java new file mode 100644 index 00000000..1ca46720 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockPositionTrackingDBClientRequestTranslator.java @@ -0,0 +1,82 @@ +/* + * 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.bedrock; + +import com.nukkitx.nbt.CompoundTagBuilder; +import com.nukkitx.nbt.tag.IntTag; +import com.nukkitx.protocol.bedrock.packet.PositionTrackingDBClientRequestPacket; +import com.nukkitx.protocol.bedrock.packet.PositionTrackingDBServerBroadcastPacket; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.PacketTranslator; +import org.geysermc.connector.network.translators.Translator; +import org.geysermc.connector.utils.DimensionUtils; +import org.geysermc.connector.utils.LoadstoneTracker; + +import java.util.ArrayList; +import java.util.List; + +@Translator(packet = PositionTrackingDBClientRequestPacket.class) +public class BedrockPositionTrackingDBClientRequestTranslator extends PacketTranslator { + + @Override + public void translate(PositionTrackingDBClientRequestPacket packet, GeyserSession session) { + PositionTrackingDBServerBroadcastPacket broadcastPacket = new PositionTrackingDBServerBroadcastPacket(); + broadcastPacket.setTrackingId(packet.getTrackingId()); + + // Fetch the stored Loadstone + LoadstoneTracker.LoadstonePos pos = LoadstoneTracker.getPos(packet.getTrackingId()); + + // If we don't have data for that ID tell the client its not found + if (pos == null) { + broadcastPacket.setAction(PositionTrackingDBServerBroadcastPacket.Action.NOT_FOUND); + session.sendUpstreamPacket(broadcastPacket); + return; + } + + broadcastPacket.setAction(PositionTrackingDBServerBroadcastPacket.Action.UPDATE); + + // Build the nbt data for the update + CompoundTagBuilder builder = CompoundTagBuilder.builder(); + builder.intTag("dim", DimensionUtils.javaToBedrock(pos.getDimension())); + builder.stringTag("id", String.format("%08X", packet.getTrackingId())); + + builder.byteTag("version", (byte) 1); // Not sure what this is for + builder.byteTag("status", (byte) 0); // Not sure what this is for + + // Build the position for the update + List posList = new ArrayList<>(); + posList.add(new IntTag("", pos.getX())); + posList.add(new IntTag("", pos.getY())); + posList.add(new IntTag("", pos.getZ())); + + builder.listTag("pos", IntTag.class, posList); + + broadcastPacket.setTag(builder.buildRootTag()); + + session.sendUpstreamPacket(broadcastPacket); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java index db5bc1b3..2dbc945c 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java @@ -133,6 +133,9 @@ public class ItemRegistry { itemIndex++; } + // Add the loadstonecompass since it doesn't exist on java but we need it for item conversion + ITEM_ENTRIES.put(itemIndex, new ItemEntry("minecraft:lodestonecompass", itemIndex, 741, 0, false)); + /* Load creative items */ stream = FileUtils.getResource("bedrock/creative_items.json"); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/CompassTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/CompassTranslator.java new file mode 100644 index 00000000..675d4255 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/CompassTranslator.java @@ -0,0 +1,121 @@ +/* + * 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.item.translators; + +import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.opennbt.tag.builtin.*; +import com.nukkitx.protocol.bedrock.data.inventory.ItemData; +import org.geysermc.connector.network.translators.ItemRemapper; +import org.geysermc.connector.network.translators.item.ItemEntry; +import org.geysermc.connector.network.translators.item.ItemRegistry; +import org.geysermc.connector.network.translators.item.ItemTranslator; +import org.geysermc.connector.utils.LoadstoneTracker; + +import java.util.List; +import java.util.stream.Collectors; + +@ItemRemapper +public class CompassTranslator extends ItemTranslator { + + private List appliedItems; + + public CompassTranslator() { + appliedItems = ItemRegistry.ITEM_ENTRIES.values().stream().filter(entry -> entry.getJavaIdentifier().endsWith("compass")).collect(Collectors.toList()); + } + + @Override + public ItemData translateToBedrock(ItemStack itemStack, ItemEntry itemEntry) { + if (itemStack.getNbt() == null) return super.translateToBedrock(itemStack, itemEntry); + + Tag lodestoneTag = itemStack.getNbt().get("LodestoneTracked"); + if (lodestoneTag instanceof ByteTag) { + // Get the fake lodestonecompass entry + itemEntry = ItemRegistry.getItemEntry("minecraft:lodestonecompass"); + + // Get the loadstone pos + CompoundTag loadstonePos = itemStack.getNbt().get("LodestonePos"); + if (loadstonePos != null) { + // Get all info needed for tracking + int x = ((IntTag) loadstonePos.get("X")).getValue(); + int y = ((IntTag) loadstonePos.get("Y")).getValue(); + int z = ((IntTag) loadstonePos.get("Z")).getValue(); + String dim = ((StringTag) itemStack.getNbt().get("LodestoneDimension")).getValue(); + + // Store the info + int trackID = LoadstoneTracker.store(x, y, z, dim); + + // Set the bedrock tracking id + itemStack.getNbt().put(new IntTag("trackingHandle", trackID)); + } else { + // The loadstone was removed just set the tracking id to 0 + itemStack.getNbt().put(new IntTag("trackingHandle", 0)); + } + } + + ItemData itemData = super.translateToBedrock(itemStack, itemEntry); + + return itemData; + } + + @Override + public ItemStack translateToJava(ItemData itemData, ItemEntry itemEntry) { + boolean isLoadstone = false; + if (itemEntry.getJavaIdentifier().equals("minecraft:lodestonecompass")) { + // Revert the entry back to the compass + itemEntry = ItemRegistry.getItemEntry("minecraft:compass"); + + isLoadstone = true; + } + + ItemStack itemStack = super.translateToJava(itemData, itemEntry); + + if (isLoadstone) { + // Get the tracking id + int trackingID = ((IntTag) itemStack.getNbt().get("trackingHandle")).getValue(); + + // Fetch the tracking info from the id + LoadstoneTracker.LoadstonePos pos = LoadstoneTracker.getPos(trackingID); + if (pos != null) { + // Build the new NBT data for the fetched tracking info + itemStack.getNbt().put(new StringTag("LodestoneDimension", pos.getDimension())); + + CompoundTag posTag = new CompoundTag("LodestonePos"); + posTag.put(new IntTag("X", pos.getX())); + posTag.put(new IntTag("Y", pos.getY())); + posTag.put(new IntTag("Z", pos.getZ())); + + itemStack.getNbt().put(posTag); + } + } + + return itemStack; + } + + @Override + public List getAppliedItems() { + return appliedItems; + } +} diff --git a/connector/src/main/java/org/geysermc/connector/utils/LoadstoneTracker.java b/connector/src/main/java/org/geysermc/connector/utils/LoadstoneTracker.java new file mode 100644 index 00000000..3bd54765 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/utils/LoadstoneTracker.java @@ -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.utils; + +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; + +public class LoadstoneTracker { + + private static final Int2ObjectMap LOADSTONES = new Int2ObjectOpenHashMap<>(); + + /** + * Store the given coordinates and dimensions + * + * @param x The X position of the Loadstone + * @param y The Y position of the Loadstone + * @param z The Z position of the Loadstone + * @param dim The dimension containing of the Loadstone + * @return The id in the Map + */ + public static int store(int x, int y, int z, String dim) { + LoadstonePos pos = new LoadstonePos(x, y, z, dim); + + if (!LOADSTONES.containsValue(pos)) { + // Start at 1 as 0 seems to not work + LOADSTONES.put(LOADSTONES.size() + 1, pos); + } + + for (Int2ObjectMap.Entry loadstone : LOADSTONES.int2ObjectEntrySet()) { + if (loadstone.getValue().equals(pos)) { + return loadstone.getIntKey(); + } + } + + return 0; + } + + /** + * Get the loadstone data + * + * @param id The ID to get the data for + * @return The stored data + */ + public static LoadstonePos getPos(int id) { + return LOADSTONES.get(id); + } + + @Getter + @AllArgsConstructor + @EqualsAndHashCode + public static class LoadstonePos { + int x; + int y; + int z; + String dimension; + } +} \ No newline at end of file