Fix item enchanting pre-1.14 (#2127)

If the server spams the window property update packet, then the network ID assigned for each enchanting slot will update too quickly, essentially disabling enchanting. This commit remedies this by only updating the network ID of each slot if a property changed.
This commit is contained in:
Camotoy 2021-04-16 11:42:03 -04:00 committed by GitHub
parent beb7e54b7a
commit 852d5b050d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 46 additions and 11 deletions

View file

@ -28,7 +28,6 @@ package org.geysermc.connector.inventory;
import com.nukkitx.protocol.bedrock.data.inventory.EnchantData; import com.nukkitx.protocol.bedrock.data.inventory.EnchantData;
import com.nukkitx.protocol.bedrock.data.inventory.EnchantOptionData; import com.nukkitx.protocol.bedrock.data.inventory.EnchantOptionData;
import lombok.Getter; import lombok.Getter;
import lombok.Setter;
import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.session.GeyserSession;
import java.util.Arrays; import java.util.Arrays;
@ -38,7 +37,6 @@ import java.util.List;
/** /**
* A mutable "wrapper" around {@link EnchantOptionData} * A mutable "wrapper" around {@link EnchantOptionData}
*/ */
@Setter
public class GeyserEnchantOption { public class GeyserEnchantOption {
private static final List<EnchantData> EMPTY = Collections.emptyList(); private static final List<EnchantData> EMPTY = Collections.emptyList();
/** /**
@ -57,6 +55,12 @@ public class GeyserEnchantOption {
@Getter @Getter
private final int javaIndex; private final int javaIndex;
/**
* Whether the enchantment details have actually changed.
* Used to mitigate weird packet spamming pre-1.14, causing the net ID to always update.
*/
private boolean hasChanged;
private int xpCost = 0; private int xpCost = 0;
private int javaEnchantIndex = -1; private int javaEnchantIndex = -1;
private int bedrockEnchantIndex = -1; private int bedrockEnchantIndex = -1;
@ -67,8 +71,35 @@ public class GeyserEnchantOption {
} }
public EnchantOptionData build(GeyserSession session) { public EnchantOptionData build(GeyserSession session) {
this.hasChanged = false;
return new EnchantOptionData(xpCost, javaIndex + 16, EMPTY, return new EnchantOptionData(xpCost, javaIndex + 16, EMPTY,
enchantLevel == -1 ? EMPTY : Collections.singletonList(new EnchantData(bedrockEnchantIndex, enchantLevel)), EMPTY, enchantLevel == -1 ? EMPTY : Collections.singletonList(new EnchantData(bedrockEnchantIndex, enchantLevel)), EMPTY,
javaEnchantIndex == -1 ? "unknown" : ENCHANT_NAMES.get(javaEnchantIndex), enchantLevel == -1 ? 0 : session.getNextItemNetId()); javaEnchantIndex == -1 ? "unknown" : ENCHANT_NAMES.get(javaEnchantIndex), enchantLevel == -1 ? 0 : session.getNextItemNetId());
} }
public boolean hasChanged() {
return hasChanged;
}
public void setXpCost(int xpCost) {
if (this.xpCost != xpCost) {
hasChanged = true;
this.xpCost = xpCost;
}
}
public void setEnchantIndex(int javaEnchantIndex, int bedrockEnchantIndex) {
if (this.javaEnchantIndex != javaEnchantIndex) {
hasChanged = true;
this.javaEnchantIndex = javaEnchantIndex;
this.bedrockEnchantIndex = bedrockEnchantIndex;
}
}
public void setEnchantLevel(int enchantLevel) {
if (this.enchantLevel != enchantLevel) {
hasChanged = true;
this.enchantLevel = enchantLevel;
}
}
} }

View file

@ -34,6 +34,7 @@ import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.StackRequ
import com.nukkitx.protocol.bedrock.packet.ItemStackResponsePacket; import com.nukkitx.protocol.bedrock.packet.ItemStackResponsePacket;
import com.nukkitx.protocol.bedrock.packet.PlayerEnchantOptionsPacket; import com.nukkitx.protocol.bedrock.packet.PlayerEnchantOptionsPacket;
import org.geysermc.connector.inventory.EnchantingContainer; import org.geysermc.connector.inventory.EnchantingContainer;
import org.geysermc.connector.inventory.GeyserEnchantOption;
import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.inventory.Inventory;
import org.geysermc.connector.inventory.PlayerInventory; import org.geysermc.connector.inventory.PlayerInventory;
import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.session.GeyserSession;
@ -67,18 +68,20 @@ public class EnchantingInventoryTranslator extends AbstractBlockInventoryTransla
case 6: case 6:
// Enchantment type // Enchantment type
slotToUpdate = key - 4; slotToUpdate = key - 4;
int index = value; // "value" here is the Java enchant ordinal, so that does not need to be changed
if (index != -1) { // The Bedrock index might need changed, so let's look it up and see.
Enchantment enchantment = Enchantment.getByJavaIdentifier("minecraft:" + JavaEnchantment.values()[index].name().toLowerCase()); int bedrockIndex = value;
if (bedrockIndex != -1) {
Enchantment enchantment = Enchantment.getByJavaIdentifier("minecraft:" + JavaEnchantment.values()[bedrockIndex].name().toLowerCase());
if (enchantment != null) { if (enchantment != null) {
// Convert the Java enchantment index to Bedrock's // Convert the Java enchantment index to Bedrock's
index = enchantment.ordinal(); bedrockIndex = enchantment.ordinal();
} else { } else {
index = -1; // There is no Bedrock enchantment equivalent
bedrockIndex = -1;
} }
} }
enchantingInventory.getGeyserEnchantOptions()[slotToUpdate].setJavaEnchantIndex(value); enchantingInventory.getGeyserEnchantOptions()[slotToUpdate].setEnchantIndex(value, bedrockIndex);
enchantingInventory.getGeyserEnchantOptions()[slotToUpdate].setBedrockEnchantIndex(index);
break; break;
case 7: case 7:
case 8: case 8:
@ -91,8 +94,9 @@ public class EnchantingInventoryTranslator extends AbstractBlockInventoryTransla
default: default:
return; return;
} }
if (shouldUpdate) { GeyserEnchantOption enchantOption = enchantingInventory.getGeyserEnchantOptions()[slotToUpdate];
enchantingInventory.getEnchantOptions()[slotToUpdate] = enchantingInventory.getGeyserEnchantOptions()[slotToUpdate].build(session); if (shouldUpdate && enchantOption.hasChanged()) {
enchantingInventory.getEnchantOptions()[slotToUpdate] = enchantOption.build(session);
PlayerEnchantOptionsPacket packet = new PlayerEnchantOptionsPacket(); PlayerEnchantOptionsPacket packet = new PlayerEnchantOptionsPacket();
packet.getOptions().addAll(Arrays.asList(enchantingInventory.getEnchantOptions())); packet.getOptions().addAll(Arrays.asList(enchantingInventory.getEnchantOptions()));
session.sendUpstreamPacket(packet); session.sendUpstreamPacket(packet);