forked from GeyserMC/Geyser
Merge pull request #398 from GeyserMC/inventory
Merges branch 'inventory' into master
This commit is contained in:
commit
7ca1d1bea6
80 changed files with 4576 additions and 622 deletions
10
README.md
10
README.md
|
@ -28,12 +28,14 @@ Take a look [here](https://github.com/GeyserMC/Geyser/wiki#Setup) for how to set
|
|||
- Donate: https://patreon.com/GeyserMC
|
||||
|
||||
## What's Left to be Added/Fixed
|
||||
- Inventories ([`inventory`](https://github.com/GeyserMC/Geyser/tree/inventory))
|
||||
- Crafting ([`inventory`](https://github.com/GeyserMC/Geyser/tree/inventory))
|
||||
- Creative Mode ([`inventory`](https://github.com/GeyserMC/Geyser/tree/inventory))
|
||||
- The Following Inventories
|
||||
- [ ] Enchantment Table
|
||||
- [ ] Beacon
|
||||
- [ ] Cartography Table
|
||||
- [ ] Stonecutter
|
||||
- [ ] Villager Trading
|
||||
- Sounds
|
||||
- Block Particles
|
||||
- Block Entities ([`inventory`](https://github.com/GeyserMC/Geyser/tree/inventory))
|
||||
- Some Entity Flags
|
||||
|
||||
## Compiling
|
||||
|
|
|
@ -66,10 +66,34 @@
|
|||
<version>8.3.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.nukkitx.fastutil</groupId>
|
||||
<artifactId>fastutil-int-double-maps</artifactId>
|
||||
<version>8.3.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.nukkitx.fastutil</groupId>
|
||||
<artifactId>fastutil-int-boolean-maps</artifactId>
|
||||
<version>8.3.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.nukkitx.fastutil</groupId>
|
||||
<artifactId>fastutil-object-int-maps</artifactId>
|
||||
<version>8.3.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.nukkitx.fastutil</groupId>
|
||||
<artifactId>fastutil-object-byte-maps</artifactId>
|
||||
<version>8.3.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.steveice10</groupId>
|
||||
<artifactId>opennbt</artifactId>
|
||||
<version>1.3-SNAPSHOT</version>
|
||||
<version>1.4-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
|
|
@ -32,6 +32,7 @@ import com.nukkitx.protocol.bedrock.v390.Bedrock_v390;
|
|||
import lombok.Getter;
|
||||
|
||||
import org.geysermc.common.AuthType;
|
||||
import org.geysermc.common.IGeyserConfiguration;
|
||||
import org.geysermc.common.PlatformType;
|
||||
import org.geysermc.common.bootstrap.IGeyserBootstrap;
|
||||
import org.geysermc.common.logger.IGeyserLogger;
|
||||
|
@ -43,7 +44,6 @@ import org.geysermc.connector.network.session.GeyserSession;
|
|||
import org.geysermc.connector.network.translators.Translators;
|
||||
import org.geysermc.connector.thread.PingPassthroughThread;
|
||||
import org.geysermc.connector.utils.Toolbox;
|
||||
import org.geysermc.common.IGeyserConfiguration;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.text.DecimalFormat;
|
||||
|
|
|
@ -44,6 +44,7 @@ import org.geysermc.connector.entity.type.EntityType;
|
|||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.scoreboard.Team;
|
||||
import org.geysermc.connector.utils.MessageUtils;
|
||||
import org.geysermc.connector.network.session.cache.EntityEffectCache;
|
||||
import org.geysermc.connector.utils.SkinUtils;
|
||||
|
||||
import java.util.UUID;
|
||||
|
@ -55,6 +56,7 @@ public class PlayerEntity extends LivingEntity {
|
|||
private String username;
|
||||
private long lastSkinUpdate = -1;
|
||||
private boolean playerList = true;
|
||||
private final EntityEffectCache effectCache;
|
||||
|
||||
public PlayerEntity(GameProfile gameProfile, long entityId, long geyserId, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, EntityType.PLAYER, position, motion, rotation);
|
||||
|
@ -62,6 +64,7 @@ public class PlayerEntity extends LivingEntity {
|
|||
profile = gameProfile;
|
||||
uuid = gameProfile.getId();
|
||||
username = gameProfile.getName();
|
||||
effectCache = new EntityEffectCache();
|
||||
if (geyserId == 1) valid = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
package org.geysermc.connector.entity.living;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.MetadataType;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityFlag;
|
||||
|
|
|
@ -45,4 +45,4 @@ public class HorseEntity extends AbstractHorseEntity {
|
|||
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -27,9 +27,12 @@ package org.geysermc.connector.inventory;
|
|||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||
import com.github.steveice10.mc.protocol.data.game.window.WindowType;
|
||||
import com.nukkitx.math.vector.Vector3i;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class Inventory {
|
||||
|
||||
@Getter
|
||||
|
@ -43,16 +46,26 @@ public class Inventory {
|
|||
protected WindowType windowType;
|
||||
|
||||
@Getter
|
||||
protected int size;
|
||||
protected final int size;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
protected String title;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
protected ItemStack[] items;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
protected Vector3i holderPosition = Vector3i.ZERO;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
protected long holderId = -1;
|
||||
|
||||
@Getter
|
||||
protected AtomicInteger transactionId = new AtomicInteger(1);
|
||||
|
||||
public Inventory(int id, WindowType windowType, int size) {
|
||||
this("Inventory", id, windowType, size);
|
||||
}
|
||||
|
@ -62,11 +75,16 @@ public class Inventory {
|
|||
this.id = id;
|
||||
this.windowType = windowType;
|
||||
this.size = size;
|
||||
|
||||
this.items = new ItemStack[size];
|
||||
}
|
||||
|
||||
public ItemStack getItem(int slot) {
|
||||
return items[slot];
|
||||
}
|
||||
|
||||
public void setItem(int slot, ItemStack item) {
|
||||
if (item != null && (item.getId() == 0 || item.getAmount() < 1))
|
||||
item = null;
|
||||
items[slot] = item;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,13 +35,21 @@ public class PlayerInventory extends Inventory {
|
|||
@Setter
|
||||
private int heldItemSlot;
|
||||
|
||||
public PlayerInventory() {
|
||||
super(0, null, 45);
|
||||
@Getter
|
||||
private ItemStack cursor;
|
||||
|
||||
public PlayerInventory() {
|
||||
super(0, null, 46);
|
||||
heldItemSlot = 0;
|
||||
}
|
||||
|
||||
public void setCursor(ItemStack stack) {
|
||||
if (stack != null && (stack.getId() == 0 || stack.getAmount() < 1))
|
||||
stack = null;
|
||||
cursor = stack;
|
||||
}
|
||||
|
||||
public ItemStack getItemInHand() {
|
||||
return items[heldItemSlot];
|
||||
return items[36 + heldItemSlot];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,7 +44,13 @@ import com.nukkitx.math.vector.Vector3f;
|
|||
import com.nukkitx.math.vector.Vector3i;
|
||||
import com.nukkitx.nbt.tag.CompoundTag;
|
||||
import com.nukkitx.protocol.bedrock.BedrockServerSession;
|
||||
import com.nukkitx.protocol.bedrock.data.ContainerId;
|
||||
import com.nukkitx.protocol.bedrock.data.GamePublishSetting;
|
||||
import com.nukkitx.protocol.bedrock.packet.AvailableEntityIdentifiersPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.BiomeDefinitionListPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.PlayStatusPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.StartGamePacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.TextPacket;
|
||||
import com.nukkitx.protocol.bedrock.data.GameRuleData;
|
||||
import com.nukkitx.protocol.bedrock.data.PlayerPermission;
|
||||
import com.nukkitx.protocol.bedrock.packet.*;
|
||||
|
@ -125,6 +131,9 @@ public class GeyserSession implements CommandSender {
|
|||
private boolean manyDimPackets = false;
|
||||
private ServerRespawnPacket lastDimPacket = null;
|
||||
|
||||
@Setter
|
||||
private int craftSlot = 0;
|
||||
|
||||
public GeyserSession(GeyserConnector connector, BedrockServerSession bedrockServerSession) {
|
||||
this.connector = connector;
|
||||
this.upstream = new UpstreamSession(bedrockServerSession);
|
||||
|
@ -160,6 +169,11 @@ public class GeyserSession implements CommandSender {
|
|||
entityPacket.setTag(CompoundTag.EMPTY);
|
||||
upstream.sendPacket(entityPacket);
|
||||
|
||||
InventoryContentPacket creativePacket = new InventoryContentPacket();
|
||||
creativePacket.setContainerId(ContainerId.CREATIVE);
|
||||
creativePacket.setContents(Toolbox.CREATIVE_ITEMS);
|
||||
upstream.sendPacket(creativePacket);
|
||||
|
||||
PlayStatusPacket playStatusPacket = new PlayStatusPacket();
|
||||
playStatusPacket.setStatus(PlayStatusPacket.Status.PLAYER_SPAWN);
|
||||
upstream.sendPacket(playStatusPacket);
|
||||
|
|
54
connector/src/main/java/org/geysermc/connector/network/session/cache/EntityEffectCache.java
vendored
Normal file
54
connector/src/main/java/org/geysermc/connector/network/session/cache/EntityEffectCache.java
vendored
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* 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.session.cache;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.Effect;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||
import lombok.Getter;
|
||||
|
||||
public class EntityEffectCache {
|
||||
|
||||
@Getter
|
||||
private final Object2IntMap<Effect> entityEffects = new Object2IntOpenHashMap<>();
|
||||
|
||||
public void addEffect(Effect effect, int effectAmplifier) {
|
||||
if (effect != null) {
|
||||
entityEffects.putIfAbsent(effect, effectAmplifier + 1);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeEffect(Effect effect) {
|
||||
if (entityEffects.containsKey(effect)) {
|
||||
int effectLevel = entityEffects.getInt(effect);
|
||||
entityEffects.remove(effect, effectLevel);
|
||||
}
|
||||
}
|
||||
|
||||
public int getEffectLevel(Effect effect) {
|
||||
return entityEffects.getOrDefault(effect, 0);
|
||||
}
|
||||
}
|
|
@ -25,15 +25,12 @@
|
|||
|
||||
package org.geysermc.connector.network.session.cache;
|
||||
|
||||
import com.github.steveice10.packetlib.packet.Packet;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class InventoryCache {
|
||||
|
@ -47,9 +44,6 @@ public class InventoryCache {
|
|||
@Getter
|
||||
private Map<Integer, Inventory> inventories = new HashMap<Integer, Inventory>();
|
||||
|
||||
@Getter
|
||||
private Map<Integer, List<Packet>> cachedPackets = new HashMap<Integer, List<Packet>>();
|
||||
|
||||
public InventoryCache(GeyserSession session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
@ -65,10 +59,4 @@ public class InventoryCache {
|
|||
public void uncacheInventory(int id) {
|
||||
inventories.remove(id);
|
||||
}
|
||||
|
||||
public void cachePacket(int id, Packet packet) {
|
||||
List<Packet> packets = cachedPackets.getOrDefault(id, new ArrayList<Packet>());
|
||||
packets.add(packet);
|
||||
cachedPackets.put(id, packets);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,11 +27,17 @@ package org.geysermc.connector.network.translators;
|
|||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.window.WindowType;
|
||||
import com.nukkitx.protocol.bedrock.data.ContainerType;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.network.translators.block.BlockTranslator;
|
||||
import org.geysermc.connector.network.translators.inventory.GenericInventoryTranslator;
|
||||
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
||||
import org.geysermc.connector.network.translators.block.entity.*;
|
||||
import org.geysermc.connector.network.translators.inventory.*;
|
||||
import org.geysermc.connector.network.translators.inventory.updater.ContainerInventoryUpdater;
|
||||
import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
import org.reflections.Reflections;
|
||||
|
||||
|
@ -50,7 +56,10 @@ public class Translators {
|
|||
private static ItemTranslator itemTranslator;
|
||||
|
||||
@Getter
|
||||
private static InventoryTranslator inventoryTranslator = new GenericInventoryTranslator();
|
||||
private static Map<WindowType, InventoryTranslator> inventoryTranslators = new HashMap<>();
|
||||
|
||||
@Getter
|
||||
private static Map<String, BlockEntityTranslator> blockEntityTranslators = new HashMap<>();
|
||||
|
||||
private static final CompoundTag EMPTY_TAG = CompoundTagBuilder.builder().buildRootTag();
|
||||
public static final byte[] EMPTY_LEVEL_CHUNK_DATA;
|
||||
|
@ -82,15 +91,15 @@ public class Translators {
|
|||
if (Packet.class.isAssignableFrom(packet)) {
|
||||
Class<? extends Packet> targetPacket = (Class<? extends Packet>) packet;
|
||||
PacketTranslator<? extends Packet> translator = (PacketTranslator<? extends Packet>) clazz.newInstance();
|
||||
|
||||
|
||||
Registry.registerJava(targetPacket, translator);
|
||||
|
||||
|
||||
} else if (BedrockPacket.class.isAssignableFrom(packet)) {
|
||||
Class<? extends BedrockPacket> targetPacket = (Class<? extends BedrockPacket>) packet;
|
||||
PacketTranslator<? extends BedrockPacket> translator = (PacketTranslator<? extends BedrockPacket>) clazz.newInstance();
|
||||
|
||||
|
||||
Registry.registerBedrock(targetPacket, translator);
|
||||
|
||||
|
||||
} else {
|
||||
GeyserConnector.getInstance().getLogger().error("Class " + clazz.getCanonicalName() + " is annotated as a translator but has an invalid target packet.");
|
||||
}
|
||||
|
@ -102,15 +111,48 @@ public class Translators {
|
|||
itemTranslator = new ItemTranslator();
|
||||
BlockTranslator.init();
|
||||
|
||||
registerBlockEntityTranslators();
|
||||
registerInventoryTranslators();
|
||||
}
|
||||
|
||||
private static void registerBlockEntityTranslators() {
|
||||
Reflections ref = new Reflections("org.geysermc.connector.network.translators.block.entity");
|
||||
|
||||
for (Class<?> clazz : ref.getTypesAnnotatedWith(BlockEntity.class)) {
|
||||
|
||||
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() {
|
||||
/*inventoryTranslators.put(WindowType.GENERIC_9X1, new GenericInventoryTranslator());
|
||||
inventoryTranslators.put(WindowType.GENERIC_9X2, new GenericInventoryTranslator());
|
||||
inventoryTranslators.put(WindowType.GENERIC_9X3, new GenericInventoryTranslator());
|
||||
inventoryTranslators.put(WindowType.GENERIC_9X4, new GenericInventoryTranslator());
|
||||
inventoryTranslators.put(WindowType.GENERIC_9X5, new GenericInventoryTranslator());
|
||||
inventoryTranslators.put(WindowType.GENERIC_9X6, new GenericInventoryTranslator());*/
|
||||
inventoryTranslators.put(null, new PlayerInventoryTranslator()); //player inventory
|
||||
inventoryTranslators.put(WindowType.GENERIC_9X1, new SingleChestInventoryTranslator(9));
|
||||
inventoryTranslators.put(WindowType.GENERIC_9X2, new SingleChestInventoryTranslator(18));
|
||||
inventoryTranslators.put(WindowType.GENERIC_9X3, new SingleChestInventoryTranslator(27));
|
||||
inventoryTranslators.put(WindowType.GENERIC_9X4, new DoubleChestInventoryTranslator(36));
|
||||
inventoryTranslators.put(WindowType.GENERIC_9X5, new DoubleChestInventoryTranslator(45));
|
||||
inventoryTranslators.put(WindowType.GENERIC_9X6, new DoubleChestInventoryTranslator(54));
|
||||
inventoryTranslators.put(WindowType.BREWING_STAND, new BrewingInventoryTranslator());
|
||||
inventoryTranslators.put(WindowType.ANVIL, new AnvilInventoryTranslator());
|
||||
inventoryTranslators.put(WindowType.CRAFTING, new CraftingInventoryTranslator());
|
||||
inventoryTranslators.put(WindowType.GRINDSTONE, new GrindstoneInventoryTranslator());
|
||||
//inventoryTranslators.put(WindowType.ENCHANTMENT, new EnchantmentInventoryTranslator()); //TODO
|
||||
|
||||
InventoryTranslator furnace = new FurnaceInventoryTranslator();
|
||||
inventoryTranslators.put(WindowType.FURNACE, furnace);
|
||||
inventoryTranslators.put(WindowType.BLAST_FURNACE, furnace);
|
||||
inventoryTranslators.put(WindowType.SMOKER, furnace);
|
||||
|
||||
InventoryUpdater containerUpdater = new ContainerInventoryUpdater();
|
||||
inventoryTranslators.put(WindowType.GENERIC_3X3, new BlockInventoryTranslator(9, "minecraft:dispenser[facing=north,triggered=false]", ContainerType.DISPENSER, containerUpdater));
|
||||
inventoryTranslators.put(WindowType.HOPPER, new BlockInventoryTranslator(5, "minecraft:hopper[enabled=false,facing=down]", ContainerType.HOPPER, containerUpdater));
|
||||
inventoryTranslators.put(WindowType.SHULKER_BOX, new BlockInventoryTranslator(27, "minecraft:shulker_box[facing=north]", ContainerType.CONTAINER, containerUpdater));
|
||||
//inventoryTranslators.put(WindowType.BEACON, new BlockInventoryTranslator(1, "minecraft:beacon", ContainerType.BEACON)); //TODO
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* 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.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientUpdateSignPacket;
|
||||
import com.nukkitx.nbt.tag.CompoundTag;
|
||||
import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Translator(packet = BlockEntityDataPacket.class)
|
||||
public class BedrockBlockEntityDataTranslator extends PacketTranslator<BlockEntityDataPacket> {
|
||||
|
||||
// In case two people are editing signs at the same time this array holds the temporary messages to be sent
|
||||
// Position -> Message being held
|
||||
protected static Map<Position, String> lastMessages = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void translate(BlockEntityDataPacket packet, GeyserSession session) {
|
||||
if (packet.getData() instanceof CompoundTag) {
|
||||
CompoundTag tag = (CompoundTag) packet.getData();
|
||||
if (tag.getString("id").equals("Sign")) {
|
||||
// This is the reason why this all works - Bedrock sends packets every time you update the sign, Java only wants the final packet
|
||||
// But Bedrock sends one final packet when you're done editing the sign, which should be equal to the last message since there's no edits
|
||||
// So if the latest update does not match the last cached update then it's still being edited
|
||||
Position pos = new Position(tag.getInt("x"), tag.getInt("y"), tag.getInt("z"));
|
||||
if (!tag.getString("Text").equals(lastMessages.get(pos))) {
|
||||
lastMessages.put(pos, tag.getString("Text"));
|
||||
return;
|
||||
}
|
||||
// Otherwise the two messages are identical and we can get to work deconstructing
|
||||
StringBuilder newMessage = new StringBuilder();
|
||||
// While Bedrock's sign lines are one string, Java's is an array of each line
|
||||
// (Initialized all with empty strings because it complains about null)
|
||||
String[] lines = new String[] {"", "", "", ""};
|
||||
int iterator = 0;
|
||||
// This converts the message into the array'd message Java wants
|
||||
for (char character : tag.getString("Text").toCharArray()) {
|
||||
// If we get a return in Bedrock, that signals to use the next line.
|
||||
if (character == '\n') {
|
||||
lines[iterator] = newMessage.toString();
|
||||
iterator++;
|
||||
// Bedrock, for whatever reason, can hold a message out of bounds
|
||||
// We don't care about that so we discard that
|
||||
if (iterator > lines.length - 1) {
|
||||
break;
|
||||
}
|
||||
newMessage = new StringBuilder();
|
||||
} else newMessage.append(character);
|
||||
}
|
||||
// Put the final line on since it isn't done in the for loop
|
||||
if (iterator < lines.length) lines[iterator] = newMessage.toString();
|
||||
ClientUpdateSignPacket clientUpdateSignPacket = new ClientUpdateSignPacket(pos, lines);
|
||||
session.getDownstream().getSession().send(clientUpdateSignPacket);
|
||||
//TODO (potentially): originally I was going to update the sign blocks so Bedrock and Java users would match visually
|
||||
// However Java can still store a lot per-line and visuals are still messed up so that doesn't work
|
||||
|
||||
// We remove the sign position from map to indicate there is no work-in-progress sign
|
||||
lastMessages.remove(pos);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* 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.github.steveice10.mc.protocol.packet.ingame.client.window.ClientCloseWindowPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.ContainerClosePacket;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
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.InventoryUtils;
|
||||
|
||||
@Translator(packet = ContainerClosePacket.class)
|
||||
public class BedrockContainerCloseTranslator extends PacketTranslator<ContainerClosePacket> {
|
||||
|
||||
@Override
|
||||
public void translate(ContainerClosePacket packet, GeyserSession session) {
|
||||
byte windowId = packet.getWindowId();
|
||||
if (windowId == -1) { //player inventory or crafting table
|
||||
Inventory openInventory = session.getInventoryCache().getOpenInventory();
|
||||
if (openInventory != null) {
|
||||
windowId = (byte) openInventory.getId();
|
||||
} else {
|
||||
windowId = 0;
|
||||
}
|
||||
}
|
||||
ClientCloseWindowPacket closeWindowPacket = new ClientCloseWindowPacket(windowId);
|
||||
session.getDownstream().getSession().send(closeWindowPacket);
|
||||
InventoryUtils.closeInventory(session, windowId);
|
||||
}
|
||||
}
|
|
@ -27,10 +27,14 @@ package org.geysermc.connector.network.translators.bedrock;
|
|||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerPlaceBlockPacket;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
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.network.translators.Translators;
|
||||
import org.geysermc.connector.utils.InventoryUtils;
|
||||
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
|
||||
|
@ -40,7 +44,6 @@ import com.github.steveice10.mc.protocol.data.game.world.block.BlockFace;
|
|||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerActionPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerInteractEntityPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerUseItemPacket;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.packet.InventoryTransactionPacket;
|
||||
|
||||
@Translator(packet = InventoryTransactionPacket.class)
|
||||
|
@ -49,6 +52,17 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||
@Override
|
||||
public void translate(InventoryTransactionPacket packet, GeyserSession session) {
|
||||
switch (packet.getTransactionType()) {
|
||||
case NORMAL:
|
||||
Inventory inventory = session.getInventoryCache().getOpenInventory();
|
||||
if (inventory == null) inventory = session.getInventory();
|
||||
Translators.getInventoryTranslators().get(inventory.getWindowType()).translateActions(session, inventory, packet.getActions());
|
||||
break;
|
||||
case INVENTORY_MISMATCH:
|
||||
Inventory inv = session.getInventoryCache().getOpenInventory();
|
||||
if (inv == null) inv = session.getInventory();
|
||||
Translators.getInventoryTranslators().get(inv.getWindowType()).updateInventory(session, inv);
|
||||
InventoryUtils.updateCursor(session);
|
||||
break;
|
||||
case ITEM_USE:
|
||||
switch (packet.getActionType()) {
|
||||
case 0:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -32,6 +32,10 @@ import com.nukkitx.nbt.NbtUtils;
|
|||
import com.nukkitx.nbt.stream.NBTInputStream;
|
||||
import com.nukkitx.nbt.tag.CompoundTag;
|
||||
import com.nukkitx.nbt.tag.ListTag;
|
||||
import it.unimi.dsi.fastutil.ints.Int2BooleanMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2BooleanOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2DoubleMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2DoubleOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
|
@ -41,7 +45,9 @@ import it.unimi.dsi.fastutil.ints.IntSet;
|
|||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.network.translators.block.entity.BlockEntity;
|
||||
import org.geysermc.connector.utils.Toolbox;
|
||||
import org.reflections.Reflections;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.*;
|
||||
|
@ -53,11 +59,22 @@ public class BlockTranslator {
|
|||
|
||||
private static final Int2IntMap JAVA_TO_BEDROCK_BLOCK_MAP = new Int2IntOpenHashMap();
|
||||
private static final Int2ObjectMap<BlockState> BEDROCK_TO_JAVA_BLOCK_MAP = new Int2ObjectOpenHashMap<>();
|
||||
private static final Map<String, BlockState> JAVA_ID_BLOCK_MAP = new HashMap<>();
|
||||
private static final IntSet WATERLOGGED = new IntOpenHashSet();
|
||||
|
||||
// Bedrock carpet ID, used in LlamaEntity.java for decoration
|
||||
public static final int CARPET = 171;
|
||||
|
||||
private static final Map<BlockState, String> JAVA_ID_TO_BLOCK_ENTITY_MAP = new HashMap<>();
|
||||
|
||||
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 Int2ObjectMap<String> JAVA_RUNTIME_ID_TO_TOOL_TYPE = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
// For block breaking animation math
|
||||
public static final IntSet JAVA_RUNTIME_WOOL_IDS = new IntOpenHashSet();
|
||||
public static final int JAVA_RUNTIME_COBWEB_ID;
|
||||
|
||||
private static final int BLOCK_STATE_VERSION = 17760256;
|
||||
|
||||
static {
|
||||
|
@ -90,16 +107,58 @@ public class BlockTranslator {
|
|||
addedStatesMap.defaultReturnValue(-1);
|
||||
List<CompoundTag> paletteList = new ArrayList<>();
|
||||
|
||||
Reflections ref = new Reflections("org.geysermc.connector.network.translators.block.entity");
|
||||
ref.getTypesAnnotatedWith(BlockEntity.class);
|
||||
|
||||
int waterRuntimeId = -1;
|
||||
int javaRuntimeId = -1;
|
||||
int bedrockRuntimeId = 0;
|
||||
int cobwebRuntimeId = -1;
|
||||
Iterator<Map.Entry<String, JsonNode>> blocksIterator = blocks.fields();
|
||||
while (blocksIterator.hasNext()) {
|
||||
javaRuntimeId++;
|
||||
Map.Entry<String, JsonNode> entry = blocksIterator.next();
|
||||
String javaId = entry.getKey();
|
||||
BlockState javaBlockState = new BlockState(javaRuntimeId);
|
||||
CompoundTag blockTag = buildBedrockState(entry.getValue());
|
||||
|
||||
// TODO fix this, (no block should have a null hardness)
|
||||
JsonNode hardnessNode = entry.getValue().get("block_hardness");
|
||||
if (hardnessNode != null) {
|
||||
JAVA_RUNTIME_ID_TO_HARDNESS.put(javaRuntimeId, hardnessNode.doubleValue());
|
||||
}
|
||||
|
||||
JAVA_RUNTIME_ID_TO_CAN_HARVEST_WITH_HAND.put(javaRuntimeId, entry.getValue().get("can_break_with_hand").booleanValue());
|
||||
|
||||
JsonNode toolTypeNode = entry.getValue().get("tool_type");
|
||||
if (toolTypeNode != null) {
|
||||
JAVA_RUNTIME_ID_TO_TOOL_TYPE.put(javaRuntimeId, toolTypeNode.textValue());
|
||||
}
|
||||
|
||||
if (javaId.contains("wool")) {
|
||||
JAVA_RUNTIME_WOOL_IDS.add(javaRuntimeId);
|
||||
}
|
||||
|
||||
if (javaId.contains("cobweb")) {
|
||||
cobwebRuntimeId = javaRuntimeId;
|
||||
}
|
||||
|
||||
JAVA_ID_BLOCK_MAP.put(javaId, javaBlockState);
|
||||
|
||||
// Used for adding all "special" Java block states to block state map
|
||||
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);
|
||||
|
||||
if ("minecraft:water[level=0]".equals(javaId)) {
|
||||
waterRuntimeId = bedrockRuntimeId;
|
||||
}
|
||||
|
@ -107,10 +166,10 @@ public class BlockTranslator {
|
|||
|| javaId.contains("minecraft:bubble_column") || javaId.contains("minecraft:kelp") || javaId.contains("seagrass");
|
||||
|
||||
if (waterlogged) {
|
||||
BEDROCK_TO_JAVA_BLOCK_MAP.putIfAbsent(bedrockRuntimeId | 1 << 31, new BlockState(javaRuntimeId));
|
||||
BEDROCK_TO_JAVA_BLOCK_MAP.putIfAbsent(bedrockRuntimeId | 1 << 31, javaBlockState);
|
||||
WATERLOGGED.add(javaRuntimeId);
|
||||
} else {
|
||||
BEDROCK_TO_JAVA_BLOCK_MAP.putIfAbsent(bedrockRuntimeId, new BlockState(javaRuntimeId));
|
||||
BEDROCK_TO_JAVA_BLOCK_MAP.putIfAbsent(bedrockRuntimeId, javaBlockState);
|
||||
}
|
||||
|
||||
CompoundTag runtimeTag = blockStateMap.remove(blockTag);
|
||||
|
@ -118,7 +177,7 @@ public class BlockTranslator {
|
|||
addedStatesMap.put(blockTag, bedrockRuntimeId);
|
||||
paletteList.add(runtimeTag);
|
||||
} else {
|
||||
int duplicateRuntimeId = addedStatesMap.get(blockTag);
|
||||
int duplicateRuntimeId = addedStatesMap.getOrDefault(blockTag, -1);
|
||||
if (duplicateRuntimeId == -1) {
|
||||
GeyserConnector.getInstance().getLogger().debug("Mapping " + javaId + " was not found for bedrock edition!");
|
||||
} else {
|
||||
|
@ -131,6 +190,11 @@ public class BlockTranslator {
|
|||
bedrockRuntimeId++;
|
||||
}
|
||||
|
||||
if (cobwebRuntimeId == -1) {
|
||||
throw new AssertionError("Unable to find cobwebs in palette");
|
||||
}
|
||||
JAVA_RUNTIME_COBWEB_ID = cobwebRuntimeId;
|
||||
|
||||
if (waterRuntimeId == -1) {
|
||||
throw new AssertionError("Unable to find water in palette");
|
||||
}
|
||||
|
@ -189,6 +253,14 @@ public class BlockTranslator {
|
|||
return BEDROCK_TO_JAVA_BLOCK_MAP.get(bedrockId);
|
||||
}
|
||||
|
||||
public static BlockState getJavaBlockState(String javaId) {
|
||||
return JAVA_ID_BLOCK_MAP.get(javaId);
|
||||
}
|
||||
|
||||
public static String getBlockEntityString(BlockState javaId) {
|
||||
return JAVA_ID_TO_BLOCK_ENTITY_MAP.get(javaId);
|
||||
}
|
||||
|
||||
public static boolean isWaterlogged(BlockState state) {
|
||||
return WATERLOGGED.contains(state.getId());
|
||||
}
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* 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;
|
||||
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.IntTag;
|
||||
import com.nukkitx.nbt.tag.StringTag;
|
||||
import com.nukkitx.nbt.tag.Tag;
|
||||
import org.geysermc.connector.network.translators.block.BlockStateValues;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@BlockEntity(name = "Banner", delay = false, regex = "banner")
|
||||
public class BannerBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState {
|
||||
|
||||
@Override
|
||||
public boolean isBlock(BlockState blockState) {
|
||||
return BlockStateValues.getBannerColor(blockState) != -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Tag<?>> translateTag(CompoundTag tag, BlockState blockState) {
|
||||
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");
|
||||
List<com.nukkitx.nbt.tag.CompoundTag> tagsList = new ArrayList<>();
|
||||
if (tag.contains("Patterns")) {
|
||||
for (com.github.steveice10.opennbt.tag.builtin.Tag patternTag : patterns.getValue()) {
|
||||
tagsList.add(getPattern((CompoundTag) patternTag));
|
||||
}
|
||||
com.nukkitx.nbt.tag.ListTag<com.nukkitx.nbt.tag.CompoundTag> bedrockPatterns =
|
||||
new com.nukkitx.nbt.tag.ListTag<>("Patterns", com.nukkitx.nbt.tag.CompoundTag.class, tagsList);
|
||||
tags.add(bedrockPatterns);
|
||||
}
|
||||
if (tag.contains("CustomName")) {
|
||||
tags.add(new StringTag("CustomName", (String) tag.get("CustomName").getValue()));
|
||||
}
|
||||
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("Patterns"));
|
||||
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("Patterns", com.nukkitx.nbt.tag.CompoundTag.class, new ArrayList<>());
|
||||
return tagBuilder.buildRootTag();
|
||||
}
|
||||
|
||||
protected com.nukkitx.nbt.tag.CompoundTag getPattern(CompoundTag pattern) {
|
||||
return CompoundTagBuilder.builder()
|
||||
.intTag("Color", 15 - (int) pattern.get("Color").getValue())
|
||||
.stringTag("Pattern", (String) pattern.get("Pattern").getValue())
|
||||
.buildRootTag();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* 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;
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.nukkitx.nbt.CompoundTagBuilder;
|
||||
import com.nukkitx.nbt.tag.ByteTag;
|
||||
import com.nukkitx.nbt.tag.Tag;
|
||||
import org.geysermc.connector.network.translators.block.BlockStateValues;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@BlockEntity(name = "Bed", delay = false, regex = "bed")
|
||||
public class BedBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState {
|
||||
|
||||
@Override
|
||||
public boolean isBlock(BlockState blockState) {
|
||||
return BlockStateValues.getBedColor(blockState) != -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Tag<?>> translateTag(CompoundTag tag, BlockState blockState) {
|
||||
List<Tag<?>> tags = new ArrayList<>();
|
||||
byte bedcolor = BlockStateValues.getBedColor(blockState);
|
||||
// Just in case...
|
||||
if (bedcolor == -1) bedcolor = 0;
|
||||
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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* 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;
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.IntTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.StringTag;
|
||||
import com.nukkitx.nbt.CompoundTagBuilder;
|
||||
import com.nukkitx.nbt.tag.Tag;
|
||||
|
||||
import org.geysermc.connector.utils.BlockEntityUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public abstract class BlockEntityTranslator {
|
||||
|
||||
public abstract List<Tag<?>> translateTag(CompoundTag tag, BlockState blockState);
|
||||
|
||||
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 com.nukkitx.nbt.tag.CompoundTag getBlockEntityTag(String id, CompoundTag tag, BlockState blockState) {
|
||||
int x = Integer.parseInt(String.valueOf(tag.getValue().get("x").getValue()));
|
||||
int y = Integer.parseInt(String.valueOf(tag.getValue().get("y").getValue()));
|
||||
int z = Integer.parseInt(String.valueOf(tag.getValue().get("z").getValue()));
|
||||
|
||||
CompoundTagBuilder tagBuilder = getConstantBedrockTag(BlockEntityUtils.getBedrockBlockEntityId(id), x, y, z).toBuilder();
|
||||
translateTag(tag, blockState).forEach(tagBuilder::tag);
|
||||
return tagBuilder.buildRootTag();
|
||||
}
|
||||
|
||||
protected CompoundTag getConstantJavaTag(String javaId, int x, int y, int z) {
|
||||
CompoundTag tag = new CompoundTag("");
|
||||
tag.put(new IntTag("x", x));
|
||||
tag.put(new IntTag("y", y));
|
||||
tag.put(new IntTag("z", z));
|
||||
tag.put(new StringTag("id", javaId));
|
||||
return tag;
|
||||
}
|
||||
|
||||
protected com.nukkitx.nbt.tag.CompoundTag getConstantBedrockTag(String bedrockId, int x, int y, int z) {
|
||||
CompoundTagBuilder tagBuilder = CompoundTagBuilder.builder()
|
||||
.intTag("x", x)
|
||||
.intTag("y", y)
|
||||
.intTag("z", z)
|
||||
.stringTag("id", bedrockId);
|
||||
return tagBuilder.buildRootTag();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <T> T getOrDefault(com.github.steveice10.opennbt.tag.builtin.Tag tag, T defaultValue) {
|
||||
return (tag != null && tag.getValue() != null) ? (T) tag.getValue() : defaultValue;
|
||||
}
|
||||
}
|
|
@ -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.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.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.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
@BlockEntity(name = "Campfire", delay = false, regex = "campfire")
|
||||
public class CampfireBlockEntityTranslator extends BlockEntityTranslator {
|
||||
|
||||
@Override
|
||||
public List<Tag<?>> translateTag(CompoundTag tag, BlockState blockState) {
|
||||
List<Tag<?>> tags = new ArrayList<>();
|
||||
ListTag items = tag.get("Items");
|
||||
int i = 1;
|
||||
for (com.github.steveice10.opennbt.tag.builtin.Tag itemTag : items.getValue()) {
|
||||
tags.add(getItem((CompoundTag) itemTag).toBuilder().build("Item" + i));
|
||||
i++;
|
||||
}
|
||||
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.tag(new com.nukkitx.nbt.tag.CompoundTag("Item1", new HashMap<>()));
|
||||
tagBuilder.tag(new com.nukkitx.nbt.tag.CompoundTag("Item2", new HashMap<>()));
|
||||
tagBuilder.tag(new com.nukkitx.nbt.tag.CompoundTag("Item3", new HashMap<>()));
|
||||
tagBuilder.tag(new com.nukkitx.nbt.tag.CompoundTag("Item4", new HashMap<>()));
|
||||
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())
|
||||
.tag(CompoundTagBuilder.builder().build("tag"));
|
||||
return tagBuilder.buildRootTag();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* 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;
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.nukkitx.nbt.tag.Tag;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@BlockEntity(name = "Empty", delay = false, regex = "")
|
||||
public class EmptyBlockEntityTranslator extends BlockEntityTranslator {
|
||||
|
||||
@Override
|
||||
public List<Tag<?>> translateTag(CompoundTag tag, BlockState blockState) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getDefaultJavaTag(String javaId, int x, int y, int z) {
|
||||
return getConstantJavaTag(javaId, x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public com.nukkitx.nbt.tag.CompoundTag getDefaultBedrockTag(String bedrockId, int x, int y, int z) {
|
||||
return getConstantBedrockTag(bedrockId, x, y, z);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* 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;
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.LongTag;
|
||||
import com.nukkitx.nbt.CompoundTagBuilder;
|
||||
import com.nukkitx.nbt.tag.IntTag;
|
||||
import com.nukkitx.nbt.tag.Tag;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
@BlockEntity(name = "EndGateway", delay = true, regex = "end_gateway")
|
||||
public class EndGatewayBlockEntityTranslator extends BlockEntityTranslator {
|
||||
|
||||
@Override
|
||||
public List<Tag<?>> translateTag(CompoundTag tag, BlockState blockState) {
|
||||
List<Tag<?>> tags = new ArrayList<>();
|
||||
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
|
||||
// Linked coordinates
|
||||
List<IntTag> tagsList = new ArrayList<>();
|
||||
// Yes, the axis letters are capitalized
|
||||
tagsList.add(new IntTag("", getExitPortalCoordinate(tag, "X")));
|
||||
tagsList.add(new IntTag("", getExitPortalCoordinate(tag, "Y")));
|
||||
tagsList.add(new IntTag("", getExitPortalCoordinate(tag, "Z")));
|
||||
com.nukkitx.nbt.tag.ListTag<IntTag> exitPortal =
|
||||
new com.nukkitx.nbt.tag.ListTag<>("ExitPortal", IntTag.class, tagsList);
|
||||
tags.add(exitPortal);
|
||||
return tags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getDefaultJavaTag(String javaId, int x, int y, int z) {
|
||||
CompoundTag tag = getConstantJavaTag(javaId, x, y, z);
|
||||
tag.put(new LongTag("Age"));
|
||||
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();
|
||||
List<IntTag> tagsList = new ArrayList<>();
|
||||
tagsList.add(new IntTag("", 0));
|
||||
tagsList.add(new IntTag("", 0));
|
||||
tagsList.add(new IntTag("", 0));
|
||||
tagBuilder.listTag("ExitPortal", IntTag.class, tagsList);
|
||||
return tagBuilder.buildRootTag();
|
||||
}
|
||||
|
||||
private int getExitPortalCoordinate(CompoundTag tag, String axis) {
|
||||
// Return 0 if it doesn't exist, otherwise give proper value
|
||||
if (tag.get("ExitPortal") != null) {
|
||||
LinkedHashMap compoundTag = (LinkedHashMap) tag.get("ExitPortal").getValue();
|
||||
com.github.steveice10.opennbt.tag.builtin.IntTag intTag = (com.github.steveice10.opennbt.tag.builtin.IntTag) compoundTag.get(axis);
|
||||
return intTag.getValue();
|
||||
} return 0;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* 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;
|
||||
import com.github.steveice10.mc.protocol.data.message.Message;
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.nukkitx.nbt.CompoundTagBuilder;
|
||||
import com.nukkitx.nbt.tag.StringTag;
|
||||
import com.nukkitx.nbt.tag.Tag;
|
||||
import org.geysermc.connector.utils.MessageUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@BlockEntity(name = "Sign", delay = true, regex = "sign")
|
||||
public class SignBlockEntityTranslator extends BlockEntityTranslator {
|
||||
|
||||
@Override
|
||||
public List<Tag<?>> translateTag(CompoundTag tag, BlockState blockState) {
|
||||
List<Tag<?>> tags = new ArrayList<>();
|
||||
|
||||
String line1 = getOrDefault(tag.getValue().get("Text1"), "");
|
||||
String line2 = getOrDefault(tag.getValue().get("Text2"), "");
|
||||
String line3 = getOrDefault(tag.getValue().get("Text3"), "");
|
||||
String line4 = getOrDefault(tag.getValue().get("Text4"), "");
|
||||
|
||||
tags.add(new StringTag("Text", MessageUtils.getBedrockMessage(Message.fromString(line1))
|
||||
+ "\n" + MessageUtils.getBedrockMessage(Message.fromString(line2))
|
||||
+ "\n" + MessageUtils.getBedrockMessage(Message.fromString(line3))
|
||||
+ "\n" + MessageUtils.getBedrockMessage(Message.fromString(line4))
|
||||
));
|
||||
|
||||
return tags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getDefaultJavaTag(String javaId, int x, int y, int z) {
|
||||
CompoundTag tag = getConstantJavaTag(javaId, x, y, z);
|
||||
tag.put(new com.github.steveice10.opennbt.tag.builtin.StringTag("Text1", "{\"text\":\"\"}"));
|
||||
tag.put(new com.github.steveice10.opennbt.tag.builtin.StringTag("Text2", "{\"text\":\"\"}"));
|
||||
tag.put(new com.github.steveice10.opennbt.tag.builtin.StringTag("Text3", "{\"text\":\"\"}"));
|
||||
tag.put(new com.github.steveice10.opennbt.tag.builtin.StringTag("Text4", "{\"text\":\"\"}"));
|
||||
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.stringTag("Text", "");
|
||||
return tagBuilder.buildRootTag();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* 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;
|
||||
import com.nukkitx.nbt.CompoundTagBuilder;
|
||||
import com.nukkitx.nbt.tag.ByteTag;
|
||||
import com.nukkitx.nbt.tag.CompoundTag;
|
||||
import com.nukkitx.nbt.tag.FloatTag;
|
||||
import com.nukkitx.nbt.tag.Tag;
|
||||
import org.geysermc.connector.network.translators.block.BlockStateValues;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@BlockEntity(name = "Skull", delay = false, regex = "skull")
|
||||
public class SkullBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState {
|
||||
|
||||
@Override
|
||||
public boolean isBlock(BlockState blockState) {
|
||||
return BlockStateValues.getSkullVariant(blockState) != -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Tag<?>> translateTag(com.github.steveice10.opennbt.tag.builtin.CompoundTag tag, BlockState blockState) {
|
||||
List<Tag<?>> tags = new ArrayList<>();
|
||||
byte skullVariant = BlockStateValues.getSkullVariant(blockState);
|
||||
float rotation = BlockStateValues.getSkullRotation(blockState) * 22.5f;
|
||||
// Just in case...
|
||||
if (skullVariant == -1) skullVariant = 0;
|
||||
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();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* 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.inventory;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||
import com.github.steveice10.mc.protocol.data.message.Message;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientRenameItemPacket;
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.nukkitx.protocol.bedrock.data.ContainerId;
|
||||
import com.nukkitx.protocol.bedrock.data.ContainerType;
|
||||
import com.nukkitx.protocol.bedrock.data.InventoryActionData;
|
||||
import com.nukkitx.protocol.bedrock.data.ItemData;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.inventory.updater.CursorInventoryUpdater;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class AnvilInventoryTranslator extends BlockInventoryTranslator {
|
||||
public AnvilInventoryTranslator() {
|
||||
super(3, "minecraft:anvil[facing=north]", ContainerType.ANVIL, new CursorInventoryUpdater());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int bedrockSlotToJava(InventoryActionData action) {
|
||||
if (action.getSource().getContainerId() == ContainerId.CURSOR) {
|
||||
switch (action.getSlot()) {
|
||||
case 1:
|
||||
return 0;
|
||||
case 2:
|
||||
return 1;
|
||||
case 50:
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
return super.bedrockSlotToJava(action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int javaSlotToBedrock(int slot) {
|
||||
switch (slot) {
|
||||
case 0:
|
||||
return 1;
|
||||
case 1:
|
||||
return 2;
|
||||
case 2:
|
||||
return 50;
|
||||
}
|
||||
return super.javaSlotToBedrock(slot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SlotType getSlotType(int javaSlot) {
|
||||
if (javaSlot == 2)
|
||||
return SlotType.OUTPUT;
|
||||
return SlotType.NORMAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translateActions(GeyserSession session, Inventory inventory, List<InventoryActionData> actions) {
|
||||
InventoryActionData anvilResult = null;
|
||||
InventoryActionData anvilInput = null;
|
||||
for (InventoryActionData action : actions) {
|
||||
if (action.getSource().getContainerId() == ContainerId.ANVIL_MATERIAL) {
|
||||
//useless packet
|
||||
return;
|
||||
} else if (action.getSource().getContainerId() == ContainerId.ANVIL_RESULT) {
|
||||
anvilResult = action;
|
||||
} else if (bedrockSlotToJava(action) == 0) {
|
||||
anvilInput = action;
|
||||
}
|
||||
}
|
||||
ItemData itemName = null;
|
||||
if (anvilResult != null) {
|
||||
itemName = anvilResult.getFromItem();
|
||||
} else if (anvilInput != null) {
|
||||
itemName = anvilInput.getToItem();
|
||||
}
|
||||
if (itemName != null) {
|
||||
String rename;
|
||||
com.nukkitx.nbt.tag.CompoundTag tag = itemName.getTag();
|
||||
if (tag != null) {
|
||||
rename = tag.getCompound("display").getString("Name");
|
||||
} else {
|
||||
rename = "";
|
||||
}
|
||||
ClientRenameItemPacket renameItemPacket = new ClientRenameItemPacket(rename);
|
||||
session.getDownstream().getSession().send(renameItemPacket);
|
||||
}
|
||||
if (anvilResult != null) {
|
||||
//client will send another packet to grab anvil output
|
||||
return;
|
||||
}
|
||||
|
||||
super.translateActions(session, inventory, actions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSlot(GeyserSession session, Inventory inventory, int slot) {
|
||||
if (slot >= 0 && slot <= 2) {
|
||||
ItemStack item = inventory.getItem(slot);
|
||||
if (item != null) {
|
||||
String rename;
|
||||
CompoundTag tag = item.getNbt();
|
||||
if (tag != null) {
|
||||
CompoundTag displayTag = tag.get("display");
|
||||
if (displayTag != null) {
|
||||
String itemName = displayTag.get("Name").getValue().toString();
|
||||
Message message = Message.fromString(itemName);
|
||||
rename = message.getText();
|
||||
} else {
|
||||
rename = "";
|
||||
}
|
||||
} else {
|
||||
rename = "";
|
||||
}
|
||||
ClientRenameItemPacket renameItemPacket = new ClientRenameItemPacket(rename);
|
||||
session.getDownstream().getSession().send(renameItemPacket);
|
||||
}
|
||||
}
|
||||
super.updateSlot(session, inventory, slot);
|
||||
}
|
||||
}
|
|
@ -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.inventory;
|
||||
|
||||
import com.nukkitx.protocol.bedrock.data.ContainerId;
|
||||
import com.nukkitx.protocol.bedrock.data.InventoryActionData;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.inventory.action.InventoryActionDataTranslator;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public abstract class BaseInventoryTranslator extends InventoryTranslator{
|
||||
BaseInventoryTranslator(int size) {
|
||||
super(size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) {
|
||||
//
|
||||
}
|
||||
|
||||
@Override
|
||||
public int bedrockSlotToJava(InventoryActionData action) {
|
||||
int slotnum = action.getSlot();
|
||||
if (action.getSource().getContainerId() == ContainerId.INVENTORY) {
|
||||
//hotbar
|
||||
if (slotnum >= 9) {
|
||||
return slotnum + this.size - 9;
|
||||
} else {
|
||||
return slotnum + this.size + 27;
|
||||
}
|
||||
}
|
||||
return slotnum;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int javaSlotToBedrock(int slot) {
|
||||
if (slot >= this.size) {
|
||||
final int tmp = slot - this.size;
|
||||
if (tmp < 27) {
|
||||
return tmp + 9;
|
||||
} else {
|
||||
return tmp - 27;
|
||||
}
|
||||
}
|
||||
return slot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SlotType getSlotType(int javaSlot) {
|
||||
return SlotType.NORMAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translateActions(GeyserSession session, Inventory inventory, List<InventoryActionData> actions) {
|
||||
InventoryActionDataTranslator.translate(this, session, inventory, actions);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* 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.inventory;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
|
||||
import com.nukkitx.protocol.bedrock.data.ContainerType;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.block.BlockTranslator;
|
||||
import org.geysermc.connector.network.translators.inventory.holder.BlockInventoryHolder;
|
||||
import org.geysermc.connector.network.translators.inventory.holder.InventoryHolder;
|
||||
import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater;
|
||||
|
||||
public class BlockInventoryTranslator extends BaseInventoryTranslator {
|
||||
private final InventoryHolder holder;
|
||||
private final InventoryUpdater updater;
|
||||
|
||||
public BlockInventoryTranslator(int size, String javaBlockIdentifier, ContainerType containerType, InventoryUpdater updater) {
|
||||
super(size);
|
||||
BlockState javaBlockState = BlockTranslator.getJavaBlockState(javaBlockIdentifier);
|
||||
int blockId = BlockTranslator.getBedrockBlockId(javaBlockState);
|
||||
this.holder = new BlockInventoryHolder(blockId, containerType);
|
||||
this.updater = updater;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepareInventory(GeyserSession session, Inventory inventory) {
|
||||
holder.prepareInventory(this, session, inventory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openInventory(GeyserSession session, Inventory inventory) {
|
||||
holder.openInventory(this, session, inventory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeInventory(GeyserSession session, Inventory inventory) {
|
||||
holder.closeInventory(this, session, inventory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateInventory(GeyserSession session, Inventory inventory) {
|
||||
updater.updateInventory(this, session, inventory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSlot(GeyserSession session, Inventory inventory, int slot) {
|
||||
updater.updateSlot(this, session, inventory, slot);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* 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.inventory;
|
||||
|
||||
import com.nukkitx.protocol.bedrock.data.ContainerType;
|
||||
import com.nukkitx.protocol.bedrock.data.InventoryActionData;
|
||||
import com.nukkitx.protocol.bedrock.packet.ContainerSetDataPacket;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.inventory.updater.ContainerInventoryUpdater;
|
||||
|
||||
public class BrewingInventoryTranslator extends BlockInventoryTranslator {
|
||||
public BrewingInventoryTranslator() {
|
||||
super(5, "minecraft:brewing_stand[has_bottle_0=false,has_bottle_1=false,has_bottle_2=false]", ContainerType.BREWING_STAND, new ContainerInventoryUpdater());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openInventory(GeyserSession session, Inventory inventory) {
|
||||
super.openInventory(session, inventory);
|
||||
ContainerSetDataPacket dataPacket = new ContainerSetDataPacket();
|
||||
dataPacket.setWindowId((byte) inventory.getId());
|
||||
dataPacket.setProperty(ContainerSetDataPacket.BREWING_STAND_FUEL_TOTAL);
|
||||
dataPacket.setValue(20);
|
||||
session.getUpstream().sendPacket(dataPacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) {
|
||||
ContainerSetDataPacket dataPacket = new ContainerSetDataPacket();
|
||||
dataPacket.setWindowId((byte) inventory.getId());
|
||||
switch (key) {
|
||||
case 0:
|
||||
dataPacket.setProperty(ContainerSetDataPacket.BREWING_STAND_BREW_TIME);
|
||||
break;
|
||||
case 1:
|
||||
dataPacket.setProperty(ContainerSetDataPacket.BREWING_STAND_FUEL_AMOUNT);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
dataPacket.setValue(value);
|
||||
session.getUpstream().sendPacket(dataPacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int bedrockSlotToJava(InventoryActionData action) {
|
||||
final int slot = super.bedrockSlotToJava(action);
|
||||
switch (slot) {
|
||||
case 0:
|
||||
return 3;
|
||||
case 1:
|
||||
return 0;
|
||||
case 2:
|
||||
return 1;
|
||||
case 3:
|
||||
return 2;
|
||||
default:
|
||||
return slot;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int javaSlotToBedrock(int slot) {
|
||||
switch (slot) {
|
||||
case 0:
|
||||
return 1;
|
||||
case 1:
|
||||
return 2;
|
||||
case 2:
|
||||
return 3;
|
||||
case 3:
|
||||
return 0;
|
||||
}
|
||||
return super.javaSlotToBedrock(slot);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* 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.inventory;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
|
||||
import com.nukkitx.protocol.bedrock.data.ContainerId;
|
||||
import com.nukkitx.protocol.bedrock.data.ContainerType;
|
||||
import com.nukkitx.protocol.bedrock.data.InventoryActionData;
|
||||
import com.nukkitx.protocol.bedrock.data.InventorySource;
|
||||
import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.inventory.updater.CursorInventoryUpdater;
|
||||
import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater;
|
||||
import org.geysermc.connector.utils.InventoryUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class CraftingInventoryTranslator extends BaseInventoryTranslator {
|
||||
private final InventoryUpdater updater;
|
||||
|
||||
public CraftingInventoryTranslator() {
|
||||
super(10);
|
||||
this.updater = new CursorInventoryUpdater();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepareInventory(GeyserSession session, Inventory inventory) {
|
||||
//
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openInventory(GeyserSession session, Inventory inventory) {
|
||||
ContainerOpenPacket containerOpenPacket = new ContainerOpenPacket();
|
||||
containerOpenPacket.setWindowId((byte) inventory.getId());
|
||||
containerOpenPacket.setType((byte) ContainerType.WORKBENCH.id());
|
||||
containerOpenPacket.setBlockPosition(inventory.getHolderPosition());
|
||||
containerOpenPacket.setUniqueEntityId(inventory.getHolderId());
|
||||
session.getUpstream().sendPacket(containerOpenPacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeInventory(GeyserSession session, Inventory inventory) {
|
||||
//
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateInventory(GeyserSession session, Inventory inventory) {
|
||||
updater.updateInventory(this, session, inventory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSlot(GeyserSession session, Inventory inventory, int slot) {
|
||||
updater.updateSlot(this, session, inventory, slot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int bedrockSlotToJava(InventoryActionData action) {
|
||||
if (action.getSource().getContainerId() == ContainerId.CURSOR) {
|
||||
int slotnum = action.getSlot();
|
||||
if (slotnum >= 32 && 42 >= slotnum) {
|
||||
return slotnum - 31;
|
||||
} else if (slotnum == 50) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return super.bedrockSlotToJava(action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int javaSlotToBedrock(int slot) {
|
||||
return slot == 0 ? 50 : slot + 31;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SlotType getSlotType(int javaSlot) {
|
||||
if (javaSlot == 0)
|
||||
return SlotType.OUTPUT;
|
||||
return SlotType.NORMAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translateActions(GeyserSession session, Inventory inventory, List<InventoryActionData> actions) {
|
||||
if (session.getGameMode() == GameMode.CREATIVE) {
|
||||
for (InventoryActionData action : actions) {
|
||||
if (action.getSource().getType() == InventorySource.Type.CREATIVE) {
|
||||
updateInventory(session, inventory);
|
||||
InventoryUtils.updateCursor(session);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
super.translateActions(session, inventory, actions);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* 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.inventory;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
||||
import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
|
||||
import com.nukkitx.math.vector.Vector3i;
|
||||
import com.nukkitx.nbt.tag.CompoundTag;
|
||||
import com.nukkitx.protocol.bedrock.data.ContainerType;
|
||||
import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.block.BlockTranslator;
|
||||
import org.geysermc.connector.network.translators.inventory.updater.ChestInventoryUpdater;
|
||||
import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater;
|
||||
|
||||
public class DoubleChestInventoryTranslator extends BaseInventoryTranslator {
|
||||
private final int blockId;
|
||||
private final InventoryUpdater updater;
|
||||
|
||||
public DoubleChestInventoryTranslator(int size) {
|
||||
super(size);
|
||||
BlockState javaBlockState = BlockTranslator.getJavaBlockState("minecraft:chest[facing=north,type=single,waterlogged=false]");
|
||||
this.blockId = BlockTranslator.getBedrockBlockId(javaBlockState);
|
||||
this.updater = new ChestInventoryUpdater(54);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepareInventory(GeyserSession session, Inventory inventory) {
|
||||
Vector3i position = session.getPlayerEntity().getPosition().toInt().add(Vector3i.UP);
|
||||
Vector3i pairPosition = position.add(Vector3i.UNIT_X);
|
||||
|
||||
UpdateBlockPacket blockPacket = new UpdateBlockPacket();
|
||||
blockPacket.setDataLayer(0);
|
||||
blockPacket.setBlockPosition(position);
|
||||
blockPacket.setRuntimeId(blockId);
|
||||
blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY);
|
||||
session.getUpstream().sendPacket(blockPacket);
|
||||
|
||||
CompoundTag tag = CompoundTag.builder()
|
||||
.stringTag("id", "Chest")
|
||||
.intTag("x", position.getX())
|
||||
.intTag("y", position.getY())
|
||||
.intTag("z", position.getZ())
|
||||
.intTag("pairx", pairPosition.getX())
|
||||
.intTag("pairz", pairPosition.getZ())
|
||||
.stringTag("CustomName", inventory.getTitle()).buildRootTag();
|
||||
BlockEntityDataPacket dataPacket = new BlockEntityDataPacket();
|
||||
dataPacket.setData(tag);
|
||||
dataPacket.setBlockPosition(position);
|
||||
session.getUpstream().sendPacket(dataPacket);
|
||||
|
||||
blockPacket = new UpdateBlockPacket();
|
||||
blockPacket.setDataLayer(0);
|
||||
blockPacket.setBlockPosition(pairPosition);
|
||||
blockPacket.setRuntimeId(blockId);
|
||||
blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY);
|
||||
session.getUpstream().sendPacket(blockPacket);
|
||||
|
||||
tag = CompoundTag.builder()
|
||||
.stringTag("id", "Chest")
|
||||
.intTag("x", pairPosition.getX())
|
||||
.intTag("y", pairPosition.getY())
|
||||
.intTag("z", pairPosition.getZ())
|
||||
.intTag("pairx", position.getX())
|
||||
.intTag("pairz", position.getZ())
|
||||
.stringTag("CustomName", inventory.getTitle()).buildRootTag();
|
||||
dataPacket = new BlockEntityDataPacket();
|
||||
dataPacket.setData(tag);
|
||||
dataPacket.setBlockPosition(pairPosition);
|
||||
session.getUpstream().sendPacket(dataPacket);
|
||||
|
||||
inventory.setHolderPosition(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openInventory(GeyserSession session, Inventory inventory) {
|
||||
ContainerOpenPacket containerOpenPacket = new ContainerOpenPacket();
|
||||
containerOpenPacket.setWindowId((byte) inventory.getId());
|
||||
containerOpenPacket.setType((byte) ContainerType.CONTAINER.id());
|
||||
containerOpenPacket.setBlockPosition(inventory.getHolderPosition());
|
||||
containerOpenPacket.setUniqueEntityId(inventory.getHolderId());
|
||||
session.getUpstream().sendPacket(containerOpenPacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeInventory(GeyserSession session, Inventory inventory) {
|
||||
Vector3i holderPos = inventory.getHolderPosition();
|
||||
Position pos = new Position(holderPos.getX(), holderPos.getY(), holderPos.getZ());
|
||||
BlockState realBlock = session.getChunkCache().getBlockAt(pos);
|
||||
UpdateBlockPacket blockPacket = new UpdateBlockPacket();
|
||||
blockPacket.setDataLayer(0);
|
||||
blockPacket.setBlockPosition(holderPos);
|
||||
blockPacket.setRuntimeId(BlockTranslator.getBedrockBlockId(realBlock));
|
||||
session.getUpstream().sendPacket(blockPacket);
|
||||
|
||||
holderPos = holderPos.add(Vector3i.UNIT_X);
|
||||
pos = new Position(holderPos.getX(), holderPos.getY(), holderPos.getZ());
|
||||
realBlock = session.getChunkCache().getBlockAt(pos);
|
||||
blockPacket = new UpdateBlockPacket();
|
||||
blockPacket.setDataLayer(0);
|
||||
blockPacket.setBlockPosition(holderPos);
|
||||
blockPacket.setRuntimeId(BlockTranslator.getBedrockBlockId(realBlock));
|
||||
session.getUpstream().sendPacket(blockPacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateInventory(GeyserSession session, Inventory inventory) {
|
||||
updater.updateInventory(this, session, inventory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSlot(GeyserSession session, Inventory inventory, int slot) {
|
||||
updater.updateSlot(this, session, inventory, slot);
|
||||
}
|
||||
}
|
|
@ -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.inventory;
|
||||
|
||||
import com.nukkitx.protocol.bedrock.data.ContainerType;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.inventory.updater.ContainerInventoryUpdater;
|
||||
|
||||
public class EnchantmentInventoryTranslator extends BlockInventoryTranslator {
|
||||
public EnchantmentInventoryTranslator() {
|
||||
super(2, "minecraft:enchanting_table", ContainerType.ENCHANTMENT, new ContainerInventoryUpdater());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) {
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* 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.inventory;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.window.WindowType;
|
||||
import com.nukkitx.protocol.bedrock.data.ContainerType;
|
||||
import com.nukkitx.protocol.bedrock.packet.ContainerSetDataPacket;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.inventory.updater.ContainerInventoryUpdater;
|
||||
|
||||
public class FurnaceInventoryTranslator extends BlockInventoryTranslator {
|
||||
public FurnaceInventoryTranslator() {
|
||||
super(3, "minecraft:furnace[facing=north,lit=false]", ContainerType.FURNACE, new ContainerInventoryUpdater());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) {
|
||||
ContainerSetDataPacket dataPacket = new ContainerSetDataPacket();
|
||||
dataPacket.setWindowId((byte) inventory.getId());
|
||||
switch (key) {
|
||||
case 0:
|
||||
dataPacket.setProperty(ContainerSetDataPacket.FURNACE_LIT_TIME);
|
||||
break;
|
||||
case 1:
|
||||
dataPacket.setProperty(ContainerSetDataPacket.FURNACE_LIT_DURATION);
|
||||
break;
|
||||
case 2:
|
||||
dataPacket.setProperty(ContainerSetDataPacket.FURNACE_TICK_COUNT);
|
||||
if (inventory.getWindowType() == WindowType.BLAST_FURNACE || inventory.getWindowType() == WindowType.SMOKER) {
|
||||
value *= 2;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
dataPacket.setValue(value);
|
||||
session.getUpstream().sendPacket(dataPacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SlotType getSlotType(int javaSlot) {
|
||||
if (javaSlot == 2)
|
||||
return SlotType.FURNACE_OUTPUT;
|
||||
return SlotType.NORMAL;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* 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.inventory;
|
||||
|
||||
import com.nukkitx.protocol.bedrock.data.ContainerType;
|
||||
import com.nukkitx.protocol.bedrock.data.InventoryActionData;
|
||||
import org.geysermc.connector.network.translators.inventory.updater.CursorInventoryUpdater;
|
||||
|
||||
public class GrindstoneInventoryTranslator extends BlockInventoryTranslator {
|
||||
|
||||
public GrindstoneInventoryTranslator() {
|
||||
super(3, "minecraft:grindstone[face=floor,facing=north]", ContainerType.GRINDSTONE, new CursorInventoryUpdater());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int bedrockSlotToJava(InventoryActionData action) {
|
||||
final int slot = super.bedrockSlotToJava(action);
|
||||
if (action.getSource().getContainerId() == 124) {
|
||||
switch (slot) {
|
||||
case 16:
|
||||
return 0;
|
||||
case 17:
|
||||
return 1;
|
||||
case 50:
|
||||
return 2;
|
||||
default:
|
||||
return slot;
|
||||
}
|
||||
} return slot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int javaSlotToBedrock(int slot) {
|
||||
switch (slot) {
|
||||
case 0:
|
||||
return 16;
|
||||
case 1:
|
||||
return 17;
|
||||
case 2:
|
||||
return 50;
|
||||
}
|
||||
return super.javaSlotToBedrock(slot);
|
||||
}
|
||||
|
||||
}
|
|
@ -25,14 +25,25 @@
|
|||
|
||||
package org.geysermc.connector.network.translators.inventory;
|
||||
|
||||
import com.nukkitx.protocol.bedrock.data.InventoryActionData;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@AllArgsConstructor
|
||||
public abstract class InventoryTranslator {
|
||||
public final int size;
|
||||
|
||||
public abstract void prepareInventory(GeyserSession session, Inventory inventory);
|
||||
public abstract void openInventory(GeyserSession session, Inventory inventory);
|
||||
public abstract void closeInventory(GeyserSession session, Inventory inventory);
|
||||
public abstract void updateProperty(GeyserSession session, Inventory inventory, int key, int value);
|
||||
public abstract void updateInventory(GeyserSession session, Inventory inventory);
|
||||
public abstract void updateSlot(GeyserSession session, Inventory inventory, int slot);
|
||||
|
||||
public abstract int bedrockSlotToJava(InventoryActionData action);
|
||||
public abstract int javaSlotToBedrock(int slot);
|
||||
public abstract SlotType getSlotType(int javaSlot);
|
||||
public abstract void translateActions(GeyserSession session, Inventory inventory, List<InventoryActionData> actions);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,225 @@
|
|||
/*
|
||||
* 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.inventory;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientCreativeInventoryActionPacket;
|
||||
import com.nukkitx.protocol.bedrock.data.*;
|
||||
import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.Translators;
|
||||
import org.geysermc.connector.network.translators.inventory.action.InventoryActionDataTranslator;
|
||||
import org.geysermc.connector.utils.InventoryUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PlayerInventoryTranslator extends InventoryTranslator {
|
||||
public PlayerInventoryTranslator() {
|
||||
super(46);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateInventory(GeyserSession session, Inventory inventory) {
|
||||
// Crafting grid
|
||||
for (int i = 1; i < 5; i++) {
|
||||
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
||||
slotPacket.setContainerId(ContainerId.CURSOR);
|
||||
slotPacket.setSlot(i + 27);
|
||||
slotPacket.setItem(Translators.getItemTranslator().translateToBedrock(inventory.getItem(i)));
|
||||
session.getUpstream().sendPacket(slotPacket);
|
||||
}
|
||||
|
||||
InventoryContentPacket inventoryContentPacket = new InventoryContentPacket();
|
||||
inventoryContentPacket.setContainerId(ContainerId.INVENTORY);
|
||||
ItemData[] contents = new ItemData[36];
|
||||
// Inventory
|
||||
for (int i = 9; i < 36; i++) {
|
||||
contents[i] = Translators.getItemTranslator().translateToBedrock(inventory.getItem(i));
|
||||
}
|
||||
// Hotbar
|
||||
for (int i = 36; i < 45; i++) {
|
||||
contents[i - 36] = Translators.getItemTranslator().translateToBedrock(inventory.getItem(i));
|
||||
}
|
||||
inventoryContentPacket.setContents(contents);
|
||||
session.getUpstream().sendPacket(inventoryContentPacket);
|
||||
|
||||
// Armor
|
||||
InventoryContentPacket armorContentPacket = new InventoryContentPacket();
|
||||
armorContentPacket.setContainerId(ContainerId.ARMOR);
|
||||
contents = new ItemData[4];
|
||||
for (int i = 5; i < 9; i++) {
|
||||
contents[i - 5] = Translators.getItemTranslator().translateToBedrock(inventory.getItem(i));
|
||||
}
|
||||
armorContentPacket.setContents(contents);
|
||||
session.getUpstream().sendPacket(armorContentPacket);
|
||||
|
||||
// Offhand
|
||||
InventoryContentPacket offhandPacket = new InventoryContentPacket();
|
||||
offhandPacket.setContainerId(ContainerId.OFFHAND);
|
||||
offhandPacket.setContents(new ItemData[]{Translators.getItemTranslator().translateToBedrock(inventory.getItem(45))});
|
||||
session.getUpstream().sendPacket(offhandPacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSlot(GeyserSession session, Inventory inventory, int slot) {
|
||||
if (slot >= 1 && slot <= 44) {
|
||||
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
||||
if (slot >= 9) {
|
||||
slotPacket.setContainerId(ContainerId.INVENTORY);
|
||||
if (slot >= 36) {
|
||||
slotPacket.setSlot(slot - 36);
|
||||
} else {
|
||||
slotPacket.setSlot(slot);
|
||||
}
|
||||
} else if (slot >= 5) {
|
||||
slotPacket.setContainerId(ContainerId.ARMOR);
|
||||
slotPacket.setSlot(slot - 5);
|
||||
} else {
|
||||
slotPacket.setContainerId(ContainerId.CURSOR);
|
||||
slotPacket.setSlot(slot + 27);
|
||||
}
|
||||
slotPacket.setItem(Translators.getItemTranslator().translateToBedrock(inventory.getItem(slot)));
|
||||
session.getUpstream().sendPacket(slotPacket);
|
||||
} else if (slot == 45) {
|
||||
InventoryContentPacket offhandPacket = new InventoryContentPacket();
|
||||
offhandPacket.setContainerId(ContainerId.OFFHAND);
|
||||
offhandPacket.setContents(new ItemData[]{Translators.getItemTranslator().translateToBedrock(inventory.getItem(slot))});
|
||||
session.getUpstream().sendPacket(offhandPacket);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int bedrockSlotToJava(InventoryActionData action) {
|
||||
int slotnum = action.getSlot();
|
||||
switch (action.getSource().getContainerId()) {
|
||||
case ContainerId.INVENTORY:
|
||||
// Inventory
|
||||
if (slotnum >= 9 && slotnum <= 35) {
|
||||
return slotnum;
|
||||
}
|
||||
// Hotbar
|
||||
if (slotnum >= 0 && slotnum <= 8) {
|
||||
return slotnum + 36;
|
||||
}
|
||||
break;
|
||||
case ContainerId.ARMOR:
|
||||
if (slotnum >= 0 && slotnum <= 3) {
|
||||
return slotnum + 5;
|
||||
}
|
||||
break;
|
||||
case ContainerId.OFFHAND:
|
||||
return 45;
|
||||
case ContainerId.CURSOR:
|
||||
if (slotnum >= 28 && 31 >= slotnum) {
|
||||
return slotnum - 27;
|
||||
} else if (slotnum == 50) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return slotnum;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int javaSlotToBedrock(int slot) {
|
||||
return slot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SlotType getSlotType(int javaSlot) {
|
||||
if (javaSlot == 0)
|
||||
return SlotType.OUTPUT;
|
||||
return SlotType.NORMAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translateActions(GeyserSession session, Inventory inventory, List<InventoryActionData> actions) {
|
||||
if (session.getGameMode() == GameMode.CREATIVE) {
|
||||
//crafting grid is not visible in creative mode in java edition
|
||||
for (InventoryActionData action : actions) {
|
||||
if (action.getSource().getContainerId() == ContainerId.CURSOR && (action.getSlot() >= 28 && 31 >= action.getSlot())) {
|
||||
updateInventory(session, inventory);
|
||||
InventoryUtils.updateCursor(session);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ItemStack javaItem;
|
||||
for (InventoryActionData action : actions) {
|
||||
switch (action.getSource().getContainerId()) {
|
||||
case ContainerId.INVENTORY:
|
||||
case ContainerId.ARMOR:
|
||||
case ContainerId.OFFHAND:
|
||||
int javaSlot = bedrockSlotToJava(action);
|
||||
if (action.getToItem().getId() == 0) {
|
||||
javaItem = new ItemStack(-1, 0, null);
|
||||
} else {
|
||||
javaItem = Translators.getItemTranslator().translateToJava(action.getToItem());
|
||||
}
|
||||
ClientCreativeInventoryActionPacket creativePacket = new ClientCreativeInventoryActionPacket(javaSlot, javaItem);
|
||||
session.getDownstream().getSession().send(creativePacket);
|
||||
inventory.setItem(javaSlot, javaItem);
|
||||
break;
|
||||
case ContainerId.CURSOR:
|
||||
if (action.getSlot() == 0) {
|
||||
session.getInventory().setCursor(Translators.getItemTranslator().translateToJava(action.getToItem()));
|
||||
}
|
||||
break;
|
||||
case ContainerId.NONE:
|
||||
if (action.getSource().getType() == InventorySource.Type.WORLD_INTERACTION
|
||||
&& action.getSource().getFlag() == InventorySource.Flag.DROP_ITEM) {
|
||||
javaItem = Translators.getItemTranslator().translateToJava(action.getToItem());
|
||||
ClientCreativeInventoryActionPacket creativeDropPacket = new ClientCreativeInventoryActionPacket(-1, javaItem);
|
||||
session.getDownstream().getSession().send(creativeDropPacket);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
InventoryActionDataTranslator.translate(this, session, inventory, actions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepareInventory(GeyserSession session, Inventory inventory) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openInventory(GeyserSession session, Inventory inventory) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeInventory(GeyserSession session, Inventory inventory) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* 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.inventory;
|
||||
|
||||
import com.nukkitx.protocol.bedrock.data.ContainerType;
|
||||
import org.geysermc.connector.network.translators.inventory.updater.ChestInventoryUpdater;
|
||||
|
||||
public class SingleChestInventoryTranslator extends BlockInventoryTranslator {
|
||||
public SingleChestInventoryTranslator(int size) {
|
||||
super(size, "minecraft:chest[facing=north,type=single,waterlogged=false]", ContainerType.CONTAINER, new ChestInventoryUpdater(27));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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.inventory;
|
||||
|
||||
public enum SlotType {
|
||||
NORMAL,
|
||||
OUTPUT,
|
||||
FURNACE_OUTPUT
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* 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.inventory.action;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.window.ClickItemParam;
|
||||
import com.github.steveice10.mc.protocol.data.game.window.WindowActionParam;
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
@AllArgsConstructor
|
||||
enum Click {
|
||||
LEFT(ClickItemParam.LEFT_CLICK),
|
||||
RIGHT(ClickItemParam.RIGHT_CLICK);
|
||||
|
||||
public final WindowActionParam actionParam;
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* 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.inventory.action;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||
import com.github.steveice10.mc.protocol.data.game.window.WindowAction;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientConfirmTransactionPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientWindowActionPacket;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.inventory.PlayerInventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
||||
import org.geysermc.connector.network.translators.inventory.SlotType;
|
||||
import org.geysermc.connector.utils.InventoryUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
class ClickPlan {
|
||||
private final List<ClickAction> plan = new ArrayList<>();
|
||||
|
||||
public void add(Click click, int slot) {
|
||||
plan.add(new ClickAction(click, slot));
|
||||
}
|
||||
|
||||
public void execute(GeyserSession session, InventoryTranslator translator, Inventory inventory, boolean refresh) {
|
||||
PlayerInventory playerInventory = session.getInventory();
|
||||
ListIterator<ClickAction> planIter = plan.listIterator();
|
||||
while (planIter.hasNext()) {
|
||||
final ClickAction action = planIter.next();
|
||||
final ItemStack cursorItem = playerInventory.getCursor();
|
||||
final ItemStack clickedItem = inventory.getItem(action.slot);
|
||||
final short actionId = (short) inventory.getTransactionId().getAndIncrement();
|
||||
|
||||
//TODO: stop relying on refreshing the inventory for crafting to work properly
|
||||
if (translator.getSlotType(action.slot) != SlotType.NORMAL)
|
||||
refresh = true;
|
||||
|
||||
ClientWindowActionPacket clickPacket = new ClientWindowActionPacket(inventory.getId(),
|
||||
actionId, action.slot, !planIter.hasNext() && refresh ? InventoryUtils.REFRESH_ITEM : clickedItem,
|
||||
WindowAction.CLICK_ITEM, action.click.actionParam);
|
||||
|
||||
if (translator.getSlotType(action.slot) == SlotType.OUTPUT) {
|
||||
if (cursorItem == null && clickedItem != null) {
|
||||
playerInventory.setCursor(clickedItem);
|
||||
} else if (InventoryUtils.canStack(cursorItem, clickedItem)) {
|
||||
playerInventory.setCursor(new ItemStack(cursorItem.getId(),
|
||||
cursorItem.getAmount() + clickedItem.getAmount(), cursorItem.getNbt()));
|
||||
}
|
||||
} else {
|
||||
switch (action.click) {
|
||||
case LEFT:
|
||||
if (!InventoryUtils.canStack(cursorItem, clickedItem)) {
|
||||
playerInventory.setCursor(clickedItem);
|
||||
inventory.setItem(action.slot, cursorItem);
|
||||
} else {
|
||||
playerInventory.setCursor(null);
|
||||
inventory.setItem(action.slot, new ItemStack(clickedItem.getId(),
|
||||
clickedItem.getAmount() + cursorItem.getAmount(), clickedItem.getNbt()));
|
||||
}
|
||||
break;
|
||||
case RIGHT:
|
||||
if (cursorItem == null && clickedItem != null) {
|
||||
ItemStack halfItem = new ItemStack(clickedItem.getId(),
|
||||
clickedItem.getAmount() / 2, clickedItem.getNbt());
|
||||
inventory.setItem(action.slot, halfItem);
|
||||
playerInventory.setCursor(new ItemStack(clickedItem.getId(),
|
||||
clickedItem.getAmount() - halfItem.getAmount(), clickedItem.getNbt()));
|
||||
} else if (cursorItem != null && clickedItem == null) {
|
||||
playerInventory.setCursor(new ItemStack(cursorItem.getId(),
|
||||
cursorItem.getAmount() - 1, cursorItem.getNbt()));
|
||||
inventory.setItem(action.slot, new ItemStack(cursorItem.getId(),
|
||||
1, cursorItem.getNbt()));
|
||||
} else if (InventoryUtils.canStack(cursorItem, clickedItem)) {
|
||||
playerInventory.setCursor(new ItemStack(cursorItem.getId(),
|
||||
cursorItem.getAmount() - 1, cursorItem.getNbt()));
|
||||
inventory.setItem(action.slot, new ItemStack(clickedItem.getId(),
|
||||
clickedItem.getAmount() + 1, clickedItem.getNbt()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
session.getDownstream().getSession().send(clickPacket);
|
||||
session.getDownstream().getSession().send(new ClientConfirmTransactionPacket(inventory.getId(), actionId, true));
|
||||
}
|
||||
|
||||
/*if (refresh) {
|
||||
translator.updateInventory(session, inventory);
|
||||
InventoryUtils.updateCursor(session);
|
||||
}*/
|
||||
}
|
||||
|
||||
private static class ClickAction {
|
||||
final Click click;
|
||||
final int slot;
|
||||
ClickAction(Click click, int slot) {
|
||||
this.click = click;
|
||||
this.slot = slot;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,330 @@
|
|||
/*
|
||||
* 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.inventory.action;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction;
|
||||
import com.github.steveice10.mc.protocol.data.game.window.*;
|
||||
import com.github.steveice10.mc.protocol.data.game.world.block.BlockFace;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerActionPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientWindowActionPacket;
|
||||
import com.nukkitx.protocol.bedrock.data.ContainerId;
|
||||
import com.nukkitx.protocol.bedrock.data.InventoryActionData;
|
||||
import com.nukkitx.protocol.bedrock.data.InventorySource;
|
||||
import com.nukkitx.protocol.bedrock.data.ItemData;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.Translators;
|
||||
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
||||
import org.geysermc.connector.network.translators.inventory.SlotType;
|
||||
import org.geysermc.connector.utils.InventoryUtils;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class InventoryActionDataTranslator {
|
||||
public static void translate(InventoryTranslator translator, GeyserSession session, Inventory inventory, List<InventoryActionData> actions) {
|
||||
if (actions.size() != 2)
|
||||
return;
|
||||
|
||||
InventoryActionData worldAction = null;
|
||||
InventoryActionData cursorAction = null;
|
||||
InventoryActionData containerAction = null;
|
||||
boolean refresh = false;
|
||||
for (InventoryActionData action : actions) {
|
||||
if (action.getSource().getContainerId() == ContainerId.CRAFTING_USE_INGREDIENT || action.getSource().getContainerId() == ContainerId.CRAFTING_RESULT) {
|
||||
return;
|
||||
} else if (action.getSource().getType() == InventorySource.Type.WORLD_INTERACTION) {
|
||||
worldAction = action;
|
||||
} else if (action.getSource().getContainerId() == ContainerId.CURSOR && action.getSlot() == 0) {
|
||||
cursorAction = action;
|
||||
ItemData translatedCursor = Translators.getItemTranslator().translateToBedrock(session.getInventory().getCursor());
|
||||
if (!translatedCursor.equals(action.getFromItem())) {
|
||||
refresh = true;
|
||||
}
|
||||
} else {
|
||||
containerAction = action;
|
||||
ItemData translatedItem = Translators.getItemTranslator().translateToBedrock(inventory.getItem(translator.bedrockSlotToJava(action)));
|
||||
if (!translatedItem.equals(action.getFromItem())) {
|
||||
refresh = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final int craftSlot = session.getCraftSlot();
|
||||
session.setCraftSlot(0);
|
||||
|
||||
if (worldAction != null) {
|
||||
InventoryActionData sourceAction;
|
||||
if (cursorAction != null) {
|
||||
sourceAction = cursorAction;
|
||||
} else {
|
||||
sourceAction = containerAction;
|
||||
}
|
||||
|
||||
if (sourceAction != null) {
|
||||
if (worldAction.getSource().getFlag() == InventorySource.Flag.DROP_ITEM) {
|
||||
//quick dropping from hotbar?
|
||||
if (session.getInventoryCache().getOpenInventory() == null && sourceAction.getSource().getContainerId() == ContainerId.INVENTORY) {
|
||||
int heldSlot = session.getInventory().getHeldItemSlot();
|
||||
if (sourceAction.getSlot() == heldSlot) {
|
||||
ClientPlayerActionPacket actionPacket = new ClientPlayerActionPacket(
|
||||
sourceAction.getToItem().getCount() == 0 ? PlayerAction.DROP_ITEM_STACK : PlayerAction.DROP_ITEM,
|
||||
new Position(0, 0, 0), BlockFace.DOWN);
|
||||
session.getDownstream().getSession().send(actionPacket);
|
||||
ItemStack item = session.getInventory().getItem(heldSlot);
|
||||
if (item != null) {
|
||||
session.getInventory().setItem(heldSlot, new ItemStack(item.getId(), item.getAmount() - 1, item.getNbt()));
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
int dropAmount = sourceAction.getFromItem().getCount() - sourceAction.getToItem().getCount();
|
||||
if (sourceAction != cursorAction) { //dropping directly from inventory
|
||||
int javaSlot = translator.bedrockSlotToJava(sourceAction);
|
||||
if (dropAmount == sourceAction.getFromItem().getCount()) {
|
||||
ClientWindowActionPacket dropPacket = new ClientWindowActionPacket(inventory.getId(),
|
||||
inventory.getTransactionId().getAndIncrement(),
|
||||
javaSlot, null, WindowAction.DROP_ITEM,
|
||||
DropItemParam.DROP_SELECTED_STACK);
|
||||
session.getDownstream().getSession().send(dropPacket);
|
||||
} else {
|
||||
for (int i = 0; i < dropAmount; i++) {
|
||||
ClientWindowActionPacket dropPacket = new ClientWindowActionPacket(inventory.getId(),
|
||||
inventory.getTransactionId().getAndIncrement(),
|
||||
javaSlot, null, WindowAction.DROP_ITEM,
|
||||
DropItemParam.DROP_FROM_SELECTED);
|
||||
session.getDownstream().getSession().send(dropPacket);
|
||||
}
|
||||
}
|
||||
ItemStack item = session.getInventory().getItem(javaSlot);
|
||||
if (item != null) {
|
||||
session.getInventory().setItem(javaSlot, new ItemStack(item.getId(), item.getAmount() - dropAmount, item.getNbt()));
|
||||
}
|
||||
return;
|
||||
} else { //clicking outside of inventory
|
||||
ClientWindowActionPacket dropPacket = new ClientWindowActionPacket(inventory.getId(), inventory.getTransactionId().getAndIncrement(),
|
||||
-999, null, WindowAction.CLICK_ITEM,
|
||||
dropAmount > 1 ? ClickItemParam.LEFT_CLICK : ClickItemParam.RIGHT_CLICK);
|
||||
session.getDownstream().getSession().send(dropPacket);
|
||||
ItemStack cursor = session.getInventory().getCursor();
|
||||
if (cursor != null) {
|
||||
session.getInventory().setCursor(new ItemStack(cursor.getId(), dropAmount > 1 ? 0 : cursor.getAmount() - 1, cursor.getNbt()));
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (cursorAction != null && containerAction != null) {
|
||||
//left/right click
|
||||
ClickPlan plan = new ClickPlan();
|
||||
int javaSlot = translator.bedrockSlotToJava(containerAction);
|
||||
if (cursorAction.getFromItem().equals(containerAction.getToItem())
|
||||
&& containerAction.getFromItem().equals(cursorAction.getToItem())
|
||||
&& !InventoryUtils.canStack(cursorAction.getFromItem(), containerAction.getFromItem())) { //simple swap
|
||||
plan.add(Click.LEFT, javaSlot);
|
||||
} else if (cursorAction.getFromItem().getCount() > cursorAction.getToItem().getCount()) { //release
|
||||
if (cursorAction.getToItem().getCount() == 0) {
|
||||
plan.add(Click.LEFT, javaSlot);
|
||||
} else {
|
||||
int difference = cursorAction.getFromItem().getCount() - cursorAction.getToItem().getCount();
|
||||
for (int i = 0; i < difference; i++) {
|
||||
plan.add(Click.RIGHT, javaSlot);
|
||||
}
|
||||
}
|
||||
} else { //pickup
|
||||
if (cursorAction.getFromItem().getCount() == 0) {
|
||||
if (containerAction.getToItem().getCount() == 0) { //pickup all
|
||||
plan.add(Click.LEFT, javaSlot);
|
||||
} else { //pickup some
|
||||
if (translator.getSlotType(javaSlot) == SlotType.FURNACE_OUTPUT
|
||||
|| containerAction.getToItem().getCount() == containerAction.getFromItem().getCount() / 2) { //right click
|
||||
plan.add(Click.RIGHT, javaSlot);
|
||||
} else {
|
||||
plan.add(Click.LEFT, javaSlot);
|
||||
int difference = containerAction.getFromItem().getCount() - cursorAction.getToItem().getCount();
|
||||
for (int i = 0; i < difference; i++) {
|
||||
plan.add(Click.RIGHT, javaSlot);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { //pickup into non-empty cursor
|
||||
if (translator.getSlotType(javaSlot) == SlotType.FURNACE_OUTPUT) {
|
||||
if (containerAction.getToItem().getCount() == 0) {
|
||||
plan.add(Click.LEFT, javaSlot);
|
||||
} else {
|
||||
ClientWindowActionPacket shiftClickPacket = new ClientWindowActionPacket(inventory.getId(),
|
||||
inventory.getTransactionId().getAndIncrement(),
|
||||
javaSlot, InventoryUtils.REFRESH_ITEM, WindowAction.SHIFT_CLICK_ITEM,
|
||||
ShiftClickItemParam.LEFT_CLICK);
|
||||
session.getDownstream().getSession().send(shiftClickPacket);
|
||||
translator.updateInventory(session, inventory);
|
||||
return;
|
||||
}
|
||||
} else if (translator.getSlotType(javaSlot) == SlotType.OUTPUT) {
|
||||
plan.add(Click.LEFT, javaSlot);
|
||||
} else {
|
||||
int cursorSlot = findTempSlot(inventory, session.getInventory().getCursor(), Collections.singletonList(javaSlot));
|
||||
if (cursorSlot != -1) {
|
||||
plan.add(Click.LEFT, cursorSlot);
|
||||
} else {
|
||||
translator.updateInventory(session, inventory);
|
||||
return;
|
||||
}
|
||||
plan.add(Click.LEFT, javaSlot);
|
||||
int difference = cursorAction.getToItem().getCount() - cursorAction.getFromItem().getCount();
|
||||
for (int i = 0; i < difference; i++) {
|
||||
plan.add(Click.RIGHT, cursorSlot);
|
||||
}
|
||||
plan.add(Click.LEFT, javaSlot);
|
||||
plan.add(Click.LEFT, cursorSlot);
|
||||
}
|
||||
}
|
||||
}
|
||||
plan.execute(session, translator, inventory, refresh);
|
||||
return;
|
||||
} else {
|
||||
ClickPlan plan = new ClickPlan();
|
||||
InventoryActionData fromAction;
|
||||
InventoryActionData toAction;
|
||||
if (actions.get(0).getFromItem().getCount() >= actions.get(0).getToItem().getCount()) {
|
||||
fromAction = actions.get(0);
|
||||
toAction = actions.get(1);
|
||||
} else {
|
||||
fromAction = actions.get(1);
|
||||
toAction = actions.get(0);
|
||||
}
|
||||
int fromSlot = translator.bedrockSlotToJava(fromAction);
|
||||
int toSlot = translator.bedrockSlotToJava(toAction);
|
||||
|
||||
if (translator.getSlotType(fromSlot) == SlotType.OUTPUT) {
|
||||
if ((craftSlot != 0 && craftSlot != -2) && (inventory.getItem(toSlot) == null
|
||||
|| InventoryUtils.canStack(session.getInventory().getCursor(), inventory.getItem(toSlot)))) {
|
||||
if (fromAction.getToItem().getCount() == 0) {
|
||||
refresh = true;
|
||||
plan.add(Click.LEFT, toSlot);
|
||||
if (craftSlot != -1) {
|
||||
plan.add(Click.LEFT, craftSlot);
|
||||
}
|
||||
} else {
|
||||
int difference = toAction.getToItem().getCount() - toAction.getFromItem().getCount();
|
||||
for (int i = 0; i < difference; i++) {
|
||||
plan.add(Click.RIGHT, toSlot);
|
||||
}
|
||||
session.setCraftSlot(craftSlot);
|
||||
}
|
||||
plan.execute(session, translator, inventory, refresh);
|
||||
return;
|
||||
} else {
|
||||
session.setCraftSlot(-2);
|
||||
}
|
||||
}
|
||||
|
||||
int cursorSlot = -1;
|
||||
if (session.getInventory().getCursor() != null) { //move cursor contents to a temporary slot
|
||||
cursorSlot = findTempSlot(inventory, session.getInventory().getCursor(), Arrays.asList(fromSlot, toSlot));
|
||||
if (cursorSlot != -1) {
|
||||
plan.add(Click.LEFT, cursorSlot);
|
||||
} else {
|
||||
translator.updateInventory(session, inventory);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if ((fromAction.getFromItem().equals(toAction.getToItem()) && !InventoryUtils.canStack(fromAction.getFromItem(), toAction.getFromItem()))
|
||||
|| fromAction.getToItem().getId() == 0) { //slot swap
|
||||
plan.add(Click.LEFT, fromSlot);
|
||||
plan.add(Click.LEFT, toSlot);
|
||||
if (fromAction.getToItem().getId() != 0) {
|
||||
plan.add(Click.LEFT, fromSlot);
|
||||
}
|
||||
} else if (InventoryUtils.canStack(fromAction.getFromItem(), toAction.getToItem())) { //partial item move
|
||||
if (translator.getSlotType(fromSlot) == SlotType.FURNACE_OUTPUT) {
|
||||
ClientWindowActionPacket shiftClickPacket = new ClientWindowActionPacket(inventory.getId(),
|
||||
inventory.getTransactionId().getAndIncrement(),
|
||||
fromSlot, InventoryUtils.REFRESH_ITEM, WindowAction.SHIFT_CLICK_ITEM,
|
||||
ShiftClickItemParam.LEFT_CLICK);
|
||||
session.getDownstream().getSession().send(shiftClickPacket);
|
||||
translator.updateInventory(session, inventory);
|
||||
return;
|
||||
} else if (translator.getSlotType(fromSlot) == SlotType.OUTPUT) {
|
||||
session.setCraftSlot(cursorSlot);
|
||||
plan.add(Click.LEFT, fromSlot);
|
||||
int difference = toAction.getToItem().getCount() - toAction.getFromItem().getCount();
|
||||
for (int i = 0; i < difference; i++) {
|
||||
plan.add(Click.RIGHT, toSlot);
|
||||
}
|
||||
//client will send additional packets later to finish transferring crafting output
|
||||
//translator will know how to handle this using the craftSlot variable
|
||||
} else {
|
||||
plan.add(Click.LEFT, fromSlot);
|
||||
int difference = toAction.getToItem().getCount() - toAction.getFromItem().getCount();
|
||||
for (int i = 0; i < difference; i++) {
|
||||
plan.add(Click.RIGHT, toSlot);
|
||||
}
|
||||
plan.add(Click.LEFT, fromSlot);
|
||||
}
|
||||
}
|
||||
if (cursorSlot != -1) {
|
||||
plan.add(Click.LEFT, cursorSlot);
|
||||
}
|
||||
plan.execute(session, translator, inventory, refresh);
|
||||
return;
|
||||
}
|
||||
|
||||
translator.updateInventory(session, inventory);
|
||||
InventoryUtils.updateCursor(session);
|
||||
}
|
||||
|
||||
private static int findTempSlot(Inventory inventory, ItemStack item, List<Integer> slotBlacklist) {
|
||||
/*try and find a slot that can temporarily store the given item
|
||||
only look in the main inventory and hotbar
|
||||
only slots that are empty or contain a different type of item are valid*/
|
||||
int offset = inventory.getId() == 0 ? 1 : 0; //offhand is not a viable slot (some servers disable it)
|
||||
List<ItemStack> itemBlacklist = new ArrayList<>(slotBlacklist.size() + 1);
|
||||
itemBlacklist.add(item);
|
||||
for (int slot : slotBlacklist) {
|
||||
ItemStack blacklistItem = inventory.getItem(slot);
|
||||
if (blacklistItem != null)
|
||||
itemBlacklist.add(blacklistItem);
|
||||
}
|
||||
for (int i = inventory.getSize() - (36 + offset); i < inventory.getSize() - offset; i++) {
|
||||
ItemStack testItem = inventory.getItem(i);
|
||||
boolean acceptable = true;
|
||||
if (testItem != null) {
|
||||
for (ItemStack blacklistItem : itemBlacklist) {
|
||||
if (InventoryUtils.canStack(testItem, blacklistItem)) {
|
||||
acceptable = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (acceptable && !slotBlacklist.contains(i))
|
||||
return i;
|
||||
}
|
||||
//could not find a viable temp slot
|
||||
return -1;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* 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.inventory.holder;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
||||
import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
|
||||
import com.nukkitx.math.vector.Vector3i;
|
||||
import com.nukkitx.nbt.tag.CompoundTag;
|
||||
import com.nukkitx.protocol.bedrock.data.ContainerType;
|
||||
import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.block.BlockTranslator;
|
||||
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class BlockInventoryHolder extends InventoryHolder {
|
||||
private final int blockId;
|
||||
private final ContainerType containerType;
|
||||
|
||||
@Override
|
||||
public void prepareInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) {
|
||||
Vector3i position = session.getPlayerEntity().getPosition().toInt();
|
||||
position = position.add(Vector3i.UP);
|
||||
UpdateBlockPacket blockPacket = new UpdateBlockPacket();
|
||||
blockPacket.setDataLayer(0);
|
||||
blockPacket.setBlockPosition(position);
|
||||
blockPacket.setRuntimeId(blockId);
|
||||
blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY);
|
||||
session.getUpstream().sendPacket(blockPacket);
|
||||
inventory.setHolderPosition(position);
|
||||
|
||||
CompoundTag tag = CompoundTag.builder()
|
||||
.intTag("x", position.getX())
|
||||
.intTag("y", position.getY())
|
||||
.intTag("z", position.getZ())
|
||||
.stringTag("CustomName", inventory.getTitle()).buildRootTag();
|
||||
BlockEntityDataPacket dataPacket = new BlockEntityDataPacket();
|
||||
dataPacket.setData(tag);
|
||||
dataPacket.setBlockPosition(position);
|
||||
session.getUpstream().sendPacket(dataPacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) {
|
||||
ContainerOpenPacket containerOpenPacket = new ContainerOpenPacket();
|
||||
containerOpenPacket.setWindowId((byte) inventory.getId());
|
||||
containerOpenPacket.setType((byte) containerType.id());
|
||||
containerOpenPacket.setBlockPosition(inventory.getHolderPosition());
|
||||
containerOpenPacket.setUniqueEntityId(inventory.getHolderId());
|
||||
session.getUpstream().sendPacket(containerOpenPacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) {
|
||||
Vector3i holderPos = inventory.getHolderPosition();
|
||||
Position pos = new Position(holderPos.getX(), holderPos.getY(), holderPos.getZ());
|
||||
BlockState realBlock = session.getChunkCache().getBlockAt(pos);
|
||||
UpdateBlockPacket blockPacket = new UpdateBlockPacket();
|
||||
blockPacket.setDataLayer(0);
|
||||
blockPacket.setBlockPosition(holderPos);
|
||||
blockPacket.setRuntimeId(BlockTranslator.getBedrockBlockId(realBlock));
|
||||
session.getUpstream().sendPacket(blockPacket);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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.inventory.holder;
|
||||
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
||||
|
||||
public abstract class InventoryHolder {
|
||||
public abstract void prepareInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory);
|
||||
public abstract void openInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory);
|
||||
public abstract void closeInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory);
|
||||
}
|
|
@ -23,38 +23,32 @@
|
|||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.network.translators.inventory;
|
||||
package org.geysermc.connector.network.translators.inventory.updater;
|
||||
|
||||
import com.nukkitx.math.vector.Vector3i;
|
||||
import com.nukkitx.protocol.bedrock.data.ItemData;
|
||||
import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.Translators;
|
||||
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
||||
|
||||
public class GenericInventoryTranslator extends InventoryTranslator {
|
||||
@AllArgsConstructor
|
||||
public class ChestInventoryUpdater extends InventoryUpdater {
|
||||
private final int paddedSize;
|
||||
|
||||
@Override
|
||||
public void prepareInventory(GeyserSession session, Inventory inventory) {
|
||||
// TODO: Add code here
|
||||
}
|
||||
public void updateInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) {
|
||||
super.updateInventory(translator, session, inventory);
|
||||
|
||||
@Override
|
||||
public void openInventory(GeyserSession session, Inventory inventory) {
|
||||
ContainerOpenPacket containerOpenPacket = new ContainerOpenPacket();
|
||||
containerOpenPacket.setWindowId((byte) inventory.getId());
|
||||
containerOpenPacket.setType((byte) 0);
|
||||
containerOpenPacket.setBlockPosition(Vector3i.ZERO);
|
||||
session.getUpstream().sendPacket(containerOpenPacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateInventory(GeyserSession session, Inventory inventory) {
|
||||
ItemData[] bedrockItems = new ItemData[inventory.getItems().length];
|
||||
ItemData[] bedrockItems = new ItemData[paddedSize];
|
||||
for (int i = 0; i < bedrockItems.length; i++) {
|
||||
bedrockItems[i] = Translators.getItemTranslator().translateToBedrock(inventory.getItems()[i]);
|
||||
if (i <= translator.size) {
|
||||
bedrockItems[i] = Translators.getItemTranslator().translateToBedrock(inventory.getItem(i));
|
||||
} else {
|
||||
bedrockItems[i] = ItemData.AIR;
|
||||
}
|
||||
}
|
||||
|
||||
InventoryContentPacket contentPacket = new InventoryContentPacket();
|
||||
|
@ -64,11 +58,15 @@ public class GenericInventoryTranslator extends InventoryTranslator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void updateSlot(GeyserSession session, Inventory inventory, int slot) {
|
||||
public boolean updateSlot(InventoryTranslator translator, GeyserSession session, Inventory inventory, int javaSlot) {
|
||||
if (super.updateSlot(translator, session, inventory, javaSlot))
|
||||
return true;
|
||||
|
||||
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
||||
slotPacket.setContainerId(inventory.getId());
|
||||
slotPacket.setItem(Translators.getItemTranslator().translateToBedrock(inventory.getItems()[slot]));
|
||||
slotPacket.setSlot(slot);
|
||||
slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot));
|
||||
slotPacket.setItem(Translators.getItemTranslator().translateToBedrock(inventory.getItem(javaSlot)));
|
||||
session.getUpstream().sendPacket(slotPacket);
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* 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.inventory.updater;
|
||||
|
||||
import com.nukkitx.protocol.bedrock.data.ItemData;
|
||||
import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.Translators;
|
||||
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
||||
|
||||
public class ContainerInventoryUpdater extends InventoryUpdater {
|
||||
@Override
|
||||
public void updateInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) {
|
||||
super.updateInventory(translator, session, inventory);
|
||||
|
||||
ItemData[] bedrockItems = new ItemData[translator.size];
|
||||
for (int i = 0; i < bedrockItems.length; i++) {
|
||||
bedrockItems[translator.javaSlotToBedrock(i)] = Translators.getItemTranslator().translateToBedrock(inventory.getItem(i));
|
||||
}
|
||||
|
||||
InventoryContentPacket contentPacket = new InventoryContentPacket();
|
||||
contentPacket.setContainerId(inventory.getId());
|
||||
contentPacket.setContents(bedrockItems);
|
||||
session.getUpstream().sendPacket(contentPacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateSlot(InventoryTranslator translator, GeyserSession session, Inventory inventory, int javaSlot) {
|
||||
if (super.updateSlot(translator, session, inventory, javaSlot))
|
||||
return true;
|
||||
|
||||
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
||||
slotPacket.setContainerId(inventory.getId());
|
||||
slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot));
|
||||
slotPacket.setItem(Translators.getItemTranslator().translateToBedrock(inventory.getItem(javaSlot)));
|
||||
session.getUpstream().sendPacket(slotPacket);
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* 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.inventory.updater;
|
||||
|
||||
import com.nukkitx.protocol.bedrock.data.ContainerId;
|
||||
import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.Translators;
|
||||
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
||||
|
||||
public class CursorInventoryUpdater extends InventoryUpdater {
|
||||
@Override
|
||||
public void updateInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) {
|
||||
super.updateInventory(translator, session, inventory);
|
||||
|
||||
for (int i = 0; i < translator.size; i++) {
|
||||
final int bedrockSlot = translator.javaSlotToBedrock(i);
|
||||
if (bedrockSlot == 50)
|
||||
continue;
|
||||
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
||||
slotPacket.setContainerId(ContainerId.CURSOR);
|
||||
slotPacket.setSlot(bedrockSlot);
|
||||
slotPacket.setItem(Translators.getItemTranslator().translateToBedrock(inventory.getItem(i)));
|
||||
session.getUpstream().sendPacket(slotPacket);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateSlot(InventoryTranslator translator, GeyserSession session, Inventory inventory, int javaSlot) {
|
||||
if (super.updateSlot(translator, session, inventory, javaSlot))
|
||||
return true;
|
||||
|
||||
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
||||
slotPacket.setContainerId(ContainerId.CURSOR);
|
||||
slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot));
|
||||
slotPacket.setItem(Translators.getItemTranslator().translateToBedrock(inventory.getItem(javaSlot)));
|
||||
session.getUpstream().sendPacket(slotPacket);
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -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.inventory.updater;
|
||||
|
||||
import com.nukkitx.protocol.bedrock.data.ContainerId;
|
||||
import com.nukkitx.protocol.bedrock.data.ItemData;
|
||||
import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.Translators;
|
||||
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
||||
|
||||
public abstract class InventoryUpdater {
|
||||
public void updateInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) {
|
||||
ItemData[] bedrockItems = new ItemData[36];
|
||||
for (int i = 0; i < 36; i++) {
|
||||
final int offset = i < 9 ? 27 : -9;
|
||||
bedrockItems[i] = Translators.getItemTranslator().translateToBedrock(inventory.getItem(translator.size + i + offset));
|
||||
}
|
||||
InventoryContentPacket contentPacket = new InventoryContentPacket();
|
||||
contentPacket.setContainerId(ContainerId.INVENTORY);
|
||||
contentPacket.setContents(bedrockItems);
|
||||
session.getUpstream().sendPacket(contentPacket);
|
||||
}
|
||||
|
||||
public boolean updateSlot(InventoryTranslator translator, GeyserSession session, Inventory inventory, int javaSlot) {
|
||||
if (javaSlot >= translator.size) {
|
||||
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
||||
slotPacket.setContainerId(ContainerId.INVENTORY);
|
||||
slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot));
|
||||
slotPacket.setItem(Translators.getItemTranslator().translateToBedrock(inventory.getItem(javaSlot)));
|
||||
session.getUpstream().sendPacket(slotPacket);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
@Getter
|
||||
enum Enchantment {
|
||||
PROTECTION,
|
||||
FIRE_PROTECTION,
|
||||
FEATHER_FALLING,
|
||||
BLAST_PROTECTION,
|
||||
PROJECTILE_PROTECTION,
|
||||
THORNS,
|
||||
RESPIRATION,
|
||||
DEPTH_STRIDER,
|
||||
AQUA_AFFINITY,
|
||||
SHARPNESS,
|
||||
SMITE,
|
||||
BANE_OF_ARTHROPODS,
|
||||
KNOCKBACK,
|
||||
FIRE_ASPECT,
|
||||
LOOTING,
|
||||
EFFICIENCY,
|
||||
SILK_TOUCH,
|
||||
UNBREAKING,
|
||||
FORTUNE,
|
||||
POWER,
|
||||
PUNCH,
|
||||
FLAME,
|
||||
INFINITY,
|
||||
LUCK_OF_THE_SEA,
|
||||
LURE,
|
||||
FROST_WALKER,
|
||||
MENDING,
|
||||
BINDING_CURSE,
|
||||
VANISHING_CURSE,
|
||||
IMPALING,
|
||||
RIPTIDE,
|
||||
LOYALTY,
|
||||
CHANNELING,
|
||||
MULTISHOT,
|
||||
PIERCING,
|
||||
QUICK_CHARGE;
|
||||
|
||||
private final String javaIdentifier;
|
||||
|
||||
Enchantment() {
|
||||
this.javaIdentifier = "minecraft:" + this.name().toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
public static Enchantment getByJavaIdentifier(String javaIdentifier) {
|
||||
for (Enchantment enchantment : Enchantment.values()) {
|
||||
if (enchantment.javaIdentifier.equals(javaIdentifier)) {
|
||||
return enchantment;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Enchantment getByBedrockId(int bedrockId) {
|
||||
if (bedrockId >= 0 && bedrockId < Enchantment.values().length) {
|
||||
return Enchantment.values()[bedrockId];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -34,11 +34,11 @@ public class ItemEntry {
|
|||
|
||||
public static ItemEntry AIR = new ItemEntry("minecraft:air", 0, 0, 0);
|
||||
|
||||
private String javaIdentifier;
|
||||
private int javaId;
|
||||
private final String javaIdentifier;
|
||||
private final int javaId;
|
||||
|
||||
private int bedrockId;
|
||||
private int bedrockData;
|
||||
private final int bedrockId;
|
||||
private final int bedrockData;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
|
|
@ -43,6 +43,7 @@ import com.github.steveice10.opennbt.tag.builtin.Tag;
|
|||
import com.nukkitx.protocol.bedrock.data.ItemData;
|
||||
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
|
||||
import org.geysermc.connector.utils.MessageUtils;
|
||||
import org.geysermc.connector.utils.Toolbox;
|
||||
|
||||
|
@ -53,24 +54,45 @@ import java.util.Map;
|
|||
|
||||
public class ItemTranslator {
|
||||
|
||||
private Map<String, ItemEntry> javaIdentifierMap = new HashMap<>();
|
||||
|
||||
public ItemStack translateToJava(ItemData data) {
|
||||
ItemEntry javaItem = getItem(data);
|
||||
|
||||
if (data.getTag() == null) {
|
||||
return new ItemStack(javaItem.getJavaId(), data.getCount());
|
||||
} else if (javaItem.getJavaIdentifier().equals("minecraft:enchanted_book")) {
|
||||
CompoundTag javaTag = translateToJavaNBT(data.getTag());
|
||||
Map<String, Tag> javaValue = javaTag.getValue();
|
||||
Tag enchTag = javaValue.get("Enchantments");
|
||||
if (enchTag instanceof ListTag) {
|
||||
enchTag = new ListTag("StoredEnchantments", ((ListTag) enchTag).getValue());
|
||||
javaValue.remove("Enchantments");
|
||||
javaValue.put("StoredEnchantments", enchTag);
|
||||
javaTag.setValue(javaValue);
|
||||
}
|
||||
return new ItemStack(javaItem.getJavaId(), data.getCount(), javaTag);
|
||||
}
|
||||
return new ItemStack(javaItem.getJavaId(), data.getCount(), translateToJavaNBT(data.getTag()));
|
||||
}
|
||||
|
||||
public ItemData translateToBedrock(ItemStack stack) {
|
||||
// Most likely dirt if null
|
||||
if (stack == null) {
|
||||
return ItemData.of(3, (short)0, 0);
|
||||
return ItemData.AIR;
|
||||
}
|
||||
|
||||
ItemEntry bedrockItem = getItem(stack);
|
||||
if (stack.getNbt() == null) {
|
||||
return ItemData.of(bedrockItem.getBedrockId(), (short) bedrockItem.getBedrockData(), stack.getAmount());
|
||||
} else if (bedrockItem.getJavaIdentifier().endsWith("potion")) {
|
||||
Tag potionTag = stack.getNbt().get("Potion");
|
||||
if (potionTag instanceof StringTag) {
|
||||
Potion potion = Potion.getByJavaIdentifier(((StringTag) potionTag).getValue());
|
||||
if (potion != null) {
|
||||
return ItemData.of(bedrockItem.getBedrockId(), potion.getBedrockId(), stack.getAmount(), translateToBedrockNBT(stack.getNbt()));
|
||||
}
|
||||
GeyserConnector.getInstance().getLogger().debug("Unknown java potion: " + potionTag.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Create proper transformers instead of shoving everything here
|
||||
|
@ -92,7 +114,14 @@ public class ItemTranslator {
|
|||
|
||||
public ItemEntry getItem(ItemData data) {
|
||||
for (ItemEntry itemEntry : Toolbox.ITEM_ENTRIES.values()) {
|
||||
if (itemEntry.getBedrockId() == data.getId() && itemEntry.getBedrockData() == data.getDamage()) {
|
||||
if (itemEntry.getBedrockId() == data.getId() && (itemEntry.getBedrockData() == data.getDamage() || itemEntry.getJavaIdentifier().endsWith("potion"))) {
|
||||
return itemEntry;
|
||||
}
|
||||
}
|
||||
// If item find was unsuccessful first time, we try again while ignoring damage
|
||||
// Fixes piston, sticky pistons, dispensers and droppers turning into air from creative inventory
|
||||
for (ItemEntry itemEntry : Toolbox.ITEM_ENTRIES.values()) {
|
||||
if (itemEntry.getBedrockId() == data.getId()) {
|
||||
return itemEntry;
|
||||
}
|
||||
}
|
||||
|
@ -101,6 +130,11 @@ public class ItemTranslator {
|
|||
return ItemEntry.AIR;
|
||||
}
|
||||
|
||||
public ItemEntry getItemEntry(String javaIdentifier) {
|
||||
return javaIdentifierMap.computeIfAbsent(javaIdentifier, key -> Toolbox.ITEM_ENTRIES.values()
|
||||
.stream().filter(itemEntry -> itemEntry.getJavaIdentifier().equals(key)).findFirst().orElse(null));
|
||||
}
|
||||
|
||||
private CompoundTag translateToJavaNBT(com.nukkitx.nbt.tag.CompoundTag tag) {
|
||||
CompoundTag javaTag = new CompoundTag(tag.getName());
|
||||
Map<String, Tag> javaValue = javaTag.getValue();
|
||||
|
@ -111,10 +145,11 @@ public class ItemTranslator {
|
|||
if (translatedTag == null)
|
||||
continue;
|
||||
|
||||
javaValue.put(str, translatedTag);
|
||||
javaValue.put(translatedTag.getName(), translatedTag);
|
||||
}
|
||||
}
|
||||
|
||||
javaTag.setValue(javaValue);
|
||||
return javaTag;
|
||||
}
|
||||
|
||||
|
@ -173,6 +208,29 @@ public class ItemTranslator {
|
|||
com.nukkitx.nbt.tag.ListTag listTag = (com.nukkitx.nbt.tag.ListTag) tag;
|
||||
|
||||
List<Tag> tags = new ArrayList<>();
|
||||
|
||||
if (tag.getName().equals("ench")) {
|
||||
for (Object value : listTag.getValue()) {
|
||||
if (!(value instanceof com.nukkitx.nbt.tag.CompoundTag))
|
||||
continue;
|
||||
|
||||
com.nukkitx.nbt.tag.CompoundTag tagValue = (com.nukkitx.nbt.tag.CompoundTag) value;
|
||||
int bedrockId = tagValue.getShort("id", (short) -1);
|
||||
Enchantment enchantment = Enchantment.getByBedrockId(bedrockId);
|
||||
if (enchantment != null) {
|
||||
CompoundTag javaTag = new CompoundTag("");
|
||||
Map<String, Tag> javaValue = javaTag.getValue();
|
||||
javaValue.put("id", new StringTag("id", enchantment.getJavaIdentifier()));
|
||||
javaValue.put("lvl", new IntTag("lvl", tagValue.getShort("lvl", (short) 1)));
|
||||
javaTag.setValue(javaValue);
|
||||
tags.add(javaTag);
|
||||
} else {
|
||||
GeyserConnector.getInstance().getLogger().debug("Unknown bedrock enchantment: " + bedrockId);
|
||||
}
|
||||
}
|
||||
return new ListTag("Enchantments", tags);
|
||||
}
|
||||
|
||||
for (Object value : listTag.getValue()) {
|
||||
if (!(value instanceof com.nukkitx.nbt.tag.Tag))
|
||||
continue;
|
||||
|
@ -201,7 +259,7 @@ public class ItemTranslator {
|
|||
if (translatedTag == null)
|
||||
continue;
|
||||
|
||||
javaValue.put(str, translatedTag);
|
||||
javaValue.put(translatedTag.getName(), translatedTag);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -262,7 +320,33 @@ public class ItemTranslator {
|
|||
|
||||
if (tag instanceof ListTag) {
|
||||
ListTag listTag = (ListTag) tag;
|
||||
if (listTag.getName().equalsIgnoreCase("Lore")) {
|
||||
if (listTag.getName().equalsIgnoreCase("Enchantments") || listTag.getName().equalsIgnoreCase("StoredEnchantments")) {
|
||||
List<com.nukkitx.nbt.tag.CompoundTag> tags = new ArrayList<>();
|
||||
for (Object value : listTag.getValue()) {
|
||||
if (!(value instanceof CompoundTag))
|
||||
continue;
|
||||
|
||||
Tag javaEnchLvl = ((CompoundTag) value).get("lvl");
|
||||
if (!(javaEnchLvl instanceof ShortTag))
|
||||
continue;
|
||||
|
||||
Tag javaEnchId = ((CompoundTag) value).get("id");
|
||||
if (!(javaEnchId instanceof StringTag))
|
||||
continue;
|
||||
|
||||
Enchantment enchantment = Enchantment.getByJavaIdentifier(((StringTag) javaEnchId).getValue());
|
||||
if (enchantment == null) {
|
||||
GeyserConnector.getInstance().getLogger().debug("Unknown java enchantment: " + javaEnchId.getValue());
|
||||
continue;
|
||||
}
|
||||
|
||||
com.nukkitx.nbt.CompoundTagBuilder builder = com.nukkitx.nbt.tag.CompoundTag.EMPTY.toBuilder();
|
||||
builder.shortTag("lvl", ((ShortTag) javaEnchLvl).getValue());
|
||||
builder.shortTag("id", (short) enchantment.ordinal());
|
||||
tags.add(builder.buildRootTag());
|
||||
}
|
||||
return new com.nukkitx.nbt.tag.ListTag<>("ench", com.nukkitx.nbt.tag.CompoundTag.class, tags);
|
||||
} else if (listTag.getName().equalsIgnoreCase("Lore")) {
|
||||
List<com.nukkitx.nbt.tag.StringTag> tags = new ArrayList<>();
|
||||
for (Object value : listTag.getValue()) {
|
||||
if (!(value instanceof Tag))
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
@Getter
|
||||
enum Potion {
|
||||
WATER(0),
|
||||
MUNDANE(1),
|
||||
THICK(3),
|
||||
AWKWARD(4),
|
||||
NIGHT_VISION(5),
|
||||
LONG_NIGHT_VISION(6),
|
||||
INVISIBILITY(7),
|
||||
LONG_INVISIBILITY(8),
|
||||
LEAPING(9),
|
||||
STRONG_LEAPING(11),
|
||||
LONG_LEAPING(10),
|
||||
FIRE_RESISTANCE(12),
|
||||
LONG_FIRE_RESISTANCE(13),
|
||||
SWIFTNESS(14),
|
||||
STRONG_SWIFTNESS(16),
|
||||
LONG_SWIFTNESS(15),
|
||||
SLOWNESS(17),
|
||||
STRONG_SLOWNESS(18), //does not exist
|
||||
LONG_SLOWNESS(18),
|
||||
WATER_BREATHING(19),
|
||||
LONG_WATER_BREATHING(20),
|
||||
HEALING(21),
|
||||
STRONG_HEALING(22),
|
||||
HARMING(23),
|
||||
STRONG_HARMING(24),
|
||||
POISON(25),
|
||||
STRONG_POISON(27),
|
||||
LONG_POISON(26),
|
||||
REGENERATION(28),
|
||||
STRONG_REGENERATION(30),
|
||||
LONG_REGENERATION(29),
|
||||
STRENGTH(31),
|
||||
STRONG_STRENGTH(33),
|
||||
LONG_STRENGTH(32),
|
||||
WEAKNESS(34),
|
||||
LONG_WEAKNESS(35),
|
||||
LUCK(2), //does not exist
|
||||
TURTLE_MASTER(37),
|
||||
STRONG_TURTLE_MASTER(39),
|
||||
LONG_TURTLE_MASTER(38),
|
||||
SLOW_FALLING(40),
|
||||
LONG_SLOW_FALLING(41);
|
||||
|
||||
private final String javaIdentifier;
|
||||
private final short bedrockId;
|
||||
|
||||
Potion(int bedrockId) {
|
||||
this.javaIdentifier = "minecraft:" + this.name().toLowerCase(Locale.ENGLISH);
|
||||
this.bedrockId = (short) bedrockId;
|
||||
}
|
||||
|
||||
public static Potion getByJavaIdentifier(String javaIdentifier) {
|
||||
for (Potion potion : Potion.values()) {
|
||||
if (potion.javaIdentifier.equals(javaIdentifier)) {
|
||||
return potion;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Potion getByBedrockId(short bedrockId) {
|
||||
for (Potion potion : Potion.values()) {
|
||||
if (potion.bedrockId == bedrockId) {
|
||||
return potion;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package org.geysermc.connector.network.translators.item;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class ToolItemEntry extends ItemEntry {
|
||||
private final String toolType;
|
||||
private final String toolTier;
|
||||
|
||||
public ToolItemEntry(String javaIdentifier, int javaId, int bedrockId, int bedrockData, String toolType, String toolTier) {
|
||||
super(javaIdentifier, javaId, bedrockId, bedrockData);
|
||||
this.toolType = toolType;
|
||||
this.toolTier = toolTier;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* 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.java;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.recipe.Ingredient;
|
||||
import com.github.steveice10.mc.protocol.data.game.recipe.Recipe;
|
||||
import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapedRecipeData;
|
||||
import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapelessRecipeData;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.ServerDeclareRecipesPacket;
|
||||
import com.nukkitx.nbt.tag.CompoundTag;
|
||||
import com.nukkitx.protocol.bedrock.data.CraftingData;
|
||||
import com.nukkitx.protocol.bedrock.data.ItemData;
|
||||
import com.nukkitx.protocol.bedrock.data.PotionMixData;
|
||||
import com.nukkitx.protocol.bedrock.packet.CraftingDataPacket;
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.EqualsAndHashCode;
|
||||
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.network.translators.Translators;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
import org.geysermc.connector.utils.Toolbox;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Translator(packet = ServerDeclareRecipesPacket.class)
|
||||
public class JavaDeclareRecipesTranslator extends PacketTranslator<ServerDeclareRecipesPacket> {
|
||||
private static final Collection<PotionMixData> POTION_MIXES =
|
||||
Arrays.stream(new int[]{372, 331, 348, 376, 289, 437, 353, 414, 382, 375, 462, 378, 396, 377, 370, 469, 470})
|
||||
.mapToObj(ingredient -> new PotionMixData(0, ingredient, 0))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
@Override
|
||||
public void translate(ServerDeclareRecipesPacket packet, GeyserSession session) {
|
||||
CraftingDataPacket craftingDataPacket = new CraftingDataPacket();
|
||||
craftingDataPacket.setCleanRecipes(true);
|
||||
for (Recipe recipe : packet.getRecipes()) {
|
||||
switch (recipe.getType()) {
|
||||
case CRAFTING_SHAPELESS: {
|
||||
ShapelessRecipeData shapelessRecipeData = (ShapelessRecipeData) recipe.getData();
|
||||
ItemData output = Translators.getItemTranslator().translateToBedrock(shapelessRecipeData.getResult());
|
||||
output = ItemData.of(output.getId(), output.getDamage(), output.getCount()); //strip NBT
|
||||
ItemData[][] inputCombinations = combinations(shapelessRecipeData.getIngredients());
|
||||
for (ItemData[] inputs : inputCombinations) {
|
||||
UUID uuid = UUID.randomUUID();
|
||||
craftingDataPacket.getCraftingData().add(CraftingData.fromShapeless(uuid.toString(),
|
||||
inputs, new ItemData[]{output}, uuid, "crafting_table", 0));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CRAFTING_SHAPED: {
|
||||
ShapedRecipeData shapedRecipeData = (ShapedRecipeData) recipe.getData();
|
||||
ItemData output = Translators.getItemTranslator().translateToBedrock(shapedRecipeData.getResult());
|
||||
output = ItemData.of(output.getId(), output.getDamage(), output.getCount()); //strip NBT
|
||||
ItemData[][] inputCombinations = combinations(shapedRecipeData.getIngredients());
|
||||
for (ItemData[] inputs : inputCombinations) {
|
||||
UUID uuid = UUID.randomUUID();
|
||||
craftingDataPacket.getCraftingData().add(CraftingData.fromShaped(uuid.toString(),
|
||||
shapedRecipeData.getWidth(), shapedRecipeData.getHeight(), inputs,
|
||||
new ItemData[]{output}, uuid, "crafting_table", 0));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
craftingDataPacket.getPotionMixData().addAll(POTION_MIXES);
|
||||
session.getUpstream().sendPacket(craftingDataPacket);
|
||||
}
|
||||
|
||||
//TODO: rewrite
|
||||
private ItemData[][] combinations(Ingredient[] ingredients) {
|
||||
Map<Set<ItemData>, IntSet> squashedOptions = new HashMap<>();
|
||||
for (int i = 0; i < ingredients.length; i++) {
|
||||
if (ingredients[i].getOptions().length == 0) {
|
||||
squashedOptions.computeIfAbsent(Collections.singleton(ItemData.AIR), k -> new IntOpenHashSet()).add(i);
|
||||
continue;
|
||||
}
|
||||
Ingredient ingredient = ingredients[i];
|
||||
Map<GroupedItem, List<ItemData>> groupedByIds = Arrays.stream(ingredient.getOptions())
|
||||
.map(item -> Translators.getItemTranslator().translateToBedrock(item))
|
||||
.collect(Collectors.groupingBy(item -> new GroupedItem(item.getId(), item.getCount(), item.getTag())));
|
||||
Set<ItemData> optionSet = new HashSet<>(groupedByIds.size());
|
||||
for (Map.Entry<GroupedItem, List<ItemData>> entry : groupedByIds.entrySet()) {
|
||||
if (entry.getValue().size() > 1) {
|
||||
GroupedItem groupedItem = entry.getKey();
|
||||
int idCount = 0;
|
||||
//not optimal
|
||||
for (ItemEntry itemEntry : Toolbox.ITEM_ENTRIES.values()) {
|
||||
if (itemEntry.getBedrockId() == groupedItem.id) {
|
||||
idCount++;
|
||||
}
|
||||
}
|
||||
if (entry.getValue().size() < idCount) {
|
||||
optionSet.addAll(entry.getValue());
|
||||
} else {
|
||||
optionSet.add(ItemData.of(groupedItem.id, (short) -1, groupedItem.count, groupedItem.tag));
|
||||
}
|
||||
} else {
|
||||
ItemData item = entry.getValue().get(0);
|
||||
optionSet.add(item);
|
||||
}
|
||||
}
|
||||
squashedOptions.computeIfAbsent(optionSet, k -> new IntOpenHashSet()).add(i);
|
||||
}
|
||||
int totalCombinations = 1;
|
||||
for (Set optionSet : squashedOptions.keySet()) {
|
||||
totalCombinations *= optionSet.size();
|
||||
}
|
||||
if (totalCombinations > 500) {
|
||||
ItemData[] translatedItems = new ItemData[ingredients.length];
|
||||
for (int i = 0; i < ingredients.length; i++) {
|
||||
if (ingredients[i].getOptions().length > 0) {
|
||||
translatedItems[i] = Translators.getItemTranslator().translateToBedrock(ingredients[i].getOptions()[0]);
|
||||
} else {
|
||||
translatedItems[i] = ItemData.AIR;
|
||||
}
|
||||
}
|
||||
return new ItemData[][]{translatedItems};
|
||||
}
|
||||
List<Set<ItemData>> sortedSets = new ArrayList<>(squashedOptions.keySet());
|
||||
sortedSets.sort(Comparator.comparing(Set::size, Comparator.reverseOrder()));
|
||||
ItemData[][] combinations = new ItemData[totalCombinations][ingredients.length];
|
||||
int x = 1;
|
||||
for (Set<ItemData> set : sortedSets) {
|
||||
IntSet slotSet = squashedOptions.get(set);
|
||||
int i = 0;
|
||||
for (ItemData item : set) {
|
||||
for (int j = 0; j < totalCombinations / set.size(); j++) {
|
||||
final int comboIndex = (i * x) + (j % x) + ((j / x) * set.size() * x);
|
||||
for (int slot : slotSet) {
|
||||
combinations[comboIndex][slot] = item;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
x *= set.size();
|
||||
}
|
||||
return combinations;
|
||||
}
|
||||
|
||||
@EqualsAndHashCode
|
||||
@AllArgsConstructor
|
||||
private static class GroupedItem {
|
||||
int id;
|
||||
int count;
|
||||
CompoundTag tag;
|
||||
}
|
||||
}
|
|
@ -53,6 +53,8 @@ public class JavaRespawnTranslator extends PacketTranslator<ServerRespawnPacket>
|
|||
// Max health must be divisible by two in bedrock
|
||||
entity.getAttributes().put(AttributeType.HEALTH, AttributeType.HEALTH.getAttribute(maxHealth, (maxHealth % 2 == 1 ? maxHealth + 1 : maxHealth)));
|
||||
|
||||
session.getInventoryCache().setOpenInventory(null);
|
||||
|
||||
SetPlayerGameTypePacket playerGameTypePacket = new SetPlayerGameTypePacket();
|
||||
playerGameTypePacket.setGamemode(packet.getGamemode().ordinal());
|
||||
session.getUpstream().sendPacket(playerGameTypePacket);
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
package org.geysermc.connector.network.translators.java.entity;
|
||||
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.entity.PlayerEntity;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
|
@ -42,6 +43,7 @@ public class JavaEntityEffectTranslator extends PacketTranslator<ServerEntityEff
|
|||
Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
|
||||
if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
|
||||
entity = session.getPlayerEntity();
|
||||
((PlayerEntity) entity).getEffectCache().addEffect(packet.getEffect(), packet.getAmplifier());
|
||||
}
|
||||
if (entity == null)
|
||||
return;
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
package org.geysermc.connector.network.translators.java.entity;
|
||||
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.entity.PlayerEntity;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
|
@ -42,6 +43,7 @@ public class JavaEntityRemoveEffectTranslator extends PacketTranslator<ServerEnt
|
|||
Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
|
||||
if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
|
||||
entity = session.getPlayerEntity();
|
||||
((PlayerEntity) entity).getEffectCache().removeEffect(packet.getEffect());
|
||||
}
|
||||
if (entity == null)
|
||||
return;
|
||||
|
|
|
@ -25,22 +25,64 @@
|
|||
|
||||
package org.geysermc.connector.network.translators.java.entity.player;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.player.ServerPlayerActionAckPacket;
|
||||
import com.github.steveice10.opennbt.tag.builtin.*;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.LevelEventType;
|
||||
import com.nukkitx.protocol.bedrock.packet.LevelEventPacket;
|
||||
import org.geysermc.connector.inventory.PlayerInventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translators;
|
||||
import org.geysermc.connector.network.translators.block.BlockTranslator;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
import org.geysermc.connector.utils.BlockUtils;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
import org.geysermc.connector.utils.ChunkUtils;
|
||||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.player.ServerPlayerActionAckPacket;
|
||||
|
||||
@Translator(packet = ServerPlayerActionAckPacket.class)
|
||||
public class JavaPlayerActionAckTranslator extends PacketTranslator<ServerPlayerActionAckPacket> {
|
||||
|
||||
@Override
|
||||
public void translate(ServerPlayerActionAckPacket packet, GeyserSession session) {
|
||||
LevelEventPacket levelEvent = new LevelEventPacket();
|
||||
switch (packet.getAction()) {
|
||||
case FINISH_DIGGING:
|
||||
ChunkUtils.updateBlock(session, packet.getNewState(), packet.getPosition());
|
||||
break;
|
||||
|
||||
case START_DIGGING:
|
||||
levelEvent.setType(LevelEventType.BLOCK_START_BREAK);
|
||||
levelEvent.setPosition(Vector3f.from(
|
||||
packet.getPosition().getX(),
|
||||
packet.getPosition().getY(),
|
||||
packet.getPosition().getZ()
|
||||
));
|
||||
double blockHardness = BlockTranslator.JAVA_RUNTIME_ID_TO_HARDNESS.get(packet.getNewState().getId());
|
||||
PlayerInventory inventory = session.getInventory();
|
||||
ItemStack item = inventory.getItemInHand();
|
||||
ItemEntry itemEntry = null;
|
||||
CompoundTag nbtData = new CompoundTag("");
|
||||
if (item != null) {
|
||||
itemEntry = Translators.getItemTranslator().getItem(item);
|
||||
nbtData = item.getNbt();
|
||||
}
|
||||
double breakTime = Math.ceil(BlockUtils.getBreakTime(blockHardness, packet.getNewState().getId(), itemEntry, nbtData, session.getPlayerEntity()) * 20);
|
||||
levelEvent.setData((int) (65535 / breakTime));
|
||||
session.getUpstream().sendPacket(levelEvent);
|
||||
break;
|
||||
|
||||
case CANCEL_DIGGING:
|
||||
levelEvent.setType(LevelEventType.BLOCK_STOP_BREAK);
|
||||
levelEvent.setPosition(Vector3f.from(
|
||||
packet.getPosition().getX(),
|
||||
packet.getPosition().getY(),
|
||||
packet.getPosition().getZ()
|
||||
));
|
||||
levelEvent.setData(0);
|
||||
session.getUpstream().sendPacket(levelEvent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* 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.java.entity.player;
|
||||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.player.ServerPlayerChangeHeldItemPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.PlayerHotbarPacket;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
|
||||
@Translator(packet = ServerPlayerChangeHeldItemPacket.class)
|
||||
public class JavaPlayerChangeHeldItemTranslator extends PacketTranslator<ServerPlayerChangeHeldItemPacket> {
|
||||
|
||||
@Override
|
||||
public void translate(ServerPlayerChangeHeldItemPacket packet, GeyserSession session) {
|
||||
PlayerHotbarPacket hotbarPacket = new PlayerHotbarPacket();
|
||||
hotbarPacket.setContainerId(0);
|
||||
hotbarPacket.setSelectedHotbarSlot(packet.getSlot());
|
||||
hotbarPacket.setSelectHotbarSlot(true);
|
||||
session.getUpstream().sendPacket(hotbarPacket);
|
||||
|
||||
session.getInventory().setHeldItemSlot(packet.getSlot());
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
package org.geysermc.connector.network.translators.java.inventory;
|
||||
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
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.network.translators.Translators;
|
||||
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
||||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerOpenWindowPacket;
|
||||
|
||||
@Translator(packet = ServerOpenWindowPacket.class)
|
||||
public class OpenWindowPacketTranslator extends PacketTranslator<ServerOpenWindowPacket> {
|
||||
@Override
|
||||
public void translate(ServerOpenWindowPacket packet, GeyserSession session) {
|
||||
System.out.println("debug: " + packet.getType());
|
||||
InventoryTranslator translator = Translators.getInventoryTranslator();
|
||||
|
||||
translator.openInventory(session, new Inventory(packet.getName(), packet.getWindowId(), packet.getType(), 54));
|
||||
|
||||
}
|
||||
}
|
|
@ -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.java.window;
|
||||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerCloseWindowPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.ContainerClosePacket;
|
||||
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.InventoryUtils;
|
||||
|
||||
@Translator(packet = ServerCloseWindowPacket.class)
|
||||
public class JavaCloseWindowTranslator extends PacketTranslator<ServerCloseWindowPacket> {
|
||||
|
||||
@Override
|
||||
public void translate(ServerCloseWindowPacket packet, GeyserSession session) {
|
||||
ContainerClosePacket closePacket = new ContainerClosePacket();
|
||||
closePacket.setWindowId((byte)packet.getWindowId());
|
||||
session.getUpstream().sendPacket(closePacket);
|
||||
InventoryUtils.closeInventory(session, packet.getWindowId());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* 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.java.window;
|
||||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientConfirmTransactionPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerConfirmTransactionPacket;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
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.network.translators.inventory.InventoryTranslator;
|
||||
import org.geysermc.connector.utils.InventoryUtils;
|
||||
|
||||
@Translator(packet = ServerConfirmTransactionPacket.class)
|
||||
public class JavaConfirmTransactionTranslator extends PacketTranslator<ServerConfirmTransactionPacket> {
|
||||
|
||||
@Override
|
||||
public void translate(ServerConfirmTransactionPacket packet, GeyserSession session) {
|
||||
if (!packet.isAccepted()) {
|
||||
ClientConfirmTransactionPacket confirmPacket = new ClientConfirmTransactionPacket(packet.getWindowId(), packet.getActionId(), true);
|
||||
session.getDownstream().getSession().send(confirmPacket);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -25,18 +25,68 @@
|
|||
|
||||
package org.geysermc.connector.network.translators.java.window;
|
||||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientCloseWindowPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerOpenWindowPacket;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.nukkitx.protocol.bedrock.packet.ContainerClosePacket;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
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.network.translators.Translators;
|
||||
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
||||
import org.geysermc.connector.utils.InventoryUtils;
|
||||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerOpenWindowPacket;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Translator(packet = ServerOpenWindowPacket.class)
|
||||
public class JavaOpenWindowTranslator extends PacketTranslator<ServerOpenWindowPacket> {
|
||||
|
||||
@Override
|
||||
public void translate(ServerOpenWindowPacket packet, GeyserSession session) {
|
||||
InventoryUtils.openInventory(session, packet);
|
||||
if (packet.getWindowId() == 0) {
|
||||
return;
|
||||
}
|
||||
InventoryTranslator newTranslator = Translators.getInventoryTranslators().get(packet.getType());
|
||||
Inventory openInventory = session.getInventoryCache().getOpenInventory();
|
||||
if (newTranslator == null) {
|
||||
if (openInventory != null) {
|
||||
ContainerClosePacket closePacket = new ContainerClosePacket();
|
||||
closePacket.setWindowId((byte)openInventory.getId());
|
||||
session.getUpstream().sendPacket(closePacket);
|
||||
Translators.getInventoryTranslators().get(openInventory.getWindowType()).closeInventory(session, openInventory);
|
||||
}
|
||||
ClientCloseWindowPacket closeWindowPacket = new ClientCloseWindowPacket(packet.getWindowId());
|
||||
session.getDownstream().getSession().send(closeWindowPacket);
|
||||
return;
|
||||
}
|
||||
|
||||
String name = packet.getName();
|
||||
try {
|
||||
JsonParser parser = new JsonParser();
|
||||
JsonObject jsonObject = parser.parse(packet.getName()).getAsJsonObject();
|
||||
if (jsonObject.has("text")) {
|
||||
name = jsonObject.get("text").getAsString();
|
||||
} else if (jsonObject.has("translate")) {
|
||||
name = jsonObject.get("translate").getAsString();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
GeyserConnector.getInstance().getLogger().debug("JavaOpenWindowTranslator: " + e.toString());
|
||||
}
|
||||
|
||||
Inventory newInventory = new Inventory(name, packet.getWindowId(), packet.getType(), newTranslator.size + 36);
|
||||
session.getInventoryCache().cacheInventory(newInventory);
|
||||
if (openInventory != null) {
|
||||
InventoryTranslator openTranslator = Translators.getInventoryTranslators().get(openInventory.getWindowType());
|
||||
if (!openTranslator.getClass().equals(newTranslator.getClass())) {
|
||||
InventoryUtils.closeInventory(session, openInventory.getId());
|
||||
GeyserConnector.getInstance().getGeneralThreadPool().schedule(() -> InventoryUtils.openInventory(session, newInventory), 500, TimeUnit.MILLISECONDS);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
InventoryUtils.openInventory(session, newInventory);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,47 +25,41 @@
|
|||
|
||||
package org.geysermc.connector.network.translators.java.window;
|
||||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerSetSlotPacket;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.session.cache.InventoryCache;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translators;
|
||||
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
import org.geysermc.connector.utils.InventoryUtils;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerSetSlotPacket;
|
||||
import java.util.Objects;
|
||||
|
||||
@Translator(packet = ServerSetSlotPacket.class)
|
||||
public class JavaSetSlotTranslator extends PacketTranslator<ServerSetSlotPacket> {
|
||||
|
||||
@Override
|
||||
public void translate(ServerSetSlotPacket packet, GeyserSession session) {
|
||||
InventoryCache inventoryCache = session.getInventoryCache();
|
||||
if (!inventoryCache.getInventories().containsKey(packet.getWindowId())) {
|
||||
inventoryCache.cachePacket(packet.getWindowId(), packet);
|
||||
if (packet.getWindowId() == 255 && packet.getSlot() == -1) { //cursor
|
||||
if (Objects.equals(session.getInventory().getCursor(), packet.getItem()))
|
||||
return;
|
||||
if (session.getCraftSlot() != 0)
|
||||
return;
|
||||
|
||||
session.getInventory().setCursor(packet.getItem());
|
||||
InventoryUtils.updateCursor(session);
|
||||
return;
|
||||
}
|
||||
|
||||
Inventory inventory = inventoryCache.getInventories().get(packet.getWindowId());
|
||||
if (packet.getWindowId() != 0 && inventory.getWindowType() == null)
|
||||
Inventory inventory = session.getInventoryCache().getInventories().get(packet.getWindowId());
|
||||
if (inventory == null || (packet.getWindowId() != 0 && inventory.getWindowType() == null))
|
||||
return;
|
||||
|
||||
// Player inventory
|
||||
if (packet.getWindowId() == 0) {
|
||||
if (packet.getSlot() >= inventory.getItems().length)
|
||||
return; // Most likely not a player inventory
|
||||
|
||||
ItemStack[] items = inventory.getItems();
|
||||
items[packet.getSlot()] = packet.getItem();
|
||||
inventory.setItems(items);
|
||||
|
||||
InventoryUtils.refreshPlayerInventory(session, inventory);
|
||||
|
||||
if (inventory.isOpen()) {
|
||||
InventoryUtils.updateSlot(session, packet);
|
||||
} else {
|
||||
inventoryCache.cachePacket(packet.getWindowId(), packet);
|
||||
}
|
||||
InventoryTranslator translator = Translators.getInventoryTranslators().get(inventory.getWindowType());
|
||||
if (translator != null) {
|
||||
inventory.setItem(packet.getSlot(), packet.getItem());
|
||||
translator.updateSlot(session, inventory, packet.getSlot());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,34 +25,34 @@
|
|||
|
||||
package org.geysermc.connector.network.translators.java.window;
|
||||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerWindowItemsPacket;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.session.cache.InventoryCache;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
import org.geysermc.connector.utils.InventoryUtils;
|
||||
import org.geysermc.connector.network.translators.Translators;
|
||||
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
||||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerWindowItemsPacket;
|
||||
import java.util.Arrays;
|
||||
|
||||
@Translator(packet = ServerWindowItemsPacket.class)
|
||||
public class JavaWindowItemsTranslator extends PacketTranslator<ServerWindowItemsPacket> {
|
||||
|
||||
@Override
|
||||
public void translate(ServerWindowItemsPacket packet, GeyserSession session) {
|
||||
InventoryCache inventoryCache = session.getInventoryCache();
|
||||
if (!inventoryCache.getInventories().containsKey(packet.getWindowId())) {
|
||||
inventoryCache.cachePacket(packet.getWindowId(), packet);
|
||||
Inventory inventory = session.getInventoryCache().getInventories().get(packet.getWindowId());
|
||||
if (inventory == null || (packet.getWindowId() != 0 && inventory.getWindowType() == null))
|
||||
return;
|
||||
}
|
||||
|
||||
Inventory inventory = inventoryCache.getInventories().get(packet.getWindowId());
|
||||
// Player inventory
|
||||
if (packet.getWindowId() == 0) {
|
||||
if (packet.getItems().length < inventory.getSize()) {
|
||||
inventory.setItems(Arrays.copyOf(packet.getItems(), inventory.getSize()));
|
||||
} else {
|
||||
inventory.setItems(packet.getItems());
|
||||
InventoryUtils.refreshPlayerInventory(session, inventory);
|
||||
return;
|
||||
}
|
||||
|
||||
InventoryUtils.updateInventory(session, packet);
|
||||
InventoryTranslator translator = Translators.getInventoryTranslators().get(inventory.getWindowType());
|
||||
if (translator != null) {
|
||||
translator.updateInventory(session, inventory);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* 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.java.window;
|
||||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerWindowPropertyPacket;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
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.network.translators.Translators;
|
||||
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
||||
|
||||
@Translator(packet = ServerWindowPropertyPacket.class)
|
||||
public class JavaWindowPropertyTranslator extends PacketTranslator<ServerWindowPropertyPacket> {
|
||||
|
||||
@Override
|
||||
public void translate(ServerWindowPropertyPacket packet, GeyserSession session) {
|
||||
Inventory inventory = session.getInventoryCache().getInventories().get(packet.getWindowId());
|
||||
if (inventory == null || (packet.getWindowId() != 0 && inventory.getWindowType() == null))
|
||||
return;
|
||||
|
||||
InventoryTranslator translator = Translators.getInventoryTranslators().get(inventory.getWindowType());
|
||||
if (translator != null) {
|
||||
translator.updateProperty(session, inventory, packet.getRawProperty(), packet.getValue());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* 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.java.world;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.world.block.value.ChestValue;
|
||||
import com.github.steveice10.mc.protocol.data.game.world.block.value.EndGatewayValue;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerBlockValuePacket;
|
||||
import com.nukkitx.math.vector.Vector3i;
|
||||
import com.nukkitx.protocol.bedrock.packet.BlockEventPacket;
|
||||
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
|
||||
@Translator(packet = ServerBlockValuePacket.class)
|
||||
public class JavaBlockValueTranslator extends PacketTranslator<ServerBlockValuePacket> {
|
||||
|
||||
@Override
|
||||
public void translate(ServerBlockValuePacket packet, GeyserSession session) {
|
||||
BlockEventPacket blockEventPacket = new BlockEventPacket();
|
||||
blockEventPacket.setBlockPosition(Vector3i.from(packet.getPosition().getX(),
|
||||
packet.getPosition().getY(), packet.getPosition().getZ()));
|
||||
if (packet.getValue() instanceof ChestValue) {
|
||||
ChestValue value = (ChestValue) packet.getValue() ;
|
||||
blockEventPacket.setEventType(1);
|
||||
blockEventPacket.setEventData(value.getViewers() > 0 ? 1 : 0);
|
||||
session.getUpstream().sendPacket(blockEventPacket);
|
||||
}
|
||||
if (packet.getValue() instanceof EndGatewayValue) {
|
||||
blockEventPacket.setEventType(1);
|
||||
session.getUpstream().sendPacket(blockEventPacket);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -25,6 +25,19 @@
|
|||
|
||||
package org.geysermc.connector.network.translators.java.world;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerChunkDataPacket;
|
||||
import com.nukkitx.nbt.NbtUtils;
|
||||
import com.nukkitx.nbt.stream.NBTOutputStream;
|
||||
import com.nukkitx.nbt.tag.CompoundTag;
|
||||
import com.nukkitx.network.VarInts;
|
||||
import com.nukkitx.protocol.bedrock.packet.LevelChunkPacket;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufOutputStream;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.BiomeTranslator;
|
||||
|
@ -33,14 +46,7 @@ import org.geysermc.connector.network.translators.Translator;
|
|||
import org.geysermc.connector.utils.ChunkUtils;
|
||||
import org.geysermc.connector.world.chunk.ChunkSection;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.chunk.Chunk;
|
||||
import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerChunkDataPacket;
|
||||
import com.nukkitx.network.VarInts;
|
||||
import com.nukkitx.protocol.bedrock.packet.LevelChunkPacket;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import java.util.Map;
|
||||
|
||||
@Translator(packet = ServerChunkDataPacket.class)
|
||||
public class JavaChunkDataTranslator extends PacketTranslator<ServerChunkDataPacket> {
|
||||
|
@ -54,7 +60,6 @@ public class JavaChunkDataTranslator extends PacketTranslator<ServerChunkDataPac
|
|||
if (packet.getColumn().getBiomeData() == null) //Non-full chunk
|
||||
return;
|
||||
|
||||
// Not sure if this is safe or not, however without this the client usually times out
|
||||
GeyserConnector.getInstance().getGeneralThreadPool().execute(() -> {
|
||||
try {
|
||||
ChunkUtils.ChunkData chunkData = ChunkUtils.translateToBedrock(packet.getColumn());
|
||||
|
@ -78,6 +83,14 @@ public class JavaChunkDataTranslator extends PacketTranslator<ServerChunkDataPac
|
|||
byteBuf.writeByte(0); // Border blocks - Edu edition only
|
||||
VarInts.writeUnsignedInt(byteBuf, 0); // extra data length, 0 for now
|
||||
|
||||
ByteBufOutputStream stream = new ByteBufOutputStream(Unpooled.buffer());
|
||||
NBTOutputStream nbtStream = NbtUtils.createNetworkWriter(stream);
|
||||
for (CompoundTag blockEntity : chunkData.getBlockEntities()) {
|
||||
nbtStream.write(blockEntity);
|
||||
}
|
||||
|
||||
byteBuf.writeBytes(stream.buffer());
|
||||
|
||||
byte[] payload = new byte[byteBuf.writerIndex()];
|
||||
byteBuf.readBytes(payload);
|
||||
|
||||
|
@ -88,6 +101,16 @@ public class JavaChunkDataTranslator extends PacketTranslator<ServerChunkDataPac
|
|||
levelChunkPacket.setChunkZ(packet.getColumn().getZ());
|
||||
levelChunkPacket.setData(payload);
|
||||
session.getUpstream().sendPacket(levelChunkPacket);
|
||||
|
||||
// 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.getLoadBlockEntitiesLater().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));
|
||||
}
|
||||
chunkData.getLoadBlockEntitiesLater().clear();
|
||||
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* 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.java.world;
|
||||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerUpdateTileEntityPacket;
|
||||
|
||||
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.network.translators.block.entity.BlockEntity;
|
||||
import org.geysermc.connector.network.translators.block.entity.BlockEntityTranslator;
|
||||
import org.geysermc.connector.utils.BlockEntityUtils;
|
||||
import org.geysermc.connector.utils.ChunkUtils;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Translator(packet = ServerUpdateTileEntityPacket.class)
|
||||
public class JavaUpdateTileEntityTranslator extends PacketTranslator<ServerUpdateTileEntityPacket> {
|
||||
|
||||
// This should be modified if sign text is not showing up
|
||||
private static final int DELAY = 500;
|
||||
|
||||
@Override
|
||||
public void translate(ServerUpdateTileEntityPacket packet, GeyserSession session) {
|
||||
String id = BlockEntityUtils.getBedrockBlockEntityId(packet.getType().name());
|
||||
BlockEntityTranslator translator = BlockEntityUtils.getBlockEntityTranslator(id);
|
||||
// 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
|
||||
session.getConnector().getGeneralThreadPool().schedule(() ->
|
||||
BlockEntityUtils.updateBlockEntity(session, translator.getBlockEntityTag(id, packet.getNbt(), null), packet.getPosition()),
|
||||
DELAY, TimeUnit.MILLISECONDS);
|
||||
} else {
|
||||
BlockEntityUtils.updateBlockEntity(session, translator.getBlockEntityTag(id, packet.getNbt(), null), packet.getPosition());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package org.geysermc.connector.utils;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
||||
import com.nukkitx.math.vector.Vector3i;
|
||||
import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket;
|
||||
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.Translators;
|
||||
import org.geysermc.connector.network.translators.block.entity.BlockEntityTranslator;
|
||||
|
||||
public class BlockEntityUtils {
|
||||
|
||||
private static final BlockEntityTranslator EMPTY_TRANSLATOR = Translators.getBlockEntityTranslators().get("Empty");
|
||||
|
||||
public static String getBedrockBlockEntityId(String id) {
|
||||
// This is the only exception when it comes to block entity ids
|
||||
if (id.contains("piston_head"))
|
||||
return "PistonArm";
|
||||
|
||||
id = id.toLowerCase()
|
||||
.replace("minecraft:", "")
|
||||
.replace("_", " ");
|
||||
String[] words = id.split(" ");
|
||||
for (int i = 0; i < words.length; i++) {
|
||||
words[i] = words[i].substring(0, 1).toUpperCase() + words[i].substring(1).toLowerCase();
|
||||
}
|
||||
|
||||
id = String.join(" ", words);
|
||||
return id.replace(" ", "");
|
||||
}
|
||||
|
||||
public static BlockEntityTranslator getBlockEntityTranslator(String name) {
|
||||
BlockEntityTranslator blockEntityTranslator = Translators.getBlockEntityTranslators().get(name);
|
||||
if (blockEntityTranslator == null) {
|
||||
return EMPTY_TRANSLATOR;
|
||||
}
|
||||
|
||||
return blockEntityTranslator;
|
||||
}
|
||||
|
||||
public static void updateBlockEntity(GeyserSession session, com.nukkitx.nbt.tag.CompoundTag blockEntity, Position position) {
|
||||
BlockEntityDataPacket blockEntityPacket = new BlockEntityDataPacket();
|
||||
blockEntityPacket.setBlockPosition(Vector3i.from(position.getX(), position.getY(), position.getZ()));
|
||||
blockEntityPacket.setData(blockEntity);
|
||||
session.getUpstream().sendPacket(blockEntityPacket);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* 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 com.github.steveice10.mc.protocol.data.game.entity.Effect;
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import org.geysermc.connector.entity.PlayerEntity;
|
||||
import org.geysermc.connector.network.translators.block.BlockTranslator;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
import org.geysermc.connector.network.translators.item.ToolItemEntry;
|
||||
|
||||
public class BlockUtils {
|
||||
|
||||
private static boolean correctTool(String blockToolType, String itemToolType) {
|
||||
return (blockToolType.equals("sword") && itemToolType.equals("sword")) ||
|
||||
(blockToolType.equals("shovel") && itemToolType.equals("shovel")) ||
|
||||
(blockToolType.equals("pickaxe") && itemToolType.equals("pickaxe")) ||
|
||||
(blockToolType.equals("axe") && itemToolType.equals("axe")) ||
|
||||
(blockToolType.equals("shears") && itemToolType.equals("shears"));
|
||||
}
|
||||
|
||||
private static double toolBreakTimeBonus(String toolType, String toolTier, boolean isWoolBlock) {
|
||||
if (toolType.equals("shears")) return isWoolBlock ? 5.0 : 15.0;
|
||||
if (toolType.equals("")) return 1.0;
|
||||
switch (toolTier) {
|
||||
case "wooden":
|
||||
return 2.0;
|
||||
case "stone":
|
||||
return 4.0;
|
||||
case "iron":
|
||||
return 6.0;
|
||||
case "diamond":
|
||||
return 8.0;
|
||||
case "golden":
|
||||
return 12.0;
|
||||
default:
|
||||
return 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
//http://minecraft.gamepedia.com/Breaking
|
||||
private static double calculateBreakTime(double blockHardness, String toolTier, boolean canHarvestWithHand, boolean correctTool,
|
||||
String toolType, boolean isWoolBlock, boolean isCobweb, int toolEfficiencyLevel, int hasteLevel, int miningFatigueLevel
|
||||
/*boolean insideOfWaterWithoutAquaAffinity, boolean outOfWaterButNotOnGround*/) {
|
||||
double baseTime = ((correctTool || canHarvestWithHand) ? 1.5 : 5.0) * blockHardness;
|
||||
double speed = 1.0 / baseTime;
|
||||
|
||||
if (correctTool) {
|
||||
speed *= toolBreakTimeBonus(toolType, toolTier, isWoolBlock);
|
||||
speed += toolEfficiencyLevel == 0 ? 0 : toolEfficiencyLevel * toolEfficiencyLevel + 1;
|
||||
} else if (toolType.equals("sword")) {
|
||||
speed*= (isCobweb ? 15.0 : 1.5);
|
||||
}
|
||||
speed *= 1.0 + (0.2 * hasteLevel);
|
||||
|
||||
switch (miningFatigueLevel) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
speed -= (speed * 0.7);
|
||||
break;
|
||||
case 2:
|
||||
speed -= (speed * 0.91);
|
||||
break;
|
||||
case 3:
|
||||
speed -= (speed * 0.9973);
|
||||
break;
|
||||
default:
|
||||
speed -= (speed * 0.99919);
|
||||
break;
|
||||
}
|
||||
|
||||
//if (insideOfWaterWithoutAquaAffinity) speed *= 0.2;
|
||||
//if (outOfWaterButNotOnGround) speed *= 0.2;
|
||||
// else if insideWaterAndNotOnGround speed *= 0.2;
|
||||
return 1.0 / speed;
|
||||
}
|
||||
|
||||
public static double getBreakTime(double blockHardness, int blockId, ItemEntry item, CompoundTag nbtData, PlayerEntity player) {
|
||||
boolean isWoolBlock = BlockTranslator.JAVA_RUNTIME_WOOL_IDS.contains(blockId);
|
||||
boolean isCobweb = blockId == BlockTranslator.JAVA_RUNTIME_COBWEB_ID;
|
||||
String blockToolType = BlockTranslator.JAVA_RUNTIME_ID_TO_TOOL_TYPE.getOrDefault(blockId, "");
|
||||
boolean canHarvestWithHand = BlockTranslator.JAVA_RUNTIME_ID_TO_CAN_HARVEST_WITH_HAND.get(blockId);
|
||||
String toolType = "";
|
||||
String toolTier = "";
|
||||
boolean correctTool = false;
|
||||
if (item instanceof ToolItemEntry) {
|
||||
ToolItemEntry toolItem = (ToolItemEntry) item;
|
||||
toolType = toolItem.getToolType();
|
||||
toolTier = toolItem.getToolTier();
|
||||
correctTool = correctTool(blockToolType, toolType);
|
||||
}
|
||||
int toolEfficiencyLevel = ItemUtils.getEnchantmentLevel(nbtData, "minecraft:efficiency");
|
||||
int hasteLevel = player.getEffectCache().getEffectLevel(Effect.FASTER_DIG);
|
||||
int miningFatigueLevel = player.getEffectCache().getEffectLevel(Effect.SLOWER_DIG);
|
||||
|
||||
// TODO implement these checks and material check if possible
|
||||
//boolean insideOfWaterWithoutAquaAffinity = player.isInsideOfWater() &&
|
||||
// Optional.ofNullable(player.getInventory().getHelmet().getEnchantment(Enchantment.ID_WATER_WORKER))
|
||||
// .map(Enchantment::getLevel).map(l -> l >= 1).orElse(false);
|
||||
//boolean outOfWaterButNotOnGround = (!player.isInsideOfWater()) && (!player.isOnGround());
|
||||
return calculateBreakTime(blockHardness, toolTier, canHarvestWithHand, correctTool, toolType, isWoolBlock, isCobweb, toolEfficiencyLevel, hasteLevel, miningFatigueLevel);
|
||||
}
|
||||
|
||||
}
|
|
@ -29,27 +29,47 @@ import com.github.steveice10.mc.protocol.data.game.chunk.Chunk;
|
|||
import com.github.steveice10.mc.protocol.data.game.chunk.Column;
|
||||
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.opennbt.tag.builtin.CompoundTag;
|
||||
import com.nukkitx.math.vector.Vector2i;
|
||||
import com.nukkitx.math.vector.Vector3i;
|
||||
import com.nukkitx.protocol.bedrock.packet.LevelChunkPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.NetworkChunkPublisherUpdatePacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.block.entity.*;
|
||||
import org.geysermc.connector.network.translators.Translators;
|
||||
import org.geysermc.connector.network.translators.block.BlockTranslator;
|
||||
import org.geysermc.connector.world.chunk.ChunkPosition;
|
||||
import org.geysermc.connector.world.chunk.ChunkSection;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.geysermc.connector.network.translators.block.BlockTranslator.BEDROCK_WATER_ID;
|
||||
|
||||
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) {
|
||||
ChunkData chunkData = new ChunkData();
|
||||
|
||||
Chunk[] chunks = column.getChunks();
|
||||
int chunkSectionCount = chunks.length;
|
||||
chunkData.sections = new ChunkSection[chunkSectionCount];
|
||||
chunkData.sections = new ChunkSection[chunks.length];
|
||||
|
||||
for (int chunkY = 0; chunkY < chunkSectionCount; chunkY++) {
|
||||
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++) {
|
||||
chunkData.sections[chunkY] = new ChunkSection();
|
||||
Chunk chunk = chunks[chunkY];
|
||||
|
||||
|
@ -57,14 +77,28 @@ public class ChunkUtils {
|
|||
continue;
|
||||
|
||||
ChunkSection section = chunkData.sections[chunkY];
|
||||
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int y = 0; y < 16; y++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
BlockState blockState = chunk.get(x, y, z);
|
||||
int id = BlockTranslator.getBedrockBlockId(blockState);
|
||||
|
||||
section.getBlockStorageArray()[0].setFullBlock(ChunkSection.blockPosition(x, y, z), id);
|
||||
// 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);
|
||||
blockEntityPositions.put(pos, blockState);
|
||||
// If there is a delay required for the block, allow it.
|
||||
if (blockEntityTranslator.getClass().getAnnotation(BlockEntity.class).delay()) {
|
||||
chunkData.loadBlockEntitiesLater.put(blockEntityTranslator.getDefaultBedrockTag(BlockEntityUtils.getBedrockBlockEntityId(BlockTranslator.getBlockEntityString(blockState)),
|
||||
pos.getX(), pos.getY(), pos.getZ()), blockState.getId());
|
||||
} else {
|
||||
section.getBlockStorageArray()[0].setFullBlock(ChunkSection.blockPosition(x, y, z), id);
|
||||
}
|
||||
} else {
|
||||
section.getBlockStorageArray()[0].setFullBlock(ChunkSection.blockPosition(x, y, z), id);
|
||||
}
|
||||
|
||||
if (BlockTranslator.isWaterlogged(blockState)) {
|
||||
section.getBlockStorageArray()[1].setFullBlock(ChunkSection.blockPosition(x, y, z), BEDROCK_WATER_ID);
|
||||
|
@ -72,7 +106,27 @@ public class ChunkUtils {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
com.nukkitx.nbt.tag.CompoundTag[] bedrockBlockEntities = new com.nukkitx.nbt.tag.CompoundTag[blockEntities.length];
|
||||
for (int i = 0; i < blockEntities.length; i++) {
|
||||
CompoundTag tag = blockEntities[i];
|
||||
String tagName;
|
||||
if (!tag.contains("id")) {
|
||||
GeyserConnector.getInstance().getLogger().debug("Got tag with no id: " + tag.getValue());
|
||||
tagName = "Empty";
|
||||
} else {
|
||||
tagName = (String) tag.get("id").getValue();
|
||||
}
|
||||
|
||||
String id = BlockEntityUtils.getBedrockBlockEntityId(tagName);
|
||||
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()));
|
||||
bedrockBlockEntities[i] = blockEntityTranslator.getBlockEntityTag(tagName, tag, blockState);
|
||||
}
|
||||
|
||||
chunkData.blockEntities = bedrockBlockEntities;
|
||||
return chunkData;
|
||||
}
|
||||
|
||||
|
@ -114,6 +168,19 @@ public class ChunkUtils {
|
|||
waterPacket.setRuntimeId(0);
|
||||
}
|
||||
session.getUpstream().sendPacket(waterPacket);
|
||||
|
||||
// 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
|
||||
// Iterates through all block entity translators and determines if the block state needs to be saved
|
||||
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) {
|
||||
|
@ -144,6 +211,9 @@ public class ChunkUtils {
|
|||
public static final class ChunkData {
|
||||
public ChunkSection[] sections;
|
||||
|
||||
public byte[] blockEntities = new byte[0];
|
||||
@Getter
|
||||
private com.nukkitx.nbt.tag.CompoundTag[] blockEntities = new com.nukkitx.nbt.tag.CompoundTag[0];
|
||||
@Getter
|
||||
private Object2IntMap<com.nukkitx.nbt.tag.CompoundTag> loadBlockEntitiesLater = new Object2IntOpenHashMap<>();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,113 +26,76 @@
|
|||
package org.geysermc.connector.utils;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientCloseWindowPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerOpenWindowPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerSetSlotPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerWindowItemsPacket;
|
||||
import com.github.steveice10.packetlib.packet.Packet;
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.nukkitx.protocol.bedrock.data.ContainerId;
|
||||
import com.nukkitx.protocol.bedrock.data.ItemData;
|
||||
import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.Translators;
|
||||
import org.geysermc.connector.network.translators.inventory.DoubleChestInventoryTranslator;
|
||||
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class InventoryUtils {
|
||||
public static final ItemStack REFRESH_ITEM = new ItemStack(1, 127, new CompoundTag("")); //TODO: stop using this
|
||||
|
||||
public static void refreshPlayerInventory(GeyserSession session, Inventory inventory) {
|
||||
InventoryContentPacket inventoryContentPacket = new InventoryContentPacket();
|
||||
inventoryContentPacket.setContainerId(ContainerId.INVENTORY);
|
||||
|
||||
ItemData[] contents = new ItemData[40];
|
||||
// Inventory
|
||||
for (int i = 9; i < 36; i++) {
|
||||
contents[i] = Translators.getItemTranslator().translateToBedrock(inventory.getItems()[i]);
|
||||
public static void openInventory(GeyserSession session, Inventory inventory) {
|
||||
InventoryTranslator translator = Translators.getInventoryTranslators().get(inventory.getWindowType());
|
||||
if (translator != null) {
|
||||
session.getInventoryCache().setOpenInventory(inventory);
|
||||
translator.prepareInventory(session, inventory);
|
||||
//TODO: find better way to handle double chest delay
|
||||
if (translator instanceof DoubleChestInventoryTranslator) {
|
||||
GeyserConnector.getInstance().getGeneralThreadPool().schedule(() -> {
|
||||
translator.openInventory(session, inventory);
|
||||
translator.updateInventory(session, inventory);
|
||||
}, 200, TimeUnit.MILLISECONDS);
|
||||
} else {
|
||||
translator.openInventory(session, inventory);
|
||||
translator.updateInventory(session, inventory);
|
||||
}
|
||||
}
|
||||
|
||||
// Hotbar
|
||||
for (int i = 36; i < 45; i++) {
|
||||
contents[i - 36] = Translators.getItemTranslator().translateToBedrock(inventory.getItems()[i]);
|
||||
}
|
||||
|
||||
// Armor
|
||||
for (int i = 5; i < 9; i++) {
|
||||
contents[i + 31] = Translators.getItemTranslator().translateToBedrock(inventory.getItems()[i]);
|
||||
}
|
||||
|
||||
inventoryContentPacket.setContents(contents);
|
||||
session.getUpstream().sendPacket(inventoryContentPacket);
|
||||
}
|
||||
|
||||
public static void openInventory(GeyserSession session, ServerOpenWindowPacket packet) {
|
||||
Inventory inventory = new Inventory(packet.getWindowId(), packet.getType(), 45); // TODO: Find a way to set this value
|
||||
session.getInventoryCache().getInventories().put(packet.getWindowId(), inventory);
|
||||
session.getInventoryCache().setOpenInventory(inventory);
|
||||
|
||||
InventoryTranslator translator = Translators.getInventoryTranslator();
|
||||
translator.prepareInventory(session, inventory);
|
||||
GeyserConnector.getInstance().getGeneralThreadPool().schedule(() -> {
|
||||
List<Packet> packets = session.getInventoryCache().getCachedPackets().get(inventory.getId());
|
||||
packets.forEach(itemPacket -> {
|
||||
if (itemPacket != null) {
|
||||
if (ServerWindowItemsPacket.class.isAssignableFrom(itemPacket.getClass())) {
|
||||
updateInventory(session, (ServerWindowItemsPacket) itemPacket);
|
||||
}
|
||||
}
|
||||
});
|
||||
}, 200, TimeUnit.MILLISECONDS);
|
||||
public static void closeInventory(GeyserSession session, int windowId) {
|
||||
if (windowId != 0) {
|
||||
Inventory inventory = session.getInventoryCache().getInventories().get(windowId);
|
||||
if (inventory != null) {
|
||||
InventoryTranslator translator = Translators.getInventoryTranslators().get(inventory.getWindowType());
|
||||
translator.closeInventory(session, inventory);
|
||||
session.getInventoryCache().uncacheInventory(windowId);
|
||||
session.getInventoryCache().setOpenInventory(null);
|
||||
}
|
||||
} else {
|
||||
Inventory inventory = session.getInventory();
|
||||
InventoryTranslator translator = Translators.getInventoryTranslators().get(inventory.getWindowType());
|
||||
translator.updateInventory(session, inventory);
|
||||
}
|
||||
session.setCraftSlot(0);
|
||||
session.getInventory().setCursor(null);
|
||||
}
|
||||
|
||||
public static void updateInventory(GeyserSession session, ServerWindowItemsPacket packet) {
|
||||
if (packet.getWindowId() == 0)
|
||||
return;
|
||||
|
||||
if (session.getInventoryCache().getOpenInventory() == null || !session.getInventoryCache().getInventories().containsKey(packet.getWindowId()))
|
||||
return;
|
||||
|
||||
Inventory openInventory = session.getInventoryCache().getOpenInventory();
|
||||
if (packet.getWindowId() != openInventory.getId())
|
||||
return;
|
||||
|
||||
InventoryTranslator translator = Translators.getInventoryTranslator();
|
||||
if (translator == null) {
|
||||
session.getDownstream().getSession().send(new ClientCloseWindowPacket(packet.getWindowId()));
|
||||
return;
|
||||
}
|
||||
|
||||
openInventory.setItems(packet.getItems());
|
||||
translator.updateInventory(session, openInventory);
|
||||
public static void updateCursor(GeyserSession session) {
|
||||
InventorySlotPacket cursorPacket = new InventorySlotPacket();
|
||||
cursorPacket.setContainerId(ContainerId.CURSOR);
|
||||
cursorPacket.setSlot(0);
|
||||
cursorPacket.setItem(Translators.getItemTranslator().translateToBedrock(session.getInventory().getCursor()));
|
||||
session.getUpstream().sendPacket(cursorPacket);
|
||||
}
|
||||
|
||||
public static void updateSlot(GeyserSession session, ServerSetSlotPacket packet) {
|
||||
if (packet.getWindowId() == 0)
|
||||
return;
|
||||
public static boolean canStack(ItemStack item1, ItemStack item2) {
|
||||
if (item1 == null || item2 == null)
|
||||
return false;
|
||||
return item1.getId() == item2.getId() && Objects.equals(item1.getNbt(), item2.getNbt());
|
||||
}
|
||||
|
||||
if (session.getInventoryCache().getOpenInventory() == null || !session.getInventoryCache().getInventories().containsKey(packet.getWindowId()))
|
||||
return;
|
||||
|
||||
Inventory openInventory = session.getInventoryCache().getOpenInventory();
|
||||
if (packet.getWindowId() != openInventory.getId())
|
||||
return;
|
||||
|
||||
InventoryTranslator translator = Translators.getInventoryTranslator();
|
||||
if (translator == null) {
|
||||
session.getDownstream().getSession().send(new ClientCloseWindowPacket(packet.getWindowId()));
|
||||
return;
|
||||
}
|
||||
|
||||
if (packet.getSlot() >= openInventory.getSize()) {
|
||||
session.getDownstream().getSession().send(new ClientCloseWindowPacket(packet.getWindowId()));
|
||||
return;
|
||||
}
|
||||
|
||||
ItemStack[] items = openInventory.getItems();
|
||||
items[packet.getSlot()] = packet.getItem();
|
||||
translator.updateSlot(session, openInventory, packet.getSlot());
|
||||
public static boolean canStack(ItemData item1, ItemData item2) {
|
||||
if (item1 == null || item2 == null)
|
||||
return false;
|
||||
return item1.equals(item2, false, true, true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* 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 com.github.steveice10.opennbt.tag.builtin.*;
|
||||
|
||||
public class ItemUtils {
|
||||
|
||||
public static int getEnchantmentLevel(CompoundTag itemNBTData, String enchantmentId) {
|
||||
ListTag enchantments = (itemNBTData == null ? null : itemNBTData.get("Enchantments"));
|
||||
if (enchantments != null) {
|
||||
int enchantmentLevel = 0;
|
||||
for (Tag tag : enchantments) {
|
||||
CompoundTag enchantment = (CompoundTag) tag;
|
||||
StringTag enchantId = enchantment.get("id");
|
||||
if (enchantId.getValue().equals(enchantmentId)) {
|
||||
enchantmentLevel = (int) ((ShortTag) enchantment.get("lvl")).getValue();
|
||||
}
|
||||
}
|
||||
return enchantmentLevel;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -191,7 +191,6 @@ public class SkinUtils {
|
|||
|
||||
if (skinAndCapeConsumer != null) skinAndCapeConsumer.accept(skinAndCape);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
|||
import com.nukkitx.nbt.NbtUtils;
|
||||
import com.nukkitx.nbt.stream.NBTInputStream;
|
||||
import com.nukkitx.nbt.tag.CompoundTag;
|
||||
import com.nukkitx.protocol.bedrock.data.ItemData;
|
||||
import com.nukkitx.protocol.bedrock.packet.StartGamePacket;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
|
@ -39,6 +40,7 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
|||
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
import org.geysermc.connector.network.translators.item.ToolItemEntry;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
@ -47,6 +49,7 @@ public class Toolbox {
|
|||
|
||||
public static final ObjectMapper JSON_MAPPER = new ObjectMapper().disable(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES);
|
||||
public static final CompoundTag BIOMES;
|
||||
public static final ItemData[] CREATIVE_ITEMS;
|
||||
|
||||
public static final List<StartGamePacket.ItemEntry> ITEMS = new ArrayList<>();
|
||||
|
||||
|
@ -101,13 +104,63 @@ public class Toolbox {
|
|||
Iterator<Map.Entry<String, JsonNode>> iterator = items.fields();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<String, JsonNode> entry = iterator.next();
|
||||
ITEM_ENTRIES.put(itemIndex, new ItemEntry(entry.getKey(), itemIndex,
|
||||
entry.getValue().get("bedrock_id").intValue(), entry.getValue().get("bedrock_data").intValue()));
|
||||
if (entry.getValue().has("tool_type")) {
|
||||
if (entry.getValue().has("tool_tier")) {
|
||||
ITEM_ENTRIES.put(itemIndex, new ToolItemEntry(
|
||||
entry.getKey(), itemIndex,
|
||||
entry.getValue().get("bedrock_id").intValue(),
|
||||
entry.getValue().get("bedrock_data").intValue(),
|
||||
entry.getValue().get("tool_type").textValue(),
|
||||
entry.getValue().get("tool_tier").textValue()));
|
||||
} else {
|
||||
ITEM_ENTRIES.put(itemIndex, new ToolItemEntry(
|
||||
entry.getKey(), itemIndex,
|
||||
entry.getValue().get("bedrock_id").intValue(),
|
||||
entry.getValue().get("bedrock_data").intValue(),
|
||||
entry.getValue().get("tool_type").textValue(),
|
||||
""));
|
||||
}
|
||||
} else {
|
||||
ITEM_ENTRIES.put(itemIndex, new ItemEntry(
|
||||
entry.getKey(), itemIndex,
|
||||
entry.getValue().get("bedrock_id").intValue(),
|
||||
entry.getValue().get("bedrock_data").intValue()));
|
||||
}
|
||||
itemIndex++;
|
||||
}
|
||||
|
||||
// Load the locale data
|
||||
LocaleUtils.init();
|
||||
|
||||
stream = getResource("bedrock/creative_items.json");
|
||||
|
||||
JsonNode creativeItemEntries;
|
||||
try {
|
||||
creativeItemEntries = JSON_MAPPER.readTree(stream).get("items");
|
||||
} catch (Exception e) {
|
||||
throw new AssertionError("Unable to load creative items", e);
|
||||
}
|
||||
|
||||
List<ItemData> creativeItems = new ArrayList<>();
|
||||
for (JsonNode itemNode : creativeItemEntries) {
|
||||
short damage = 0;
|
||||
if (itemNode.has("damage")) {
|
||||
damage = itemNode.get("damage").numberValue().shortValue();
|
||||
}
|
||||
if (itemNode.has("nbt_b64")) {
|
||||
byte[] bytes = Base64.getDecoder().decode(itemNode.get("nbt_b64").asText());
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
|
||||
try {
|
||||
com.nukkitx.nbt.tag.CompoundTag tag = (com.nukkitx.nbt.tag.CompoundTag) NbtUtils.createReaderLE(bais).readTag();
|
||||
creativeItems.add(ItemData.of(itemNode.get("id").asInt(), damage, 1, tag));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
creativeItems.add(ItemData.of(itemNode.get("id").asInt(), damage, 1));
|
||||
}
|
||||
}
|
||||
CREATIVE_ITEMS = creativeItems.toArray(new ItemData[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -48,7 +48,6 @@ public class ChunkPosition {
|
|||
int chunkX = x & 15;
|
||||
int chunkY = y & 15;
|
||||
int chunkZ = z & 15;
|
||||
|
||||
return new Position(chunkX, chunkY, chunkZ);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3008,21 +3008,6 @@
|
|||
{
|
||||
"id" : -198
|
||||
},
|
||||
{
|
||||
"id" : 238,
|
||||
"damage" : 8
|
||||
},
|
||||
{
|
||||
"id" : 238
|
||||
},
|
||||
{
|
||||
"id" : 238,
|
||||
"damage" : 12
|
||||
},
|
||||
{
|
||||
"id" : 238,
|
||||
"damage" : 4
|
||||
},
|
||||
{
|
||||
"id" : 379
|
||||
},
|
||||
|
@ -3419,363 +3404,6 @@
|
|||
{
|
||||
"id" : 386
|
||||
},
|
||||
{
|
||||
"id" : 36
|
||||
},
|
||||
{
|
||||
"id" : -12
|
||||
},
|
||||
{
|
||||
"id" : -13
|
||||
},
|
||||
{
|
||||
"id" : -14
|
||||
},
|
||||
{
|
||||
"id" : -15
|
||||
},
|
||||
{
|
||||
"id" : -16
|
||||
},
|
||||
{
|
||||
"id" : -17
|
||||
},
|
||||
{
|
||||
"id" : -18
|
||||
},
|
||||
{
|
||||
"id" : -19
|
||||
},
|
||||
{
|
||||
"id" : -20
|
||||
},
|
||||
{
|
||||
"id" : -21
|
||||
},
|
||||
{
|
||||
"id" : -22
|
||||
},
|
||||
{
|
||||
"id" : -23
|
||||
},
|
||||
{
|
||||
"id" : -24
|
||||
},
|
||||
{
|
||||
"id" : -25
|
||||
},
|
||||
{
|
||||
"id" : -26
|
||||
},
|
||||
{
|
||||
"id" : -27
|
||||
},
|
||||
{
|
||||
"id" : -28
|
||||
},
|
||||
{
|
||||
"id" : -29
|
||||
},
|
||||
{
|
||||
"id" : -30
|
||||
},
|
||||
{
|
||||
"id" : -31
|
||||
},
|
||||
{
|
||||
"id" : -32
|
||||
},
|
||||
{
|
||||
"id" : -33
|
||||
},
|
||||
{
|
||||
"id" : -34
|
||||
},
|
||||
{
|
||||
"id" : -35
|
||||
},
|
||||
{
|
||||
"id" : -36
|
||||
},
|
||||
{
|
||||
"id" : -37
|
||||
},
|
||||
{
|
||||
"id" : -38
|
||||
},
|
||||
{
|
||||
"id" : -39
|
||||
},
|
||||
{
|
||||
"id" : -40
|
||||
},
|
||||
{
|
||||
"id" : -41
|
||||
},
|
||||
{
|
||||
"id" : -42
|
||||
},
|
||||
{
|
||||
"id" : -43
|
||||
},
|
||||
{
|
||||
"id" : -44
|
||||
},
|
||||
{
|
||||
"id" : -45
|
||||
},
|
||||
{
|
||||
"id" : -46
|
||||
},
|
||||
{
|
||||
"id" : -47
|
||||
},
|
||||
{
|
||||
"id" : -48
|
||||
},
|
||||
{
|
||||
"id" : -49
|
||||
},
|
||||
{
|
||||
"id" : -50
|
||||
},
|
||||
{
|
||||
"id" : -51
|
||||
},
|
||||
{
|
||||
"id" : -52
|
||||
},
|
||||
{
|
||||
"id" : -53
|
||||
},
|
||||
{
|
||||
"id" : -54
|
||||
},
|
||||
{
|
||||
"id" : -55
|
||||
},
|
||||
{
|
||||
"id" : -56
|
||||
},
|
||||
{
|
||||
"id" : -57
|
||||
},
|
||||
{
|
||||
"id" : -58
|
||||
},
|
||||
{
|
||||
"id" : -59
|
||||
},
|
||||
{
|
||||
"id" : -60
|
||||
},
|
||||
{
|
||||
"id" : -61
|
||||
},
|
||||
{
|
||||
"id" : -62
|
||||
},
|
||||
{
|
||||
"id" : -63
|
||||
},
|
||||
{
|
||||
"id" : -64
|
||||
},
|
||||
{
|
||||
"id" : -65
|
||||
},
|
||||
{
|
||||
"id" : -66
|
||||
},
|
||||
{
|
||||
"id" : -67
|
||||
},
|
||||
{
|
||||
"id" : -68
|
||||
},
|
||||
{
|
||||
"id" : -69
|
||||
},
|
||||
{
|
||||
"id" : -70
|
||||
},
|
||||
{
|
||||
"id" : -71
|
||||
},
|
||||
{
|
||||
"id" : -72
|
||||
},
|
||||
{
|
||||
"id" : -73
|
||||
},
|
||||
{
|
||||
"id" : -74
|
||||
},
|
||||
{
|
||||
"id" : -75
|
||||
},
|
||||
{
|
||||
"id" : -76
|
||||
},
|
||||
{
|
||||
"id" : -77
|
||||
},
|
||||
{
|
||||
"id" : -78
|
||||
},
|
||||
{
|
||||
"id" : -79
|
||||
},
|
||||
{
|
||||
"id" : -80
|
||||
},
|
||||
{
|
||||
"id" : -81
|
||||
},
|
||||
{
|
||||
"id" : -82
|
||||
},
|
||||
{
|
||||
"id" : -83
|
||||
},
|
||||
{
|
||||
"id" : -84
|
||||
},
|
||||
{
|
||||
"id" : -85
|
||||
},
|
||||
{
|
||||
"id" : -86
|
||||
},
|
||||
{
|
||||
"id" : -87
|
||||
},
|
||||
{
|
||||
"id" : -88
|
||||
},
|
||||
{
|
||||
"id" : -89
|
||||
},
|
||||
{
|
||||
"id" : -90
|
||||
},
|
||||
{
|
||||
"id" : -91
|
||||
},
|
||||
{
|
||||
"id" : -92
|
||||
},
|
||||
{
|
||||
"id" : -93
|
||||
},
|
||||
{
|
||||
"id" : -94
|
||||
},
|
||||
{
|
||||
"id" : -95
|
||||
},
|
||||
{
|
||||
"id" : -96
|
||||
},
|
||||
{
|
||||
"id" : -97
|
||||
},
|
||||
{
|
||||
"id" : -98
|
||||
},
|
||||
{
|
||||
"id" : -99
|
||||
},
|
||||
{
|
||||
"id" : -100
|
||||
},
|
||||
{
|
||||
"id" : -101
|
||||
},
|
||||
{
|
||||
"id" : -102
|
||||
},
|
||||
{
|
||||
"id" : -103
|
||||
},
|
||||
{
|
||||
"id" : -104
|
||||
},
|
||||
{
|
||||
"id" : -105
|
||||
},
|
||||
{
|
||||
"id" : -106
|
||||
},
|
||||
{
|
||||
"id" : -107
|
||||
},
|
||||
{
|
||||
"id" : -108
|
||||
},
|
||||
{
|
||||
"id" : -109
|
||||
},
|
||||
{
|
||||
"id" : -110
|
||||
},
|
||||
{
|
||||
"id" : -111
|
||||
},
|
||||
{
|
||||
"id" : -112
|
||||
},
|
||||
{
|
||||
"id" : -113
|
||||
},
|
||||
{
|
||||
"id" : -114
|
||||
},
|
||||
{
|
||||
"id" : -115
|
||||
},
|
||||
{
|
||||
"id" : -116
|
||||
},
|
||||
{
|
||||
"id" : -117
|
||||
},
|
||||
{
|
||||
"id" : -118
|
||||
},
|
||||
{
|
||||
"id" : -119
|
||||
},
|
||||
{
|
||||
"id" : -120
|
||||
},
|
||||
{
|
||||
"id" : -121
|
||||
},
|
||||
{
|
||||
"id" : -122
|
||||
},
|
||||
{
|
||||
"id" : -123
|
||||
},
|
||||
{
|
||||
"id" : -124
|
||||
},
|
||||
{
|
||||
"id" : -125
|
||||
},
|
||||
{
|
||||
"id" : -126
|
||||
},
|
||||
{
|
||||
"id" : -127
|
||||
},
|
||||
{
|
||||
"id" : -128
|
||||
},
|
||||
{
|
||||
"id" : -129
|
||||
},
|
||||
{
|
||||
"id" : 403,
|
||||
"nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAQACAgBpZAAAAAA="
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit efc9db6b7d51bdf145230933ac23b321ac1c132d
|
||||
Subproject commit a6a790d944eb153c93d0c414813d8a0880fd5d26
|
Loading…
Reference in a new issue