Enchantment table works; anvil is almost there

This commit is contained in:
Camotoy 2020-12-23 01:21:00 -05:00
parent 009905184e
commit f4f804e1ca
No known key found for this signature in database
GPG key ID: 7EEFB66FE798081F
16 changed files with 566 additions and 133 deletions

View file

@ -0,0 +1,34 @@
/*
* 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.inventory;
import com.github.steveice10.mc.protocol.data.game.window.WindowType;
public class AnvilContainer extends Container {
public AnvilContainer(String title, int id, WindowType windowType, int size, PlayerInventory playerInventory) {
super(title, id, windowType, size, playerInventory);
}
}

View file

@ -0,0 +1,53 @@
/*
* 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.inventory;
import com.github.steveice10.mc.protocol.data.game.window.WindowType;
import com.nukkitx.protocol.bedrock.data.inventory.EnchantOptionData;
import lombok.Getter;
public class EnchantingContainer extends Container {
/**
* A cache of what Bedrock sees
*/
@Getter
private final EnchantOptionData[] enchantOptions;
/**
* A mutable cache of what the server sends us
*/
@Getter
private final GeyserEnchantOption[] geyserEnchantOptions;
public EnchantingContainer(String title, int id, WindowType windowType, int size, PlayerInventory playerInventory) {
super(title, id, windowType, size, playerInventory);
enchantOptions = new EnchantOptionData[3];
geyserEnchantOptions = new GeyserEnchantOption[3];
for (int i = 0; i < geyserEnchantOptions.length; i++) {
geyserEnchantOptions[i] = new GeyserEnchantOption(i);
}
}
}

View file

@ -1,40 +0,0 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*
*/
package org.geysermc.connector.inventory;
import com.github.steveice10.mc.protocol.data.game.window.WindowType;
import com.nukkitx.protocol.bedrock.data.inventory.EnchantOptionData;
import lombok.Getter;
@Getter
public class EnchantmentInventory extends Inventory {
private EnchantOptionData[] enchantOptions;
public EnchantmentInventory(String title, int id, WindowType windowType, int size) {
super(title, id, windowType, size);
}
}

View file

