mirror of
https://github.com/ViaVersion/ViaVersion.git
synced 2024-11-22 10:05:12 +01:00
Implement showShieldWhenSwordInHand option (#2417)
This commit is contained in:
parent
26bbc92f94
commit
e83686d6fc
@ -79,10 +79,22 @@ public interface ViaVersionConfig {
|
||||
/**
|
||||
* Whether the player can block with the shield without a delay.
|
||||
*
|
||||
* This option requires {@link #isShowShieldWhenSwordInHand()} to be disabled
|
||||
*
|
||||
* @return {@code true} if non delayed shield blocking is enabled.
|
||||
*/
|
||||
boolean isNoDelayShieldBlocking();
|
||||
|
||||
/**
|
||||
* Puts the shield into the second hand when holding a sword.
|
||||
* The shield will disappear when switching to another item.
|
||||
*
|
||||
* This option requires {@link #isShieldBlocking()} to be enabled
|
||||
*
|
||||
* @return {@code true} if the shield should appear when holding a sword
|
||||
*/
|
||||
boolean isShowShieldWhenSwordInHand();
|
||||
|
||||
/**
|
||||
* Get if armor stand positions are fixed so holograms show up at the correct height in 1.9 & 1.10
|
||||
*
|
||||
|
@ -33,6 +33,7 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
|
||||
private boolean suppressMetadataErrors;
|
||||
private boolean shieldBlocking;
|
||||
private boolean noDelayShieldBlocking;
|
||||
private boolean showShieldWhenSwordInHand;
|
||||
private boolean hologramPatch;
|
||||
private boolean pistonAnimationPatch;
|
||||
private boolean bossbarPatch;
|
||||
@ -93,6 +94,7 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
|
||||
suppressMetadataErrors = getBoolean("suppress-metadata-errors", false);
|
||||
shieldBlocking = getBoolean("shield-blocking", true);
|
||||
noDelayShieldBlocking = getBoolean("no-delay-shield-blocking", false);
|
||||
showShieldWhenSwordInHand = getBoolean("show-shield-when-sword-in-hand", false);
|
||||
hologramPatch = getBoolean("hologram-patch", false);
|
||||
pistonAnimationPatch = getBoolean("piston-animation-patch", false);
|
||||
bossbarPatch = getBoolean("bossbar-patch", true);
|
||||
@ -177,6 +179,11 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
|
||||
return noDelayShieldBlocking;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShowShieldWhenSwordInHand() {
|
||||
return showShieldWhenSwordInHand;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHologramPatch() {
|
||||
return hologramPatch;
|
||||
|
@ -18,6 +18,7 @@
|
||||
package us.myles.ViaVersion.protocols.protocol1_9to1_8.packets;
|
||||
|
||||
import us.myles.ViaVersion.api.PacketWrapper;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.api.minecraft.item.Item;
|
||||
import us.myles.ViaVersion.api.protocol.Protocol;
|
||||
import us.myles.ViaVersion.api.remapper.PacketHandler;
|
||||
@ -113,6 +114,25 @@ public class InventoryPackets {
|
||||
@Override
|
||||
public void handle(PacketWrapper wrapper) throws Exception {
|
||||
Item stack = wrapper.get(Type.ITEM, 0);
|
||||
|
||||
boolean showShieldWhenSwordInHand = Via.getConfig().isShowShieldWhenSwordInHand()
|
||||
&& Via.getConfig().isShieldBlocking();
|
||||
|
||||
// Check if it is the inventory of the player
|
||||
if (showShieldWhenSwordInHand) {
|
||||
InventoryTracker inventoryTracker = wrapper.user().get(InventoryTracker.class);
|
||||
EntityTracker1_9 entityTracker = wrapper.user().get(EntityTracker1_9.class);
|
||||
|
||||
short slotID = wrapper.get(Type.SHORT, 0);
|
||||
short windowId = wrapper.get(Type.BYTE, 0);
|
||||
|
||||
// Store item in slot
|
||||
inventoryTracker.setItemId(windowId, slotID, stack == null ? 0 : stack.getIdentifier());
|
||||
|
||||
// Sync shield item in offhand with main hand
|
||||
entityTracker.syncShieldWithSword();
|
||||
}
|
||||
|
||||
ItemRewriter.toClient(stack);
|
||||
}
|
||||
});
|
||||
@ -145,8 +165,29 @@ public class InventoryPackets {
|
||||
@Override
|
||||
public void handle(PacketWrapper wrapper) throws Exception {
|
||||
Item[] stacks = wrapper.get(Type.ITEM_ARRAY, 0);
|
||||
for (Item stack : stacks)
|
||||
Short windowId = wrapper.get(Type.UNSIGNED_BYTE, 0);
|
||||
|
||||
InventoryTracker inventoryTracker = wrapper.user().get(InventoryTracker.class);
|
||||
EntityTracker1_9 entityTracker = wrapper.user().get(EntityTracker1_9.class);
|
||||
|
||||
boolean showShieldWhenSwordInHand = Via.getConfig().isShowShieldWhenSwordInHand()
|
||||
&& Via.getConfig().isShieldBlocking();
|
||||
|
||||
for (short i = 0; i < stacks.length; i++) {
|
||||
Item stack = stacks[i];
|
||||
|
||||
// Store items in slots
|
||||
if (showShieldWhenSwordInHand) {
|
||||
inventoryTracker.setItemId(windowId, i, stack == null ? 0 : stack.getIdentifier());
|
||||
}
|
||||
|
||||
ItemRewriter.toClient(stack);
|
||||
}
|
||||
|
||||
// Sync shield item in offhand with main hand
|
||||
if (showShieldWhenSwordInHand) {
|
||||
entityTracker.syncShieldWithSword();
|
||||
}
|
||||
}
|
||||
});
|
||||
// Brewing Patch
|
||||
@ -185,6 +226,7 @@ public class InventoryPackets {
|
||||
public void handle(PacketWrapper wrapper) throws Exception {
|
||||
InventoryTracker inventoryTracker = wrapper.user().get(InventoryTracker.class);
|
||||
inventoryTracker.setInventory(null);
|
||||
inventoryTracker.resetInventory(wrapper.get(Type.UNSIGNED_BYTE, 0));
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -218,6 +260,22 @@ public class InventoryPackets {
|
||||
@Override
|
||||
public void handle(PacketWrapper wrapper) throws Exception {
|
||||
Item stack = wrapper.get(Type.ITEM, 0);
|
||||
|
||||
boolean showShieldWhenSwordInHand = Via.getConfig().isShowShieldWhenSwordInHand()
|
||||
&& Via.getConfig().isShieldBlocking();
|
||||
|
||||
if (showShieldWhenSwordInHand) {
|
||||
InventoryTracker inventoryTracker = wrapper.user().get(InventoryTracker.class);
|
||||
EntityTracker1_9 entityTracker = wrapper.user().get(EntityTracker1_9.class);
|
||||
short slotID = wrapper.get(Type.SHORT, 0);
|
||||
|
||||
// Update item in slot
|
||||
inventoryTracker.setItemId((short) 0, slotID, stack == null ? 0 : stack.getIdentifier());
|
||||
|
||||
// Sync shield item in offhand with main hand
|
||||
entityTracker.syncShieldWithSword();
|
||||
}
|
||||
|
||||
ItemRewriter.toServer(stack);
|
||||
}
|
||||
});
|
||||
@ -259,6 +317,18 @@ public class InventoryPackets {
|
||||
@Override
|
||||
public void handle(PacketWrapper wrapper) throws Exception {
|
||||
Item stack = wrapper.get(Type.ITEM, 0);
|
||||
|
||||
if (Via.getConfig().isShowShieldWhenSwordInHand()) {
|
||||
Short windowId = wrapper.get(Type.UNSIGNED_BYTE, 0);
|
||||
byte mode = wrapper.get(Type.BYTE, 1);
|
||||
short hoverSlot = wrapper.get(Type.SHORT, 0);
|
||||
byte button = wrapper.get(Type.BYTE, 0);
|
||||
|
||||
// Move items in inventory to track the sword location
|
||||
InventoryTracker inventoryTracker = wrapper.user().get(InventoryTracker.class);
|
||||
inventoryTracker.handleWindowClick(windowId, mode, hoverSlot, button);
|
||||
}
|
||||
|
||||
ItemRewriter.toServer(stack);
|
||||
}
|
||||
});
|
||||
@ -305,12 +375,15 @@ public class InventoryPackets {
|
||||
|
||||
@Override
|
||||
public void registerMap() {
|
||||
map(Type.UNSIGNED_BYTE); // 0 - Window ID
|
||||
|
||||
// Inventory tracking
|
||||
handler(new PacketHandler() {
|
||||
@Override
|
||||
public void handle(PacketWrapper wrapper) throws Exception {
|
||||
InventoryTracker inventoryTracker = wrapper.user().get(InventoryTracker.class);
|
||||
inventoryTracker.setInventory(null);
|
||||
inventoryTracker.resetInventory(wrapper.get(Type.UNSIGNED_BYTE, 0));
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -319,14 +392,30 @@ public class InventoryPackets {
|
||||
protocol.registerIncoming(ServerboundPackets1_9.HELD_ITEM_CHANGE, new PacketRemapper() {
|
||||
@Override
|
||||
public void registerMap() {
|
||||
map(Type.SHORT); // 0 - Slot id
|
||||
|
||||
// Blocking patch
|
||||
handler(new PacketHandler() {
|
||||
@Override
|
||||
public void handle(PacketWrapper wrapper) throws Exception {
|
||||
boolean showShieldWhenSwordInHand = Via.getConfig().isShowShieldWhenSwordInHand()
|
||||
&& Via.getConfig().isShieldBlocking();
|
||||
|
||||
EntityTracker1_9 entityTracker = wrapper.user().get(EntityTracker1_9.class);
|
||||
if (entityTracker.isBlocking()) {
|
||||
entityTracker.setBlocking(false);
|
||||
entityTracker.setSecondHand(null);
|
||||
|
||||
if (!showShieldWhenSwordInHand) {
|
||||
entityTracker.setSecondHand(null);
|
||||
}
|
||||
}
|
||||
|
||||
if (showShieldWhenSwordInHand) {
|
||||
// Update current held item slot index
|
||||
entityTracker.setHeldItemSlot(wrapper.get(Type.SHORT, 0));
|
||||
|
||||
// Sync shield item in offhand with main hand
|
||||
entityTracker.syncShieldWithSword();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -498,7 +498,9 @@ public class PlayerPackets {
|
||||
// cancel any blocking >.>
|
||||
EntityTracker1_9 tracker = wrapper.user().get(EntityTracker1_9.class);
|
||||
if (tracker.isBlocking()) {
|
||||
tracker.setSecondHand(null);
|
||||
if(!Via.getConfig().isShowShieldWhenSwordInHand()) {
|
||||
tracker.setSecondHand(null);
|
||||
}
|
||||
tracker.setBlocking(false);
|
||||
}
|
||||
}
|
||||
|
@ -269,7 +269,9 @@ public class WorldPackets {
|
||||
EntityTracker1_9 entityTracker = wrapper.user().get(EntityTracker1_9.class);
|
||||
if (entityTracker.isBlocking()) {
|
||||
entityTracker.setBlocking(false);
|
||||
entityTracker.setSecondHand(null);
|
||||
if (!Via.getConfig().isShowShieldWhenSwordInHand()) {
|
||||
entityTracker.setSecondHand(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -296,23 +298,36 @@ public class WorldPackets {
|
||||
if (Via.getConfig().isShieldBlocking()) {
|
||||
EntityTracker1_9 tracker = wrapper.user().get(EntityTracker1_9.class);
|
||||
|
||||
// Check if the shield is already there or if we have to give it here
|
||||
boolean showShieldWhenSwordInHand = Via.getConfig().isShowShieldWhenSwordInHand();
|
||||
|
||||
if (item != null && Protocol1_9To1_8.isSword(item.getIdentifier())) {
|
||||
if (hand == 0) {
|
||||
if (!tracker.isBlocking()) {
|
||||
tracker.setBlocking(true);
|
||||
Item shield = new Item(442, (byte) 1, (short) 0, null);
|
||||
tracker.setSecondHand(shield);
|
||||
|
||||
// Check if the shield is already in the offhand
|
||||
if (!showShieldWhenSwordInHand || tracker.getItemInSecondHand() == null) {
|
||||
|
||||
// Set shield in offhand when interacting with main hand
|
||||
Item shield = new Item(442, (byte) 1, (short) 0, null);
|
||||
tracker.setSecondHand(shield);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Uses left or right hand to start blocking depending on the no delay setting
|
||||
boolean noDelayBlocking = Via.getConfig().isNoDelayShieldBlocking();
|
||||
// Use the main hand to trigger the blocking
|
||||
boolean blockUsingMainHand = Via.getConfig().isNoDelayShieldBlocking()
|
||||
&& !showShieldWhenSwordInHand;
|
||||
|
||||
if (noDelayBlocking && hand == 1 || !noDelayBlocking && hand == 0) {
|
||||
if (blockUsingMainHand && hand == 1 || !blockUsingMainHand && hand == 0) {
|
||||
wrapper.cancel();
|
||||
}
|
||||
} else {
|
||||
tracker.setSecondHand(null);
|
||||
if (!showShieldWhenSwordInHand) {
|
||||
// Remove the shield from the offhand
|
||||
tracker.setSecondHand(null);
|
||||
}
|
||||
tracker.setBlocking(false);
|
||||
}
|
||||
}
|
||||
|
@ -66,6 +66,8 @@ public class EntityTracker1_9 extends EntityTracker {
|
||||
private boolean teamExists = false;
|
||||
private GameMode gameMode;
|
||||
private String currentTeam;
|
||||
private int heldItemSlot;
|
||||
private Item itemInSecondHand = null;
|
||||
|
||||
public EntityTracker1_9(UserConnection user) {
|
||||
super(user, EntityType.PLAYER);
|
||||
@ -89,7 +91,7 @@ public class EntityTracker1_9 extends EntityTracker {
|
||||
PacketWrapper wrapper = new PacketWrapper(0x3C, null, getUser());
|
||||
wrapper.write(Type.VAR_INT, entityID);
|
||||
wrapper.write(Type.VAR_INT, 1); // slot
|
||||
wrapper.write(Type.ITEM, item);
|
||||
wrapper.write(Type.ITEM, this.itemInSecondHand = item);
|
||||
try {
|
||||
wrapper.send(Protocol1_9To1_8.class);
|
||||
} catch (Exception e) {
|
||||
@ -97,6 +99,31 @@ public class EntityTracker1_9 extends EntityTracker {
|
||||
}
|
||||
}
|
||||
|
||||
public Item getItemInSecondHand() {
|
||||
return itemInSecondHand;
|
||||
}
|
||||
|
||||
/**
|
||||
* It will set a shield to the offhand if a sword is in the main hand.
|
||||
* The item in the offhand will be cleared if there is no sword in the main hand.
|
||||
*/
|
||||
public void syncShieldWithSword() {
|
||||
InventoryTracker inventoryTracker = getUser().get(InventoryTracker.class);
|
||||
|
||||
// Get item in new selected slot
|
||||
int inventorySlot = this.heldItemSlot + 36; // Hotbar slot index to inventory slot
|
||||
int itemIdentifier = inventoryTracker.getItemId((short) 0, (short) inventorySlot);
|
||||
|
||||
boolean isSword = Protocol1_9To1_8.isSword(itemIdentifier);
|
||||
|
||||
// Update if the state changed
|
||||
if (isSword == (this.itemInSecondHand == null)) {
|
||||
|
||||
// Update shield in off hand depending if a sword is in the main hand
|
||||
setSecondHand(isSword ? new Item(442, (byte) 1, (short) 0, null) : null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeEntity(int entityId) {
|
||||
super.removeEntity(entityId);
|
||||
@ -395,4 +422,8 @@ public class EntityTracker1_9 extends EntityTracker {
|
||||
public void setCurrentTeam(String currentTeam) {
|
||||
this.currentTeam = currentTeam;
|
||||
}
|
||||
|
||||
public void setHeldItemSlot(int heldItemSlot) {
|
||||
this.heldItemSlot = heldItemSlot;
|
||||
}
|
||||
}
|
||||
|
@ -20,9 +20,16 @@ package us.myles.ViaVersion.protocols.protocol1_9to1_8.storage;
|
||||
import us.myles.ViaVersion.api.data.StoredObject;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class InventoryTracker extends StoredObject {
|
||||
private String inventory;
|
||||
|
||||
private final Map<Short, Map<Short, Integer>> windowItemCache = new HashMap<>();
|
||||
private int itemIdInCursor = 0;
|
||||
private boolean dragging = false;
|
||||
|
||||
public InventoryTracker(UserConnection user) {
|
||||
super(user);
|
||||
}
|
||||
@ -34,4 +41,142 @@ public class InventoryTracker extends StoredObject {
|
||||
public void setInventory(String inventory) {
|
||||
this.inventory = inventory;
|
||||
}
|
||||
|
||||
public void resetInventory(short windowId) {
|
||||
// Reset the cursor state of the inventory
|
||||
if (inventory == null) {
|
||||
this.itemIdInCursor = 0;
|
||||
this.dragging = false;
|
||||
|
||||
// Remove window from cache (Except players window)
|
||||
if (windowId != 0) {
|
||||
this.windowItemCache.remove(windowId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getItemId(short windowId, short slot) {
|
||||
Map<Short, Integer> itemMap = this.windowItemCache.get(windowId);
|
||||
if (itemMap == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return itemMap.getOrDefault(slot, 0);
|
||||
}
|
||||
|
||||
public void setItemId(short windowId, short slot, int itemId) {
|
||||
if (windowId == -1 && slot == -1) {
|
||||
// Set the cursor item
|
||||
this.itemIdInCursor = itemId;
|
||||
} else {
|
||||
// Set item in normal inventory
|
||||
this.windowItemCache.computeIfAbsent(windowId, k -> new HashMap<>()).put(slot, itemId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the window click to track the position of the sword
|
||||
*
|
||||
* @param windowId Id of the current inventory
|
||||
* @param mode Inventory operation mode
|
||||
* @param hoverSlot The slot number of the current mouse position
|
||||
* @param button The button to use in the click
|
||||
*/
|
||||
public void handleWindowClick(short windowId, byte mode, short hoverSlot, byte button) {
|
||||
EntityTracker1_9 entityTracker = getUser().get(EntityTracker1_9.class);
|
||||
|
||||
// Skip inventory background clicks
|
||||
if (hoverSlot == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Interaction with the offhand slot
|
||||
if (hoverSlot == 45) {
|
||||
entityTracker.setSecondHand(null); // Remove it so we know that we can update it on ITEM_USE
|
||||
return;
|
||||
}
|
||||
|
||||
// It is not possible to put a sword into the armor or crafting result slot
|
||||
boolean isArmorOrResultSlot = hoverSlot >= 5 && hoverSlot <= 8 || hoverSlot == 0;
|
||||
|
||||
switch (mode) {
|
||||
case 0: // Click on slot
|
||||
|
||||
// The cursor is empty, so we can put an item to it
|
||||
if (this.itemIdInCursor == 0) {
|
||||
// Move item to cursor
|
||||
this.itemIdInCursor = getItemId(windowId, hoverSlot);
|
||||
|
||||
// Remove item in slot
|
||||
setItemId(windowId, hoverSlot, 0);
|
||||
} else {
|
||||
// Dropping item
|
||||
if (hoverSlot == -999) {
|
||||
this.itemIdInCursor = 0;
|
||||
} else if (!isArmorOrResultSlot) {
|
||||
int previousItem = getItemId(windowId, hoverSlot);
|
||||
|
||||
// Place item in inventory
|
||||
setItemId(windowId, hoverSlot, this.itemIdInCursor);
|
||||
|
||||
// Pick up the other item
|
||||
this.itemIdInCursor = previousItem;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2: // Move item using number keys
|
||||
if (!isArmorOrResultSlot) {
|
||||
short hotkeySlot = (short) (button + 36);
|
||||
|
||||
// Get items to swap
|
||||
int sourceItem = getItemId(windowId, hoverSlot);
|
||||
int destinationItem = getItemId(windowId, hotkeySlot);
|
||||
|
||||
// Swap
|
||||
setItemId(windowId, hotkeySlot, sourceItem);
|
||||
setItemId(windowId, hoverSlot, destinationItem);
|
||||
}
|
||||
|
||||
break;
|
||||
case 4: // Drop item
|
||||
int hoverItem = getItemId(windowId, hoverSlot);
|
||||
|
||||
if (hoverItem != 0) {
|
||||
setItemId(windowId, hoverSlot, 0);
|
||||
}
|
||||
|
||||
break;
|
||||
case 5: // Mouse dragging
|
||||
switch (button) {
|
||||
case 0: // Start left dragging
|
||||
case 4: // Start right dragging
|
||||
this.dragging = true;
|
||||
break;
|
||||
case 1: // Place item during left dragging
|
||||
case 5: // Place item during right dragging
|
||||
// Check dragging mode and item on cursor
|
||||
if (this.dragging && this.itemIdInCursor != 0 && !isArmorOrResultSlot) {
|
||||
int previousItem = getItemId(windowId, hoverSlot);
|
||||
|
||||
// Place item on cursor in hovering slot
|
||||
setItemId(windowId, hoverSlot, this.itemIdInCursor);
|
||||
|
||||
// Pick up the other item
|
||||
this.itemIdInCursor = previousItem;
|
||||
}
|
||||
break;
|
||||
case 2: // Stop left dragging
|
||||
case 6: // Stop right dragging
|
||||
this.dragging = false;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Update shield state in offhand
|
||||
entityTracker.syncShieldWithSword();
|
||||
}
|
||||
}
|
||||
|
@ -169,7 +169,12 @@ suppress-metadata-errors: false
|
||||
shield-blocking: true
|
||||
# If this setting is active, the main hand is used instead of the off hand to trigger the blocking of the player.
|
||||
# With the main hand the blocking starts way faster.
|
||||
# (Requires "show-shield-when-sword-in-hand" to be disabled)
|
||||
no-delay-shield-blocking: false
|
||||
# If this setting is active, the shield will appear immediately for 1.9+ when you hold a sword in your main hand.
|
||||
# The shield disappears when you switch to another item.
|
||||
# (Requires "shield-blocking" to be enabled)
|
||||
show-shield-when-sword-in-hand: false
|
||||
# Enable player tick simulation, this fixes eating, drinking, nether portals.
|
||||
simulate-pt: true
|
||||
# Should we use nms player to simulate packets, (may fix anti-cheat issues)
|
||||
|
Loading…
Reference in New Issue
Block a user