@ -30,6 +30,7 @@ import com.github.steveice10.mc.protocol.data.game.window.WindowType;
import lombok.Getter;
import lombok.Setter;
//TODO: Figure out what this is and if we should remove it
@Getter
public class FurnaceInventory extends Inventory {
@Setter

View file

@ -0,0 +1,78 @@
/*
* 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.inventory;
import com.nukkitx.protocol.bedrock.data.inventory.EnchantData;
import com.nukkitx.protocol.bedrock.data.inventory.EnchantOptionData;
import lombok.Getter;
import lombok.Setter;
import org.geysermc.connector.network.session.GeyserSession;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* A mutable "wrapper" around {@link EnchantOptionData}
*/
@Setter
public class GeyserEnchantOption {
private static final List<EnchantData> EMPTY = Collections.emptyList();
/**
* This: https://cdn.discordapp.com/attachments/613168850925649981/791030657169227816/unknown.png
* is controlled by the server.
* So, of course, we have to throw in some easter eggs. ;)
*/
private static final List<String> ENCHANT_NAMES = Arrays.asList("tougher armor", "lukeeey", "fall better",
"explode less", "camo toy", "breathe better", "rtm five one six", "armor stab", "water walk", "you are elsa",
"tim two zero three", "fast walk nether", "oof ouch owie", "enemy on fire", "spider sad", "aj ferguson", "redned",
"more items thx", "long sword reach", "fast tool", "give me block", "less breaky break", "cube craft",
"strong arrow", "fist arrow", "spicy arrow", "many many arrows", "geyser", "come here fish", "i like this",
"stabby stab", "supreme mortal", "avatar i guess", "more arrows", "fly finder seventeen", "in and out",
"xp heals tools", "dragon proxy waz here");
@Getter
private final int javaIndex;
private int xpCost = 0;
private int javaEnchantIndex = -1;
private int bedrockEnchantIndex = -1;
private int enchantLevel = -1;
public GeyserEnchantOption(int javaIndex) {
this.javaIndex = javaIndex;
}
public EnchantOptionData build(GeyserSession session) {
if (enchantLevel == -1) {
// Should not be sent to the client, as it is supposed to be empty
return null;
}
return new EnchantOptionData(xpCost, javaIndex + 16, EMPTY,
Collections.singletonList(new EnchantData(bedrockEnchantIndex, enchantLevel)), EMPTY,
javaEnchantIndex == -1 ? "unknown" : ENCHANT_NAMES.get(javaEnchantIndex), session.getItemNetId().incrementAndGet());
}
}

View file

@ -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.bedrock;
import com.nukkitx.protocol.bedrock.packet.FilterTextPacket;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.network.translators.Translator;
/**
* Used to send strings to the client and filter out unwanted words.
* Java doesn't care, so we don't care, and we approve all strings.
*/
@Translator(packet = FilterTextPacket.class)
public class BedrockFilterTextTranslator extends PacketTranslator<FilterTextPacket> {
@Override
public void translate(FilterTextPacket packet, GeyserSession session) {
// TODO: Bedrock doesn't send this. Why?
System.out.println(packet.toString());
packet.setFromServer(true);
session.sendUpstreamPacket(packet);
}
}

View file

@ -62,29 +62,36 @@ public abstract class InventoryTranslator {
public static final Map<WindowType, InventoryTranslator> INVENTORY_TRANSLATORS = new HashMap<WindowType, InventoryTranslator>() {
{
/* Player Inventory */
put(null, new PlayerInventoryTranslator()); //player inventory
/* Chest UIs */
put(WindowType.GENERIC_9X1, new SingleChestInventoryTranslator(9));
put(WindowType.GENERIC_9X2, new SingleChestInventoryTranslator(18));
put(WindowType.GENERIC_9X3, new SingleChestInventoryTranslator(27));
put(WindowType.GENERIC_9X4, new DoubleChestInventoryTranslator(36));
put(WindowType.GENERIC_9X5, new DoubleChestInventoryTranslator(45));
put(WindowType.GENERIC_9X6, new DoubleChestInventoryTranslator(54));
put(WindowType.CRAFTING, new CraftingInventoryTranslator());
put(WindowType.SHULKER_BOX, new ShulkerInventoryTranslator());
put(WindowType.BREWING_STAND, new BrewingInventoryTranslator());
//put(WindowType.ANVIL, new AnvilInventoryTranslator());
put(WindowType.GRINDSTONE, new GrindstoneInventoryTranslator());
put(WindowType.MERCHANT, new MerchantInventoryTranslator());
put(WindowType.SMITHING, new SmithingInventoryTranslator());
//put(WindowType.ENCHANTMENT, new EnchantmentInventoryTranslator()); //TODO
/* Furnaces */
put(WindowType.FURNACE, new FurnaceInventoryTranslator());
put(WindowType.BLAST_FURNACE, new BlastFurnaceInventoryTranslator());
put(WindowType.SMOKER, new SmokerInventoryTranslator());
/* Specific Inventories */
put(WindowType.ANVIL, new AnvilInventoryTranslator());
put(WindowType.BREWING_STAND, new BrewingInventoryTranslator());
put(WindowType.CRAFTING, new CraftingInventoryTranslator());
put(WindowType.ENCHANTMENT, new EnchantingInventoryTranslator());
put(WindowType.GRINDSTONE, new GrindstoneInventoryTranslator());
put(WindowType.MERCHANT, new MerchantInventoryTranslator());
put(WindowType.SHULKER_BOX, new ShulkerInventoryTranslator());
put(WindowType.SMITHING, new SmithingInventoryTranslator());
/* Generics */
put(WindowType.GENERIC_3X3, new GenericBlockInventoryTranslator(9, "minecraft:dispenser[facing=north,triggered=false]", ContainerType.DISPENSER));
put(WindowType.HOPPER, new GenericBlockInventoryTranslator(5, "minecraft:hopper[enabled=false,facing=down]", ContainerType.HOPPER));
//put(WindowType.BEACON, new AbstractBlockInventoryTranslator(1, "minecraft:beacon", ContainerType.BEACON)); //TODO*/
//put(WindowType.BEACON, new AbstractBlockInventoryTranslator(1, "minecraft:beacon", ContainerType.BEACON)); //TODO
//put(WindowType.CARTOGRAPHY
//put(WindowType.STONECUTTER
@ -110,12 +117,30 @@ public abstract class InventoryTranslator {
public abstract SlotType getSlotType(int javaSlot);
public abstract Inventory createInventory(String name, int windowId, WindowType windowType, PlayerInventory playerInventory);
/**
* Should be overrided if this request matches a certain criteria and shouldn't be treated normally.
* E.G. anvil renaming or enchanting
*/
public boolean shouldHandleRequestFirst(StackRequestActionData action) {
return false;
}
/**
* If {@link #shouldHandleRequestFirst(StackRequestActionData)} returns true, this will be called
*/
public ItemStackResponsePacket.Response translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) {
return null;
}
public void translateRequests(GeyserSession session, Inventory inventory, List<ItemStackRequestPacket.Request> requests) {
ItemStackResponsePacket responsePacket = new ItemStackResponsePacket();
for (ItemStackRequestPacket.Request request : requests) {
if (request.getActions().length > 0) {
StackRequestActionData firstAction = request.getActions()[0];
if (firstAction.getType() == StackRequestActionType.CRAFT_RECIPE || firstAction.getType() == StackRequestActionType.CRAFT_RECIPE_AUTO) {
if (shouldHandleRequestFirst(firstAction)) {
// Some special request that shouldn't be processed normally
responsePacket.getEntries().add(translateSpecialRequest(session, inventory, request));
} else if (firstAction.getType() == StackRequestActionType.CRAFT_RECIPE || firstAction.getType() == StackRequestActionType.CRAFT_RECIPE_AUTO) {
responsePacket.getEntries().add(translateCraftingRequest(session, inventory, request));
} else if (firstAction.getType() == StackRequestActionType.CRAFT_CREATIVE) {
// This is also used for pulling items out of creative
@ -335,12 +360,30 @@ public abstract class InventoryTranslator {
return rejectRequest(request);
if (isCursor(dropAction.getSource())) { //clicking outside of window
int sourceAmount = plan.getCursor().getAmount();
if (dropAction.getCount() == sourceAmount) { //drop all
plan.add(Click.LEFT_OUTSIDE, Click.OUTSIDE_SLOT);
} else { //drop some
for (int i = 0; i < dropAction.getCount(); i++) {
plan.add(Click.RIGHT_OUTSIDE, Click.OUTSIDE_SLOT); //drop one until goal is met
if (session.getGameMode() == GameMode.CREATIVE && inventory instanceof PlayerInventory) {
GeyserItemStack cursorItem = session.getPlayerInventory().getCursor();
GeyserItemStack droppingItem = cursorItem.copy();
// Subtract the cursor item by however much is being dropped
cursorItem.setAmount(cursorItem.getAmount() - dropAction.getCount());
if (cursorItem.isEmpty()) {
// Cursor item no longer exists
session.getPlayerInventory().setCursor(GeyserItemStack.EMPTY);
}
droppingItem.setAmount(dropAction.getCount());
ClientCreativeInventoryActionPacket packet = new ClientCreativeInventoryActionPacket(
Click.OUTSIDE_SLOT,
droppingItem.getItemStack()
);
System.out.println(packet.toString());
session.sendDownstreamPacket(packet);
} else {
int sourceAmount = plan.getCursor().getAmount();
if (dropAction.getCount() == sourceAmount) { //drop all
plan.add(Click.LEFT_OUTSIDE, Click.OUTSIDE_SLOT);
} else { //drop some
for (int i = 0; i < dropAction.getCount(); i++) {
plan.add(Click.RIGHT_OUTSIDE, Click.OUTSIDE_SLOT); //drop one until goal is met
}
}
}
} else { //dropping from inventory
@ -395,6 +438,10 @@ public abstract class InventoryTranslator {
case CRAFT_RESULTS_DEPRECATED: {
break;
}
case CRAFT_RECIPE_OPTIONAL: {
// Anvils and cartography tables will handle this
break;
}
default:
return rejectRequest(request);
}
@ -578,7 +625,14 @@ public abstract class InventoryTranslator {
Collections.singletonList(makeItemEntry(session, 0, session.getPlayerInventory().getCursor())))));
} else {
int javaSlot = bedrockSlotToJava(transferAction.getDestination());
inventory.setItem(javaSlot, GeyserItemStack.from(javaCreativeItem, session.getItemNetId().getAndIncrement()));
GeyserItemStack existingItem = inventory.getItem(javaSlot);
if (existingItem.getId() == javaCreativeItem.getId()) {
// Adding more to an existing item
existingItem.setAmount(existingItem.getAmount() + transferAction.getCount());
javaCreativeItem = existingItem.getItemStack();
} else {
inventory.setItem(javaSlot, GeyserItemStack.from(javaCreativeItem, session.getItemNetId().getAndIncrement()));
}
ClientCreativeInventoryActionPacket creativeActionPacket = new ClientCreativeInventoryActionPacket(
javaSlot,
javaCreativeItem

View file

@ -0,0 +1,87 @@
/*
* 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.translators;
import com.github.steveice10.mc.protocol.data.game.window.WindowType;
import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType;
import com.nukkitx.protocol.bedrock.data.inventory.ContainerType;
import com.nukkitx.protocol.bedrock.data.inventory.StackRequestSlotInfoData;
import org.geysermc.connector.inventory.AnvilContainer;
import org.geysermc.connector.inventory.Inventory;
import org.geysermc.connector.inventory.PlayerInventory;
import org.geysermc.connector.network.translators.inventory.BedrockContainerSlot;
import org.geysermc.connector.network.translators.inventory.updater.UIInventoryUpdater;
public class AnvilInventoryTranslator extends AbstractBlockInventoryTranslator {
public AnvilInventoryTranslator() {
super(3, "minecraft:anvil[facing=north]", ContainerType.ANVIL, UIInventoryUpdater.INSTANCE);
}
@Override
public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) {
if (slotInfoData.getContainer() == ContainerSlotType.ANVIL_INPUT) {
return 0;
}
if (slotInfoData.getContainer() == ContainerSlotType.ANVIL_MATERIAL) {
return 1;
}
if (slotInfoData.getContainer() == ContainerSlotType.ANVIL_RESULT || slotInfoData.getContainer() == ContainerSlotType.CREATIVE_OUTPUT) {
return 2;
}
return super.bedrockSlotToJava(slotInfoData);
}
@Override
public BedrockContainerSlot javaSlotToBedrockContainer(int slot) {
switch (slot) {
case 0:
return new BedrockContainerSlot(ContainerSlotType.ANVIL_INPUT, 1);
case 1:
return new BedrockContainerSlot(ContainerSlotType.ANVIL_MATERIAL, 2);
case 2:
return new BedrockContainerSlot(ContainerSlotType.ANVIL_RESULT, 50);
}
return super.javaSlotToBedrockContainer(slot);
}
@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 Inventory createInventory(String name, int windowId, WindowType windowType, PlayerInventory playerInventory) {
return new AnvilContainer(name, windowId, windowType, this.size, playerInventory);
}
}

View file

@ -30,11 +30,11 @@ import com.nukkitx.protocol.bedrock.data.inventory.ContainerType;
import com.nukkitx.protocol.bedrock.data.inventory.StackRequestSlotInfoData;
import org.geysermc.connector.network.translators.inventory.BedrockContainerSlot;
import org.geysermc.connector.network.translators.inventory.SlotType;
import org.geysermc.connector.network.translators.inventory.updater.CursorInventoryUpdater;
import org.geysermc.connector.network.translators.inventory.updater.UIInventoryUpdater;
public class CraftingInventoryTranslator extends AbstractBlockInventoryTranslator {
public CraftingInventoryTranslator() {
super(10, "minecraft:crafting_table", ContainerType.WORKBENCH, CursorInventoryUpdater.INSTANCE);
super(10, "minecraft:crafting_table", ContainerType.WORKBENCH, UIInventoryUpdater.INSTANCE);
}
@Override

View file

@ -25,11 +25,195 @@
package org.geysermc.connector.network.translators.inventory.translators;
import com.github.steveice10.mc.protocol.data.game.window.WindowType;
import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientClickWindowButtonPacket;
import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType;
import com.nukkitx.protocol.bedrock.data.inventory.ContainerType;
import org.geysermc.connector.network.translators.inventory.updater.CursorInventoryUpdater;
import com.nukkitx.protocol.bedrock.data.inventory.EnchantOptionData;
import com.nukkitx.protocol.bedrock.data.inventory.StackRequestSlotInfoData;
import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.CraftRecipeStackRequestActionData;
import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.StackRequestActionData;
import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.StackRequestActionType;
import com.nukkitx.protocol.bedrock.packet.ItemStackRequestPacket;
import com.nukkitx.protocol.bedrock.packet.ItemStackResponsePacket;
import com.nukkitx.protocol.bedrock.packet.PlayerEnchantOptionsPacket;
import org.geysermc.connector.inventory.EnchantingContainer;
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.BedrockContainerSlot;
import org.geysermc.connector.network.translators.inventory.updater.UIInventoryUpdater;
import org.geysermc.connector.network.translators.item.Enchantment;
import java.util.Arrays;
import java.util.Collections;
public class EnchantingInventoryTranslator extends AbstractBlockInventoryTranslator {
public EnchantingInventoryTranslator() {
super(2, "minecraft:enchanting_table", ContainerType.ENCHANTMENT, CursorInventoryUpdater.INSTANCE);
super(2, "minecraft:enchanting_table", ContainerType.ENCHANTMENT, UIInventoryUpdater.INSTANCE);
}
@Override
public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) {
int slotToUpdate;
EnchantingContainer enchantingInventory = (EnchantingContainer) inventory;
boolean shouldUpdate = false;
switch (key) {
case 0:
case 1:
case 2:
// Experience required
slotToUpdate = key;
enchantingInventory.getGeyserEnchantOptions()[slotToUpdate].setXpCost(value);
break;
case 4:
case 5:
case 6:
// Enchantment type
slotToUpdate = key - 4;
int index = value;
if (index != -1) {
Enchantment enchantment = Enchantment.getByJavaIdentifier("minecraft:" + JavaEnchantment.values()[index].name().toLowerCase());
if (enchantment != null) {
// Convert the Java enchantment index to Bedrock's
index = enchantment.ordinal();
} else {
index = -1;
}
}
enchantingInventory.getGeyserEnchantOptions()[slotToUpdate].setJavaEnchantIndex(value);
enchantingInventory.getGeyserEnchantOptions()[slotToUpdate].setBedrockEnchantIndex(index);
break;
case 7:
case 8:
case 9:
// Enchantment level
slotToUpdate = key - 7;
enchantingInventory.getGeyserEnchantOptions()[slotToUpdate].setEnchantLevel(value);
shouldUpdate = true; // Java sends each property as its own packet, so let's only update after all properties have been sent
break;
default:
return;
}
if (shouldUpdate) {
enchantingInventory.getEnchantOptions()[slotToUpdate] = enchantingInventory.getGeyserEnchantOptions()[slotToUpdate].build(session);
PlayerEnchantOptionsPacket packet = new PlayerEnchantOptionsPacket();
packet.getOptions().addAll(Arrays.asList(enchantingInventory.getEnchantOptions()));
System.out.println(packet);
session.sendUpstreamPacket(packet);
}
}
@Override
public boolean shouldHandleRequestFirst(StackRequestActionData action) {
return action.getType() == StackRequestActionType.CRAFT_RECIPE;
}
@Override
public ItemStackResponsePacket.Response translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) {
// Client has requested an item to be enchanted
CraftRecipeStackRequestActionData craftRecipeData = (CraftRecipeStackRequestActionData) request.getActions()[0];
EnchantingContainer enchantingInventory = (EnchantingContainer) inventory;
int javaSlot = -1;
for (int i = 0; i < enchantingInventory.getEnchantOptions().length; i++) {
EnchantOptionData enchantData = enchantingInventory.getEnchantOptions()[i];
if (enchantData != null) {
if (craftRecipeData.getRecipeNetworkId() == enchantData.getEnchantNetId()) {
// Enchant net ID is how we differentiate between what item Bedrock wants
javaSlot = enchantingInventory.getGeyserEnchantOptions()[i].getJavaIndex();
break;
}
}
}
if (javaSlot == -1) {
// Slot should be determined as 0, 1, or 2
throw new RuntimeException("Cannot find enchant slot for item!");
}
ClientClickWindowButtonPacket packet = new ClientClickWindowButtonPacket(inventory.getId(), javaSlot);
System.out.println(packet);
session.sendDownstreamPacket(packet);
return acceptRequest(request, makeContainerEntries(session, inventory, Collections.emptySet()));
}
@Override
public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) {
if (slotInfoData.getContainer() == ContainerSlotType.ENCHANTING_INPUT) {
return 0;
}
if (slotInfoData.getContainer() == ContainerSlotType.ENCHANTING_LAPIS) {
return 1;
}
return super.bedrockSlotToJava(slotInfoData);
}
@Override
public BedrockContainerSlot javaSlotToBedrockContainer(int slot) {
if (slot == 0) {
return new BedrockContainerSlot(ContainerSlotType.ENCHANTING_INPUT, 14);
}
if (slot == 1) {
return new BedrockContainerSlot(ContainerSlotType.ENCHANTING_LAPIS, 15);
}
return super.javaSlotToBedrockContainer(slot);
}
@Override
public int javaSlotToBedrock(int slot) {
if (slot == 0) {
return 14;
}
if (slot == 1) {
return 15;
}
return super.javaSlotToBedrock(slot);
}
@Override
public Inventory createInventory(String name, int windowId, WindowType windowType, PlayerInventory playerInventory) {
return new EnchantingContainer(name, windowId, windowType, this.size, playerInventory);
}
/**
* Enchantments classified by their Java index
*/
public enum JavaEnchantment {
PROTECTION,
FIRE_PROTECTION,
FEATHER_FALLING,
BLAST_PROTECTION,
PROJECTILE_PROTECTION,
RESPIRATION,
AQUA_AFFINITY,
THORNS,
DEPTH_STRIDER,
FROST_WALKER,
BINDING_CURSE,
SOUL_SPEED,
SHARPNESS,
SMITE,
BANE_OF_ARTHROPODS,
KNOCKBACK,
FIRE_ASPECT,
LOOTING,
SWEEPING,
EFFICIENCY,
SILK_TOUCH,
UNBREAKING,
FORTUNE,
POWER,
PUNCH,
FLAME,
INFINITY,
LUCK_OF_THE_SEA,
LURE,
LOYALTY,
IMPALING,
RIPTIDE,
CHANNELING,
MULTISHOT,
QUICK_CHARGE,
PIERCING,
MENDING,
VANISHING_CURSE
}
}

View file

@ -29,11 +29,11 @@ import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType;
import com.nukkitx.protocol.bedrock.data.inventory.ContainerType;
import com.nukkitx.protocol.bedrock.data.inventory.StackRequestSlotInfoData;
import org.geysermc.connector.network.translators.inventory.BedrockContainerSlot;
import org.geysermc.connector.network.translators.inventory.updater.CursorInventoryUpdater;
import org.geysermc.connector.network.translators.inventory.updater.UIInventoryUpdater;
public class GrindstoneInventoryTranslator extends AbstractBlockInventoryTranslator {
public GrindstoneInventoryTranslator() {
super(3, "minecraft:grindstone[face=floor,facing=north]", ContainerType.GRINDSTONE, CursorInventoryUpdater.INSTANCE);
super(3, "minecraft:grindstone[face=floor,facing=north]", ContainerType.GRINDSTONE, UIInventoryUpdater.INSTANCE);
}
@Override

View file

@ -44,12 +44,11 @@ import org.geysermc.connector.network.translators.inventory.updater.InventoryUpd
import org.geysermc.connector.network.translators.inventory.updater.UIInventoryUpdater;
public class MerchantInventoryTranslator extends BaseInventoryTranslator {
private final InventoryUpdater updater;
public MerchantInventoryTranslator() {
super(3);
this.updater = new UIInventoryUpdater();
this.updater = UIInventoryUpdater.INSTANCE;
}
@Override

View file

@ -29,11 +29,11 @@ import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType;
import com.nukkitx.protocol.bedrock.data.inventory.ContainerType;
import com.nukkitx.protocol.bedrock.data.inventory.StackRequestSlotInfoData;
import org.geysermc.connector.network.translators.inventory.BedrockContainerSlot;
import org.geysermc.connector.network.translators.inventory.updater.CursorInventoryUpdater;
import org.geysermc.connector.network.translators.inventory.updater.UIInventoryUpdater;
public class SmithingInventoryTranslator extends AbstractBlockInventoryTranslator {
public SmithingInventoryTranslator() {
super(3, "minecraft:smithing_table", ContainerType.SMITHING_TABLE, CursorInventoryUpdater.INSTANCE);
super(3, "minecraft:smithing_table", ContainerType.SMITHING_TABLE, UIInventoryUpdater.INSTANCE);
}
@Override

View file

@ -1,65 +0,0 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.connector.network.translators.inventory.updater;
import com.nukkitx.protocol.bedrock.data.inventory.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.inventory.InventoryTranslator;
public class CursorInventoryUpdater extends InventoryUpdater {
public static final CursorInventoryUpdater INSTANCE = new CursorInventoryUpdater();
@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.UI);
slotPacket.setSlot(bedrockSlot);
slotPacket.setItem(inventory.getItem(i).getItemData(session));
session.sendUpstreamPacket(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.UI);
slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot));
slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session));
session.sendUpstreamPacket(slotPacket);
return true;
}
}

View file

@ -30,9 +30,9 @@ 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.inventory.InventoryTranslator;
import org.geysermc.connector.network.translators.item.ItemTranslator;
public class UIInventoryUpdater extends InventoryUpdater {
public static final UIInventoryUpdater INSTANCE = new UIInventoryUpdater();
@Override
public void updateInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) {

View file

@ -38,6 +38,7 @@ public class JavaWindowPropertyTranslator extends PacketTranslator<ServerWindowP
@Override
public void translate(ServerWindowPropertyPacket packet, GeyserSession session) {
System.out.println(packet.toString());
session.addInventoryTask(() -> {
Inventory inventory = InventoryUtils.getInventory(session, packet.getWindowId());
if (inventory == null)