Compare commits

...
31 Commits
Author SHA1 Message Date
Nassim Jahnke 6363cd38ab 5.4.2 Release 2025-07-23 18:41:56 +02:00
Nassim Jahnke 5ca359b287 Fix hidden tooltip in emulated dialog item widgets 2025-07-23 18:38:07 +02:00
Nassim Jahnke c18c670bdb Fix 1.10->1.9 potion entity data 2025-07-22 00:04:13 +02:00
Nassim Jahnke 345406ecae Back up custom attribute modifier ids 2025-07-18 11:06:44 +02:00
Nassim Jahnke 4a159bf16a [ci skip] Split up publishing steps
Putting them into the same step meant if one publish action failed, the second one wouldn't run. Before this change, Modrinth would often block Hangar from publishing
2025-07-17 16:10:46 +02:00
Pantera (Mad_Daniel) 6a2482f42f Fix ADD_ENTITY velocity for non-living entities on 1.21.6+ servers (#1066) 2025-07-15 15:28:43 +02:00
Pantera (Mad_Daniel) 8075d49ad2 Fix sendUnlockedRecipes (#1067) 2025-07-14 22:31:14 +02:00
Nassim Jahnke 36aecf3444 [ci skip] Clean up imports 2025-07-14 12:42:13 +02:00
Nassim Jahnke f0aa7d9dae Fix minecarts losing type in 1.21.5->1.21.4
Fixes #1057
2025-07-13 09:31:04 +02:00
Nassim Jahnke b63e031662 [ci skip] Remove clearOnServerSwitch overrides 2025-07-12 10:37:06 +02:00
EnZaXD 8825ef0f44 [ci skip] Add Java resolving plugin (#1059) 2025-07-12 10:28:37 +02:00
Pantera (Mad_Daniel) eea2687e66 Add limit (#1063) 2025-07-11 10:18:46 +02:00
EnZaXD 712f656a3a Remap UI sound source to master in 1.21.6->1.21.5 (#1056) 2025-07-06 21:17:58 +02:00
Nassim Jahnke 181a0cb7c1 Cache parsed item name and lore in older protocols 2025-07-05 13:04:55 +02:00
Nassim Jahnke b367037cef Bump version to 5.4.2-SNAPSHOT 2025-07-04 13:37:59 +02:00
Nassim Jahnke b90b573f1d 5.4.1 Release 2025-06-30 16:04:55 +02:00
Nassim Jahnke 74aeadd688 1.21.7-rc1/2 2025-06-30 16:04:53 +02:00
riku6460 6f27988cf6 Ensure run_command click events start with '/' in 1.21.5->1.21.4 (#1051) 2025-06-30 16:03:42 +02:00
Nassim Jahnke 81aad86d9f Map waterlogged light to water
Fixes #1038
2025-06-30 12:32:05 +02:00
FlorianMichael 1e7dbf38fd [ci skip] Add SECURITY.md (#1031) 2025-06-29 15:37:05 +02:00
riku6460andFlorianMichael 0404184e15 Use correct tag type to write custom click actions in 1.21.6->.5 (#1050)
Co-authored-by: FlorianMichael <florian.michael07@gmail.com>
2025-06-29 09:45:13 +02:00
FlorianMichael 64a7d9f8bd Strip default namespace when reading types (#1049) 2025-06-28 13:06:10 +02:00
FlorianMichael 924346882c Fix style and remap translations for item description in 1.21.6->.5 dialogs (#1048) 2025-06-28 12:34:32 +02:00
FlorianMichael 1d7332101f Fix run_command and custom click events (#1046) 2025-06-25 09:08:45 +02:00
FlorianMichael 30e63ebc3b Improve multiple text widgets follow one another in dialogs (#1044) 2025-06-24 13:36:19 +02:00
FlorianMichael 217c9459f5 Emulate dialog screens using chest inventories (#1041) 2025-06-23 22:53:59 +02:00
Nassim Jahnke ead2c6f330 Send sneaking command on vehicle exit in 1.21.2->1.21.1
Fixes #1001
2025-06-23 12:26:04 +02:00
Nassim Jahnke 1a972da613 Fix horse saddle handling in 1.21.5->1.21.4 2025-06-23 11:10:47 +02:00
Nassim Jahnke 44dbbf37e2 Remove saddle slot group from enchantments in 1.21.5->1.21.4
Fixes #1033
2025-06-22 22:14:47 +02:00
RK_01 def010c2bf Remap difficulty data type (#1040) 2025-06-21 10:08:55 +02:00
Nassim Jahnke 75744d5525 Bump version to 5.4.1-SNAPSHOT 2025-06-21 09:46:31 +02:00
112 changed files with 3321 additions and 284 deletions

No files matched your search

+9 -2
View File
@@ -23,8 +23,15 @@ jobs:
distribution: 'temurin'
java-version: 17
check-latest: true
- name: Publish
- name: Build
run: ./gradlew build
- name: Publish to Hangar
env:
HANGAR_TOKEN: ${{ secrets.HANGAR_TOKEN }}
run: ./gradlew publishAllPublicationsToHangar --stacktrace
continue-on-error: true
- name: Publish to Modrinth
env:
MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}
run: ./gradlew build modrinth publishAllPublicationsToHangar --refresh-dependencies --stacktrace
run: ./gradlew modrinth --stacktrace
continue-on-error: true
+10
View File
@@ -0,0 +1,10 @@
# Security Policy
## Reporting a Vulnerability
If you discover a **security vulnerability**, please **do not** open a public issue. Instead, use one of the following **confidential contact methods**:
* **Email:** [security@viaversion.com](mailto:security@viaversion.com)
* **Discord:** Join our [Discord server](https://discord.gg/viaversion) and visit the [#exploit-report](https://discord.com/channels/316206679014244363/1388847764137316485) channel for further instructions.
If your issue is **not security-related** (e.g., bug reports, feature requests, or usage questions), please use the [GitHub Issues page](https://github.com/ViaVersion/ViaBackwards/issues) or contact us via the [Discord server](https://discord.gg/viaversion).
+1 -1
View File
@@ -8,5 +8,5 @@ repositories {
dependencies {
// version must be manually kept in sync with the one in root project settings.gradle.kts
implementation("com.gradleup.shadow", "shadow-gradle-plugin", "8.3.6")
implementation("com.gradleup.shadow", "shadow-gradle-plugin", "8.3.8")
}
@@ -21,48 +21,50 @@ package com.viaversion.viabackwards.api;
import com.viaversion.viabackwards.ViaBackwards;
import com.viaversion.viabackwards.ViaBackwardsConfig;
import com.viaversion.viabackwards.api.data.TranslatableMappings;
import com.viaversion.viabackwards.protocol.v1_11to1_10.Protocol1_11To1_10;
import com.viaversion.viabackwards.protocol.v1_12to1_11_1.Protocol1_12To1_11_1;
import com.viaversion.viabackwards.protocol.v1_10to1_9_3.Protocol1_10To1_9_3;
import com.viaversion.viabackwards.protocol.v1_11_1to1_11.Protocol1_11_1To1_11;
import com.viaversion.viabackwards.protocol.v1_12_2to1_12_1.Protocol1_12_2To1_12_1;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.Protocol1_13To1_12_2;
import com.viaversion.viabackwards.protocol.v1_11to1_10.Protocol1_11To1_10;
import com.viaversion.viabackwards.protocol.v1_12_1to1_12.Protocol1_12_1To1_12;
import com.viaversion.viabackwards.protocol.v1_13_2to1_13_1.Protocol1_13_2To1_13_1;
import com.viaversion.viabackwards.protocol.v1_14to1_13_2.Protocol1_14To1_13_2;
import com.viaversion.viabackwards.protocol.v1_12_2to1_12_1.Protocol1_12_2To1_12_1;
import com.viaversion.viabackwards.protocol.v1_12to1_11_1.Protocol1_12To1_11_1;
import com.viaversion.viabackwards.protocol.v1_13_1to1_13.Protocol1_13_1To1_13;
import com.viaversion.viabackwards.protocol.v1_13_2to1_13_1.Protocol1_13_2To1_13_1;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.Protocol1_13To1_12_2;
import com.viaversion.viabackwards.protocol.v1_14_1to1_14.Protocol1_14_1To1_14;
import com.viaversion.viabackwards.protocol.v1_14_2to1_14_1.Protocol1_14_2To1_14_1;
import com.viaversion.viabackwards.protocol.v1_14_3to1_14_2.Protocol1_14_3To1_14_2;
import com.viaversion.viabackwards.protocol.v1_14_4to1_14_3.Protocol1_14_4To1_14_3;
import com.viaversion.viabackwards.protocol.v1_15to1_14_4.Protocol1_15To1_14_4;
import com.viaversion.viabackwards.protocol.v1_14_1to1_14.Protocol1_14_1To1_14;
import com.viaversion.viabackwards.protocol.v1_15_2to1_15_1.Protocol1_15_2To1_15_1;
import com.viaversion.viabackwards.protocol.v1_16to1_15_2.Protocol1_16To1_15_2;
import com.viaversion.viabackwards.protocol.v1_14to1_13_2.Protocol1_14To1_13_2;
import com.viaversion.viabackwards.protocol.v1_15_1to1_15.Protocol1_15_1To1_15;
import com.viaversion.viabackwards.protocol.v1_15_2to1_15_1.Protocol1_15_2To1_15_1;
import com.viaversion.viabackwards.protocol.v1_15to1_14_4.Protocol1_15To1_14_4;
import com.viaversion.viabackwards.protocol.v1_16_1to1_16.Protocol1_16_1To1_16;
import com.viaversion.viabackwards.protocol.v1_16_2to1_16_1.Protocol1_16_2To1_16_1;
import com.viaversion.viabackwards.protocol.v1_16_3to1_16_2.Protocol1_16_3To1_16_2;
import com.viaversion.viabackwards.protocol.v1_16_4to1_16_3.Protocol1_16_4To1_16_3;
import com.viaversion.viabackwards.protocol.v1_17to1_16_4.Protocol1_17To1_16_4;
import com.viaversion.viabackwards.protocol.v1_16_1to1_16.Protocol1_16_1To1_16;
import com.viaversion.viabackwards.protocol.v1_18to1_17_1.Protocol1_18To1_17_1;
import com.viaversion.viabackwards.protocol.v1_16to1_15_2.Protocol1_16To1_15_2;
import com.viaversion.viabackwards.protocol.v1_17_1to1_17.Protocol1_17_1To1_17;
import com.viaversion.viabackwards.protocol.v1_19to1_18_2.Protocol1_19To1_18_2;
import com.viaversion.viabackwards.protocol.v1_17to1_16_4.Protocol1_17To1_16_4;
import com.viaversion.viabackwards.protocol.v1_18_2to1_18.Protocol1_18_2To1_18;
import com.viaversion.viabackwards.protocol.v1_18to1_17_1.Protocol1_18To1_17_1;
import com.viaversion.viabackwards.protocol.v1_19_1to1_19.Protocol1_19_1To1_19;
import com.viaversion.viabackwards.protocol.v1_19_3to1_19_1.Protocol1_19_3To1_19_1;
import com.viaversion.viabackwards.protocol.v1_19_4to1_19_3.Protocol1_19_4To1_19_3;
import com.viaversion.viabackwards.protocol.v1_21_4to1_21_2.Protocol1_21_4To1_21_2;
import com.viaversion.viabackwards.protocol.v1_20to1_19_4.Protocol1_20To1_19_4;
import com.viaversion.viabackwards.protocol.v1_19_1to1_19.Protocol1_19_1To1_19;
import com.viaversion.viabackwards.protocol.v1_19to1_18_2.Protocol1_19To1_18_2;
import com.viaversion.viabackwards.protocol.v1_20_2to1_20.Protocol1_20_2To1_20;
import com.viaversion.viabackwards.protocol.v1_20_3to1_20_2.Protocol1_20_3To1_20_2;
import com.viaversion.viabackwards.protocol.v1_20_5to1_20_3.Protocol1_20_5To1_20_3;
import com.viaversion.viabackwards.protocol.v1_20_2to1_20.Protocol1_20_2To1_20;
import com.viaversion.viabackwards.protocol.v1_20to1_19_4.Protocol1_20To1_19_4;
import com.viaversion.viabackwards.protocol.v1_21_2to1_21.Protocol1_21_2To1_21;
import com.viaversion.viabackwards.protocol.v1_21_2to1_21.task.PlayerPacketsTickTask;
import com.viaversion.viabackwards.protocol.v1_21_4to1_21_2.Protocol1_21_4To1_21_2;
import com.viaversion.viabackwards.protocol.v1_21_5to1_21_4.Protocol1_21_5To1_21_4;
import com.viaversion.viabackwards.protocol.v1_21to1_20_5.Protocol1_21To1_20_5;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.Protocol1_21_6To1_21_5;
import com.viaversion.viabackwards.protocol.v1_9_3to1_9_1.Protocol1_9_3To1_9_1;
import com.viaversion.viabackwards.protocol.v1_10to1_9_3.Protocol1_10To1_9_3;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.task.ChestDialogViewTask;
import com.viaversion.viabackwards.protocol.v1_21_7to1_21_6.Protocol1_21_7To1_21_6;
import com.viaversion.viabackwards.protocol.v1_21to1_20_5.Protocol1_21To1_20_5;
import com.viaversion.viabackwards.protocol.v1_9_1to1_9.Protocol1_9_1To1_9;
import com.viaversion.viabackwards.protocol.v1_9_3to1_9_1.Protocol1_9_3To1_9_1;
import com.viaversion.viabackwards.utils.VersionInfo;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.protocol.ProtocolManager;
@@ -151,6 +153,7 @@ public interface ViaBackwardsPlatform {
protocolManager.registerProtocol(new Protocol1_21_5To1_21_4(), ProtocolVersion.v1_21_4, ProtocolVersion.v1_21_5);
protocolManager.registerProtocol(new Protocol1_21_6To1_21_5(), ProtocolVersion.v1_21_5, ProtocolVersion.v1_21_6);
protocolManager.registerProtocol(new Protocol1_21_7To1_21_6(), ProtocolVersion.v1_21_6, ProtocolVersion.v1_21_7);
}
default void enable() {
@@ -158,6 +161,10 @@ public interface ViaBackwardsPlatform {
if (protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_21_2)) {
Via.getPlatform().runRepeatingSync(new PlayerPacketsTickTask(), 1L);
}
if (protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_21_6)) {
Via.getPlatform().runRepeatingSync(new ChestDialogViewTask(), 20L);
}
}
/**
@@ -18,6 +18,10 @@
package com.viaversion.viabackwards.api.data;
import com.google.common.base.Preconditions;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.NumberTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viabackwards.ViaBackwards;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viaversion.api.Via;
@@ -30,10 +34,6 @@ import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectArrayMap;
import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectMap;
import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectOpenHashMap;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.NumberTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.util.Key;
import java.util.HashMap;
import java.util.Map;
@@ -17,10 +17,10 @@
*/
package com.viaversion.viabackwards.api.data;
import com.viaversion.viabackwards.ViaBackwards;
import com.viaversion.viaversion.api.data.MappingDataLoader;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viabackwards.ViaBackwards;
import com.viaversion.viaversion.api.data.MappingDataLoader;
import java.io.File;
import java.io.IOException;
import java.util.Map;
@@ -18,9 +18,9 @@
package com.viaversion.viabackwards.api.entities.storage;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viaversion.util.ComponentUtil;
import java.util.Locale;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -26,11 +26,14 @@ import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.data.MappedItem;
import com.viaversion.viabackwards.item.DataItemWithExtras;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.libs.gson.JsonElement;
import java.util.List;
import org.checkerframework.checker.nullness.qual.Nullable;
public class BackwardsItemRewriter<C extends ClientboundPacketType, S extends ServerboundPacketType,
@@ -52,29 +55,45 @@ public class BackwardsItemRewriter<C extends ClientboundPacketType, S extends Se
CompoundTag display = item.tag() != null ? item.tag().getCompoundTag("display") : null;
if (protocol.getComponentRewriter() != null && display != null) {
// Handle name and lore components
StringTag name = display.getStringTag("Name");
if (name != null) {
String newValue = protocol.getComponentRewriter().processText(connection, name.getValue()).toString();
if (!newValue.equals(name.getValue())) {
saveStringTag(display, name, "Name");
}
name.setValue(newValue);
final DataItemWithExtras fullItem;
if (item instanceof DataItemWithExtras) {
fullItem = (DataItemWithExtras) item;
} else {
item = fullItem = new DataItemWithExtras(item);
}
ListTag<StringTag> lore = display.getListTag("Lore", StringTag.class);
// Handle name and lore components
final JsonElement name = fullItem.name();
if (name != null) {
final JsonElement updatedName = name.deepCopy();
protocol.getComponentRewriter().processText(connection, updatedName);
if (!updatedName.equals(name)) {
final StringTag rawName = fullItem.rawName();
saveStringTag(display, rawName, "Name");
rawName.setValue(updatedName.toString());
}
}
final List<JsonElement> lore = fullItem.lore();
if (lore != null) {
boolean changed = false;
for (StringTag loreEntry : lore) {
String newValue = protocol.getComponentRewriter().processText(connection, loreEntry.getValue()).toString();
if (!changed && !newValue.equals(loreEntry.getValue())) {
// Backup original lore before doing any modifications
changed = true;
saveListTag(display, lore, "Lore");
final ListTag<StringTag> rawLore = fullItem.rawLore();
for (int i = 0; i < lore.size(); i++) {
final JsonElement loreEntry = lore.get(i);
final JsonElement updatedLoreEntry = loreEntry.deepCopy();
protocol.getComponentRewriter().processText(connection, updatedLoreEntry);
if (updatedLoreEntry.equals(loreEntry)) {
continue;
}
loreEntry.setValue(newValue);
if (!changed) {
// Backup original lore before doing any modifications
changed = true;
saveListTag(display, rawLore, "Lore");
}
final StringTag rawLoreEntry = rawLore.get(i);
rawLoreEntry.setValue(updatedLoreEntry.toString());
}
}
}
@@ -17,19 +17,17 @@
*/
package com.viaversion.viabackwards.api.rewriters;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.rewriter.ItemRewriter;
import java.util.ArrayList;
import java.util.List;
import org.checkerframework.checker.nullness.qual.Nullable;
public abstract class BackwardsItemRewriterBase<C extends ClientboundPacketType, S extends ServerboundPacketType,
@@ -17,12 +17,12 @@
*/
package com.viaversion.viabackwards.api.rewriters;
import com.viaversion.viabackwards.utils.ChatUtil;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.NumberTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viabackwards.utils.ChatUtil;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.util.Key;
import java.util.ArrayList;
import java.util.HashMap;
@@ -175,7 +175,7 @@ public abstract class EntityRewriterBase<C extends ClientboundPacketType, T exte
filter().handler((event, data) -> {
EntityDataType type = data.dataType();
if (type == itemType) {
protocol.getItemRewriter().handleItemToClient(event.user(), data.value());
data.setValue(protocol.getItemRewriter().handleItemToClient(event.user(), data.value()));
} else if (type == blockStateType) {
int value = data.value();
data.setValue(protocol.getMappingData().getNewBlockStateId(value));
@@ -17,7 +17,6 @@
*/
package com.viaversion.viabackwards.api.rewriters;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.nbt.tag.ByteTag;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.IntTag;
@@ -25,6 +24,7 @@ import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.NumberTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.api.minecraft.item.Item;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
@@ -64,12 +64,11 @@ public class SoundRewriter<C extends ClientboundPacketType> extends com.viaversi
public PacketHandler getStopSoundHandler() {
return wrapper -> {
final byte flags = wrapper.passthrough(Types.BYTE);
if ((flags & 0x02) == 0) return; // No sound specified
if ((flags & 0x01) != 0) {
wrapper.passthrough(Types.VAR_INT); // Source
}
if ((flags & 0x02) == 0) return; // No sound specified
final String soundId = wrapper.read(Types.STRING);
final String mappedId = protocol.getMappingData().getMappedNamedSound(soundId);
if (mappedId == null) {
@@ -0,0 +1,103 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viabackwards.item;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viaversion.api.minecraft.item.DataItem;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.libs.gson.JsonParser;
import com.viaversion.viaversion.libs.gson.JsonPrimitive;
import com.viaversion.viaversion.libs.gson.JsonSyntaxException;
import java.util.ArrayList;
import java.util.List;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Prevent expensive parsing/toString by checking against cached JsonElement instances, used from 1.14 to 1.20.5.
* <p>
* When using this, be careful not to break caching by modifying the display tag directly.
*/
public final class DataItemWithExtras extends DataItem {
private JsonElement name;
private List<JsonElement> lore;
public DataItemWithExtras(final Item from) {
setIdentifier(from.identifier());
setAmount(from.amount());
setData(from.data());
setTag(from.tag());
if (tag() == null) {
return;
}
final CompoundTag display = tag().getCompoundTag("display");
if (display == null) {
return;
}
final StringTag name = display.getStringTag("Name");
if (name != null) {
this.name = parse(name.getValue());
}
final ListTag<StringTag> lore = display.getListTag("Lore", StringTag.class);
if (lore != null) {
this.lore = new ArrayList<>(lore.size());
for (int i = 0; i < lore.size(); i++) {
this.lore.add(parse(lore.get(i).getValue()));
}
}
}
public @Nullable JsonElement name() {
return name;
}
public @Nullable StringTag rawName() {
if (tag() == null) {
return null;
}
final CompoundTag display = tag().getCompoundTag("display");
return display != null ? display.getStringTag("Name") : null;
}
public @Nullable List<JsonElement> lore() {
return lore;
}
public @Nullable ListTag<StringTag> rawLore() {
if (tag() == null) {
return null;
}
final CompoundTag display = tag().getCompoundTag("display");
return display != null ? display.getListTag("Lore", StringTag.class) : null;
}
private JsonElement parse(final String value) {
try {
return JsonParser.parseString(value);
} catch (final JsonSyntaxException e) {
return new JsonPrimitive(value);
}
}
}
@@ -157,6 +157,9 @@ public class EntityPacketRewriter1_10 extends LegacyEntityRewriter<ClientboundPa
}
});
// Added index from incorrect entity data hierarchy, where potions add to item entities
filter().type(EntityTypes1_10.EntityType.POTION).addIndex(6);
// Handle the missing NoGravity tag for every entity data
filter().removeIndex(5);
}
@@ -23,8 +23,6 @@ import com.viaversion.viabackwards.api.rewriters.LegacyEnchantmentRewriter;
import com.viaversion.viabackwards.protocol.v1_11_1to1_11.Protocol1_11_1To1_11;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ClientboundPackets1_9_3;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ServerboundPackets1_9_3;
@@ -18,6 +18,8 @@
package com.viaversion.viabackwards.protocol.v1_11to1_10.rewriter;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viabackwards.api.data.MappedLegacyBlockItem;
import com.viaversion.viabackwards.api.rewriters.LegacyBlockItemRewriter;
import com.viaversion.viabackwards.api.rewriters.LegacyEnchantmentRewriter;
@@ -35,8 +37,6 @@ import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_9_3;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viaversion.protocols.v1_10to1_11.data.EntityMappings1_11;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ClientboundPackets1_9_3;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ServerboundPackets1_9_3;
@@ -20,11 +20,11 @@ package com.viaversion.viabackwards.protocol.v1_12to1_11_1;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.data.BackwardsMappingData;
import com.viaversion.viabackwards.protocol.v1_12to1_11_1.storage.ShoulderTracker;
import com.viaversion.viabackwards.protocol.v1_12to1_11_1.rewriter.BlockItemPacketRewriter1_12;
import com.viaversion.viabackwards.protocol.v1_12to1_11_1.rewriter.ComponentRewriter1_12;
import com.viaversion.viabackwards.protocol.v1_12to1_11_1.rewriter.EntityPacketRewriter1_12;
import com.viaversion.viabackwards.protocol.v1_12to1_11_1.rewriter.SoundPacketRewriter1_12;
import com.viaversion.viabackwards.protocol.v1_12to1_11_1.storage.ShoulderTracker;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_12;
@@ -18,7 +18,11 @@
package com.viaversion.viabackwards.protocol.v1_12to1_11_1.rewriter;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.IntArrayTag;
import com.viaversion.nbt.tag.LongArrayTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viabackwards.api.rewriters.LegacyBlockItemRewriter;
import com.viaversion.viabackwards.protocol.v1_12to1_11_1.Protocol1_12To1_11_1;
import com.viaversion.viabackwards.protocol.v1_12to1_11_1.data.MapColorMappings1_11_1;
@@ -30,18 +34,14 @@ import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_9_3;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.IntArrayTag;
import com.viaversion.nbt.tag.LongArrayTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.protocols.v1_11_1to1_12.packet.ClientboundPackets1_12;
import com.viaversion.viaversion.protocols.v1_11_1to1_12.packet.ServerboundPackets1_12;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ServerboundPackets1_9_3;
import java.util.Iterator;
import java.util.Map;
import com.viaversion.viaversion.util.ComponentUtil;
import com.viaversion.viaversion.util.Key;
import com.viaversion.viaversion.util.SerializerVersion;
import java.util.Iterator;
import java.util.Map;
import org.checkerframework.checker.nullness.qual.Nullable;
public class BlockItemPacketRewriter1_12 extends LegacyBlockItemRewriter<ClientboundPackets1_12, ServerboundPackets1_9_3, Protocol1_12To1_11_1> {
@@ -21,7 +21,6 @@ package com.viaversion.viabackwards.protocol.v1_12to1_11_1.rewriter;
import com.viaversion.viabackwards.api.rewriters.LegacySoundRewriter;
import com.viaversion.viabackwards.protocol.v1_12to1_11_1.Protocol1_12To1_11_1;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_11_1to1_12.packet.ClientboundPackets1_12;
@@ -40,10 +40,10 @@ import com.viaversion.viaversion.libs.gson.JsonObject;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.packet.ClientboundPackets1_13;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.packet.ServerboundPackets1_13;
import com.viaversion.viaversion.protocols.v1_13to1_13_1.Protocol1_13To1_13_1;
import com.viaversion.viaversion.rewriter.text.ComponentRewriterBase;
import com.viaversion.viaversion.rewriter.ParticleRewriter;
import com.viaversion.viaversion.rewriter.StatisticsRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
import com.viaversion.viaversion.rewriter.text.ComponentRewriterBase;
import com.viaversion.viaversion.util.ComponentUtil;
public class Protocol1_13_1To1_13 extends BackwardsProtocol<ClientboundPackets1_13, ClientboundPackets1_13, ServerboundPackets1_13, ServerboundPackets1_13> {
@@ -131,7 +131,7 @@ public class EntityPacketRewriter1_13_1 extends LegacyEntityRewriter<Clientbound
// Rewrite items & blocks
filter().handler((event, data) -> {
if (data.dataType() == Types1_13.ENTITY_DATA_TYPES.itemType) {
protocol.getItemRewriter().handleItemToClient(event.user(), (Item) data.getValue());
data.setValue(protocol.getItemRewriter().handleItemToClient(event.user(), (Item) data.getValue()));
} else if (data.dataType() == Types1_13.ENTITY_DATA_TYPES.optionalBlockStateType) {
// Convert to new block id
int value = (int) data.getValue();
@@ -19,8 +19,8 @@ package com.viaversion.viabackwards.protocol.v1_13_1to1_13.rewriter;
import com.viaversion.viabackwards.protocol.v1_13_1to1_13.Protocol1_13_1To1_13;
import com.viaversion.viaversion.api.minecraft.BlockFace;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.BlockPosition;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
@@ -23,7 +23,6 @@ import com.viaversion.viabackwards.protocol.v1_13_2to1_13_1.rewriter.ItemPacketR
import com.viaversion.viabackwards.protocol.v1_13_2to1_13_1.rewriter.WorldPacketRewriter1_13_2;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.packet.ClientboundPackets1_13;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.packet.ServerboundPackets1_13;
@@ -19,7 +19,6 @@ package com.viaversion.viabackwards.protocol.v1_13_2to1_13_1.rewriter;
import com.viaversion.viabackwards.protocol.v1_13_2to1_13_1.Protocol1_13_2To1_13_1;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.packet.ClientboundPackets1_13;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.packet.ServerboundPackets1_13;
@@ -19,7 +19,6 @@ package com.viaversion.viabackwards.protocol.v1_13_2to1_13_1.rewriter;
import com.viaversion.viabackwards.protocol.v1_13_2to1_13_1.Protocol1_13_2To1_13_1;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.packet.ClientboundPackets1_13;
@@ -40,11 +40,11 @@ import com.viaversion.viaversion.data.entity.EntityTrackerBase;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.libs.gson.JsonObject;
import com.viaversion.viaversion.libs.gson.JsonParser;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.Protocol1_12_2To1_13;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.packet.ClientboundPackets1_13;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.packet.ServerboundPackets1_13;
import com.viaversion.viaversion.protocols.v1_12to1_12_1.packet.ClientboundPackets1_12_1;
import com.viaversion.viaversion.protocols.v1_12to1_12_1.packet.ServerboundPackets1_12_1;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.Protocol1_12_2To1_13;
import com.viaversion.viaversion.rewriter.text.ComponentRewriterBase;
import com.viaversion.viaversion.util.ComponentUtil;
import com.viaversion.viaversion.util.ProtocolLogger;
@@ -18,11 +18,11 @@
package com.viaversion.viabackwards.protocol.v1_13to1_12_2.block_entity_handlers;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.Protocol1_13To1_12_2;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.provider.BackwardsBlockEntityProvider.BackwardsBlockEntityHandler;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.NumberTag;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.Protocol1_13To1_12_2;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.provider.BackwardsBlockEntityProvider.BackwardsBlockEntityHandler;
public class BannerHandler implements BackwardsBlockEntityHandler {
private static final int WALL_BANNER_START = 7110; // 4 each
@@ -18,8 +18,8 @@
package com.viaversion.viabackwards.protocol.v1_13to1_12_2.block_entity_handlers;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.provider.BackwardsBlockEntityProvider;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.provider.BackwardsBlockEntityProvider;
public class BedHandler implements BackwardsBlockEntityProvider.BackwardsBlockEntityHandler {
@@ -18,10 +18,10 @@
package com.viaversion.viabackwards.protocol.v1_13to1_12_2.block_entity_handlers;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.provider.BackwardsBlockEntityProvider;
import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectMap;
import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectOpenHashMap;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viaversion.util.Pair;
public class FlowerPotHandler implements BackwardsBlockEntityProvider.BackwardsBlockEntityHandler {
@@ -17,16 +17,16 @@
*/
package com.viaversion.viabackwards.protocol.v1_13to1_12_2.block_entity_handlers;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.Protocol1_13To1_12_2;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.provider.BackwardsBlockEntityProvider;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.data.MappingDataLoader;
import com.viaversion.viaversion.libs.fastutil.objects.Object2IntMap;
import com.viaversion.viaversion.libs.fastutil.objects.Object2IntOpenHashMap;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.blockconnections.ConnectionData;
import java.util.Map;
import java.util.StringJoiner;
@@ -18,8 +18,8 @@
package com.viaversion.viabackwards.protocol.v1_13to1_12_2.block_entity_handlers;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.provider.BackwardsBlockEntityProvider.BackwardsBlockEntityHandler;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.provider.BackwardsBlockEntityProvider.BackwardsBlockEntityHandler;
public class SkullHandler implements BackwardsBlockEntityHandler {
private static final int SKULL_START = 5447;
@@ -18,10 +18,10 @@
package com.viaversion.viabackwards.protocol.v1_13to1_12_2.block_entity_handlers;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.data.EntityNameMappings1_12_2;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.provider.BackwardsBlockEntityProvider;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.data.EntityNameMappings1_12_2;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.provider.BackwardsBlockEntityProvider;
public class SpawnerHandler implements BackwardsBlockEntityProvider.BackwardsBlockEntityHandler {
@@ -18,10 +18,10 @@
package com.viaversion.viabackwards.protocol.v1_13to1_12_2.data;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viabackwards.api.data.BackwardsMappingData;
import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectMap;
import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectOpenHashMap;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.Protocol1_12_2To1_13;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.data.StatisticMappings1_13;
import java.util.HashMap;
@@ -18,6 +18,8 @@
package com.viaversion.viabackwards.protocol.v1_13to1_12_2.provider;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.block_entity_handlers.BannerHandler;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.block_entity_handlers.BedHandler;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.block_entity_handlers.FlowerPotHandler;
@@ -28,8 +30,6 @@ import com.viaversion.viabackwards.protocol.v1_13to1_12_2.storage.BackwardsBlock
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.BlockPosition;
import com.viaversion.viaversion.api.platform.providers.Provider;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viaversion.util.Key;
import java.util.HashMap;
import java.util.Map;
@@ -19,6 +19,13 @@
package com.viaversion.viabackwards.protocol.v1_13to1_12_2.rewriter;
import com.google.common.primitives.Ints;
import com.viaversion.nbt.tag.ByteTag;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.IntTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.NumberTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viabackwards.ViaBackwards;
import com.viaversion.viabackwards.api.rewriters.BackwardsItemRewriter;
import com.viaversion.viabackwards.api.rewriters.EnchantmentRewriter;
@@ -30,8 +37,8 @@ import com.viaversion.viabackwards.protocol.v1_13to1_12_2.storage.NoteBlockStora
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.BlockChangeRecord;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.BlockPosition;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
import com.viaversion.viaversion.api.minecraft.chunks.ChunkSection;
import com.viaversion.viaversion.api.minecraft.chunks.DataPalette;
@@ -42,19 +49,12 @@ import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_13;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_9_3;
import com.viaversion.nbt.tag.ByteTag;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.IntTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.NumberTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.Protocol1_12_2To1_13;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.data.BlockIdData;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.data.SpawnEggMappings1_13;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.packet.ClientboundPackets1_13;
import com.viaversion.viaversion.protocols.v1_12to1_12_1.packet.ClientboundPackets1_12_1;
import com.viaversion.viaversion.protocols.v1_12to1_12_1.packet.ServerboundPackets1_12_1;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.Protocol1_12_2To1_13;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.data.BlockIdData;
import com.viaversion.viaversion.util.ComponentUtil;
import com.viaversion.viaversion.util.IdAndData;
import com.viaversion.viaversion.util.Key;
@@ -34,11 +34,11 @@ import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.protocols.base.ClientboundLoginPackets;
import com.viaversion.viaversion.protocols.base.ServerboundLoginPackets;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.packet.ClientboundPackets1_13;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.packet.ServerboundPackets1_13;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.rewriter.ItemPacketRewriter1_13;
import com.viaversion.viaversion.protocols.v1_12to1_12_1.packet.ClientboundPackets1_12_1;
import com.viaversion.viaversion.protocols.v1_12to1_12_1.packet.ServerboundPackets1_12_1;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.packet.ClientboundPackets1_13;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.packet.ServerboundPackets1_13;
import com.viaversion.viaversion.rewriter.CommandRewriter;
import com.viaversion.viaversion.util.Key;
import java.nio.charset.StandardCharsets;
@@ -18,7 +18,6 @@
package com.viaversion.viabackwards.protocol.v1_14_3to1_14_2;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_13_2to1_14.packet.ClientboundPackets1_14;
import com.viaversion.viaversion.protocols.v1_13_2to1_14.packet.ServerboundPackets1_14;
@@ -19,7 +19,6 @@ package com.viaversion.viabackwards.protocol.v1_14_4to1_14_3;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_13_2to1_14.packet.ClientboundPackets1_14;
import com.viaversion.viaversion.protocols.v1_13_2to1_14.packet.ServerboundPackets1_14;
@@ -24,6 +24,7 @@ import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viabackwards.api.data.TranslatableMappings;
import com.viaversion.viabackwards.api.rewriters.BackwardsItemRewriter;
import com.viaversion.viabackwards.api.rewriters.EnchantmentRewriter;
import com.viaversion.viabackwards.item.DataItemWithExtras;
import com.viaversion.viabackwards.protocol.v1_14to1_13_2.Protocol1_14To1_13_2;
import com.viaversion.viabackwards.protocol.v1_14to1_13_2.storage.ChunkLightStorage;
import com.viaversion.viaversion.api.Via;
@@ -39,6 +40,7 @@ import com.viaversion.viaversion.api.minecraft.chunks.PaletteType;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_14;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import com.viaversion.viaversion.api.minecraft.item.DataItem;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
@@ -61,7 +63,6 @@ import com.viaversion.viaversion.util.ComponentUtil;
import com.viaversion.viaversion.util.Key;
import com.viaversion.viaversion.util.SerializerVersion;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
@@ -462,31 +463,34 @@ public class BlockItemPacketRewriter1_14 extends BackwardsItemRewriter<Clientbou
super.handleItemToClient(connection, item);
// Lore now uses JSON
CompoundTag tag = item.tag();
CompoundTag display;
if (tag != null && (display = tag.getCompoundTag("display")) != null) {
ListTag<StringTag> lore = display.getListTag("Lore", StringTag.class);
if (lore != null) {
saveListTag(display, lore, "Lore");
final CompoundTag display = item.tag() != null ? item.tag().getCompoundTag("display") : null;
if (display != null && item instanceof DataItemWithExtras fullItem && fullItem.lore() != null) {
final List<JsonElement> lore = fullItem.lore();
final ListTag<StringTag> loreTag = fullItem.rawLore();
saveListTag(display, loreTag, "Lore");
try {
final Iterator<StringTag> each = lore.iterator();
while (each.hasNext()) {
final StringTag loreEntry = each.next();
final var component = SerializerVersion.V1_12.toComponent(loreEntry.getValue());
if (component == null) {
each.remove();
continue;
}
TextUtils.setTranslator(component, s -> Protocol1_12_2To1_13.MAPPINGS.getMojangTranslation().
getOrDefault(s, TranslatableMappings.getTranslatableMappings("1.14").get(s)));
loreEntry.setValue(component.asLegacyFormatString());
try {
for (int i = 0; i < lore.size(); i++) {
final JsonElement loreEntry = lore.get(i);
final var component = SerializerVersion.V1_12.toComponent(loreEntry);
if (component == null) {
lore.remove(i);
loreTag.remove(i);
i--;
continue;
}
} catch (final JsonParseException e) {
display.remove("Lore");
TextUtils.setTranslator(component, s -> Protocol1_12_2To1_13.MAPPINGS.getMojangTranslation()
.getOrDefault(s, TranslatableMappings.getTranslatableMappings("1.14").get(s)));
loreTag.get(i).setValue(component.asLegacyFormatString());
}
} catch (final JsonParseException e) {
display.remove("Lore");
}
}
if (item instanceof DataItemWithExtras) {
item = new DataItem(item.identifier(), (byte) item.amount(), item.data(), item.tag()); // back to a normal DataItem
}
enchantmentRewriter.handleToClient(item);
return item;
@@ -17,7 +17,6 @@
*/
package com.viaversion.viabackwards.protocol.v1_14to1_13_2.rewriter;
import com.viaversion.viabackwards.ViaBackwards;
import com.viaversion.viabackwards.api.rewriters.SoundRewriter;
import com.viaversion.viabackwards.protocol.v1_14to1_13_2.Protocol1_14To1_13_2;
import com.viaversion.viabackwards.protocol.v1_14to1_13_2.storage.EntityPositionStorage1_14;
@@ -36,10 +36,10 @@ import com.viaversion.viaversion.protocols.v1_13_2to1_14.packet.ServerboundPacke
import com.viaversion.viaversion.protocols.v1_14_3to1_14_4.packet.ClientboundPackets1_14_4;
import com.viaversion.viaversion.protocols.v1_14_4to1_15.Protocol1_14_4To1_15;
import com.viaversion.viaversion.protocols.v1_14_4to1_15.packet.ClientboundPackets1_15;
import com.viaversion.viaversion.rewriter.text.ComponentRewriterBase;
import com.viaversion.viaversion.rewriter.ParticleRewriter;
import com.viaversion.viaversion.rewriter.StatisticsRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
import com.viaversion.viaversion.rewriter.text.ComponentRewriterBase;
public class Protocol1_15To1_14_4 extends BackwardsProtocol<ClientboundPackets1_15, ClientboundPackets1_14_4, ServerboundPackets1_14, ServerboundPackets1_14> {
@@ -37,10 +37,10 @@ import com.viaversion.viaversion.protocols.v1_15_2to1_16.packet.ServerboundPacke
import com.viaversion.viaversion.protocols.v1_16_1to1_16_2.Protocol1_16_1To1_16_2;
import com.viaversion.viaversion.protocols.v1_16_1to1_16_2.packet.ClientboundPackets1_16_2;
import com.viaversion.viaversion.protocols.v1_16_1to1_16_2.packet.ServerboundPackets1_16_2;
import com.viaversion.viaversion.rewriter.text.ComponentRewriterBase;
import com.viaversion.viaversion.rewriter.ParticleRewriter;
import com.viaversion.viaversion.rewriter.StatisticsRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
import com.viaversion.viaversion.rewriter.text.ComponentRewriterBase;
import com.viaversion.viaversion.util.ProtocolLogger;
public class Protocol1_16_2To1_16_1 extends BackwardsProtocol<ClientboundPackets1_16_2, ClientboundPackets1_16, ServerboundPackets1_16_2, ServerboundPackets1_16> {
@@ -17,7 +17,6 @@
*/
package com.viaversion.viabackwards.protocol.v1_16_2to1_16_1.data;
import com.viaversion.viabackwards.ViaBackwards;
import com.viaversion.viabackwards.api.data.BackwardsMappingDataLoader;
import com.viaversion.viabackwards.protocol.v1_16_2to1_16_1.Protocol1_16_2To1_16_1;
import com.viaversion.viaversion.api.Via;
@@ -21,7 +21,6 @@ import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.protocol.v1_16_4to1_16_3.storage.PlayerHandStorage;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_16_1to1_16_2.packet.ClientboundPackets1_16_2;
import com.viaversion.viaversion.protocols.v1_16_1to1_16_2.packet.ServerboundPackets1_16_2;
@@ -17,18 +17,16 @@
*/
package com.viaversion.viabackwards.protocol.v1_17_1to1_17;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.protocol.v1_17to1_16_4.storage.PlayerLastCursorItem;
import com.viaversion.viabackwards.protocol.v1_17_1to1_17.storage.InventoryStateIds;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.protocol.v1_17_1to1_17.storage.InventoryStateIds;
import com.viaversion.viabackwards.protocol.v1_17to1_16_4.storage.PlayerLastCursorItem;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_16_4to1_17.packet.ClientboundPackets1_17;
import com.viaversion.viaversion.protocols.v1_16_4to1_17.packet.ServerboundPackets1_17;
import com.viaversion.viaversion.protocols.v1_17to1_17_1.packet.ClientboundPackets1_17_1;
@@ -40,11 +40,11 @@ import com.viaversion.viaversion.protocols.v1_16_1to1_16_2.packet.ServerboundPac
import com.viaversion.viaversion.protocols.v1_16_4to1_17.Protocol1_16_4To1_17;
import com.viaversion.viaversion.protocols.v1_16_4to1_17.packet.ClientboundPackets1_17;
import com.viaversion.viaversion.protocols.v1_16_4to1_17.packet.ServerboundPackets1_17;
import com.viaversion.viaversion.rewriter.text.ComponentRewriterBase;
import com.viaversion.viaversion.rewriter.IdRewriteFunction;
import com.viaversion.viaversion.rewriter.ParticleRewriter;
import com.viaversion.viaversion.rewriter.StatisticsRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
import com.viaversion.viaversion.rewriter.text.ComponentRewriterBase;
import com.viaversion.viaversion.util.Key;
import java.util.ArrayList;
import java.util.HashMap;
@@ -17,7 +17,9 @@
*/
package com.viaversion.viabackwards.protocol.v1_18_2to1_18;
import com.viaversion.viabackwards.ViaBackwards;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.protocol.v1_18_2to1_18.rewriter.CommandRewriter1_18_2;
import com.viaversion.viaversion.api.Via;
@@ -25,9 +27,6 @@ import com.viaversion.viaversion.api.protocol.remapper.PacketHandler;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_16_4to1_17.packet.ServerboundPackets1_17;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viaversion.protocols.v1_17_1to1_18.packet.ClientboundPackets1_18;
import com.viaversion.viaversion.util.TagUtil;
@@ -33,9 +33,9 @@ import com.viaversion.viaversion.data.entity.EntityTrackerBase;
import com.viaversion.viaversion.protocols.v1_16_4to1_17.packet.ServerboundPackets1_17;
import com.viaversion.viaversion.protocols.v1_17_1to1_18.packet.ClientboundPackets1_18;
import com.viaversion.viaversion.protocols.v1_17to1_17_1.packet.ClientboundPackets1_17_1;
import com.viaversion.viaversion.rewriter.text.ComponentRewriterBase;
import com.viaversion.viaversion.rewriter.ParticleRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
import com.viaversion.viaversion.rewriter.text.ComponentRewriterBase;
public final class Protocol1_18To1_17_1 extends BackwardsProtocol<ClientboundPackets1_18, ClientboundPackets1_17_1, ServerboundPackets1_17, ServerboundPackets1_17> {
@@ -17,11 +17,11 @@
*/
package com.viaversion.viabackwards.protocol.v1_18to1_17_1.data;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viabackwards.api.data.BackwardsMappingData;
import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectMap;
import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectOpenHashMap;
import com.viaversion.viaversion.libs.fastutil.objects.Object2IntMap;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viaversion.protocols.v1_17_1to1_18.Protocol1_17_1To1_18;
import com.viaversion.viaversion.protocols.v1_17_1to1_18.data.BlockEntities1_18;
@@ -17,6 +17,7 @@
*/
package com.viaversion.viabackwards.protocol.v1_18to1_17_1.rewriter;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viabackwards.api.rewriters.BackwardsItemRewriter;
import com.viaversion.viabackwards.protocol.v1_18to1_17_1.Protocol1_18To1_17_1;
import com.viaversion.viabackwards.protocol.v1_18to1_17_1.data.BlockEntityMappings1_17_1;
@@ -35,7 +36,6 @@ import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_17;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_18;
import com.viaversion.viaversion.protocols.v1_16_4to1_17.packet.ServerboundPackets1_17;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viaversion.protocols.v1_17_1to1_18.packet.ClientboundPackets1_18;
import com.viaversion.viaversion.protocols.v1_17to1_17_1.packet.ClientboundPackets1_17_1;
import com.viaversion.viaversion.rewriter.RecipeRewriter;
@@ -17,6 +17,9 @@
*/
package com.viaversion.viabackwards.protocol.v1_19_1to1_19;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.NumberTag;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.rewriters.text.JsonNBTComponentRewriter;
import com.viaversion.viabackwards.protocol.v1_19_1to1_19.rewriter.EntityPacketRewriter1_19_1;
@@ -40,17 +43,14 @@ import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.data.entity.EntityTrackerBase;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.NumberTag;
import com.viaversion.viaversion.protocols.base.ClientboundLoginPackets;
import com.viaversion.viaversion.protocols.base.ServerboundLoginPackets;
import com.viaversion.viaversion.protocols.v1_18_2to1_19.Protocol1_18_2To1_19;
import com.viaversion.viaversion.protocols.v1_18_2to1_19.packet.ClientboundPackets1_19;
import com.viaversion.viaversion.protocols.v1_18_2to1_19.packet.ServerboundPackets1_19;
import com.viaversion.viaversion.protocols.v1_19to1_19_1.Protocol1_19To1_19_1;
import com.viaversion.viaversion.protocols.v1_19to1_19_1.packet.ClientboundPackets1_19_1;
import com.viaversion.viaversion.protocols.v1_19to1_19_1.packet.ServerboundPackets1_19_1;
import com.viaversion.viaversion.protocols.v1_18_2to1_19.Protocol1_18_2To1_19;
import com.viaversion.viaversion.rewriter.text.ComponentRewriterBase;
import com.viaversion.viaversion.util.CipherUtil;
import com.viaversion.viaversion.util.ComponentUtil;
@@ -17,10 +17,10 @@
*/
package com.viaversion.viabackwards.protocol.v1_19_1to1_19.storage;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viaversion.api.connection.StorableObject;
import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectMap;
import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectOpenHashMap;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viaversion.protocols.v1_18_2to1_19.Protocol1_18_2To1_19;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -39,9 +39,4 @@ public abstract class ChatRegistryStorage implements StorableObject {
public void clear() {
chatTypes.clear();
}
@Override
public boolean clearOnServerSwitch() {
return false;
}
}
@@ -54,10 +54,10 @@ import com.viaversion.viaversion.protocols.v1_19_1to1_19_3.packet.ServerboundPac
import com.viaversion.viaversion.protocols.v1_19to1_19_1.packet.ClientboundPackets1_19_1;
import com.viaversion.viaversion.protocols.v1_19to1_19_1.packet.ServerboundPackets1_19_1;
import com.viaversion.viaversion.rewriter.CommandRewriter;
import com.viaversion.viaversion.rewriter.text.ComponentRewriterBase;
import com.viaversion.viaversion.rewriter.ParticleRewriter;
import com.viaversion.viaversion.rewriter.StatisticsRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
import com.viaversion.viaversion.rewriter.text.ComponentRewriterBase;
import com.viaversion.viaversion.util.CipherUtil;
import com.viaversion.viaversion.util.ComponentUtil;
import com.viaversion.viaversion.util.Pair;
@@ -17,13 +17,13 @@
*/
package com.viaversion.viabackwards.protocol.v1_19_3to1_19_1.data;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viabackwards.api.data.BackwardsMappingData;
import com.viaversion.viabackwards.api.data.BackwardsMappingDataLoader;
import com.viaversion.viaversion.libs.fastutil.objects.Object2IntMap;
import com.viaversion.viaversion.libs.fastutil.objects.Object2IntOpenHashMap;
import com.viaversion.viaversion.libs.gson.JsonArray;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viaversion.protocols.v1_19_1to1_19_3.Protocol1_19_1To1_19_3;
import com.viaversion.viaversion.util.Key;
@@ -17,6 +17,9 @@
*/
package com.viaversion.viabackwards.protocol.v1_19_3to1_19_1.rewriter;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.NumberTag;
import com.viaversion.viabackwards.api.rewriters.EntityRewriter;
import com.viaversion.viabackwards.protocol.v1_19_3to1_19_1.Protocol1_19_3To1_19_1;
import com.viaversion.viabackwards.protocol.v1_19_3to1_19_1.storage.ChatTypeStorage1_19_3;
@@ -31,9 +34,6 @@ import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.version.Types1_19;
import com.viaversion.viaversion.api.type.types.version.Types1_19_3;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.NumberTag;
import com.viaversion.viaversion.protocols.v1_19_1to1_19_3.packet.ClientboundPackets1_19_3;
import com.viaversion.viaversion.protocols.v1_19_1to1_19_3.packet.ServerboundPackets1_19_3;
import com.viaversion.viaversion.protocols.v1_19to1_19_1.packet.ClientboundPackets1_19_1;
@@ -34,10 +34,10 @@ import com.viaversion.viaversion.protocols.v1_19_3to1_19_4.Protocol1_19_3To1_19_
import com.viaversion.viaversion.protocols.v1_19_3to1_19_4.packet.ClientboundPackets1_19_4;
import com.viaversion.viaversion.protocols.v1_19_3to1_19_4.packet.ServerboundPackets1_19_4;
import com.viaversion.viaversion.rewriter.CommandRewriter;
import com.viaversion.viaversion.rewriter.text.ComponentRewriterBase;
import com.viaversion.viaversion.rewriter.ParticleRewriter;
import com.viaversion.viaversion.rewriter.StatisticsRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
import com.viaversion.viaversion.rewriter.text.ComponentRewriterBase;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
@@ -268,7 +268,7 @@ public final class EntityPacketRewriter1_19_4 extends EntityRewriter<Clientbound
final PacketWrapper wrapper = PacketWrapper.create(ClientboundPackets1_19_3.SET_PASSENGERS, event.user());
wrapper.write(Types.VAR_INT, event.entityId()); // Entity id
wrapper.write(Types.VAR_INT_ARRAY_PRIMITIVE, new int[] { linkedEntity }); // Passenger entity ids
wrapper.write(Types.VAR_INT_ARRAY_PRIMITIVE, new int[]{linkedEntity}); // Passenger entity ids
wrapper.send(Protocol1_19_4To1_19_3.class);
});
filter().type(EntityTypes1_19_4.ITEM_DISPLAY).index(22).handler((event, data) -> {
@@ -50,10 +50,10 @@ import com.viaversion.viaversion.protocols.v1_18_2to1_19.packet.ServerboundPacke
import com.viaversion.viaversion.protocols.v1_19to1_19_1.Protocol1_19To1_19_1;
import com.viaversion.viaversion.protocols.v1_19to1_19_1.data.ChatDecorationResult;
import com.viaversion.viaversion.rewriter.CommandRewriter;
import com.viaversion.viaversion.rewriter.text.ComponentRewriterBase;
import com.viaversion.viaversion.rewriter.ParticleRewriter;
import com.viaversion.viaversion.rewriter.StatisticsRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
import com.viaversion.viaversion.rewriter.text.ComponentRewriterBase;
import com.viaversion.viaversion.util.Pair;
import java.security.SignatureException;
import java.time.Instant;
@@ -190,7 +190,7 @@ public final class EntityPacketRewriter1_19 extends EntityRewriter<ClientboundPa
}
}
if (!found) {
throw new IllegalStateException("Could not find dimension " + dimensionKey + " in dimension registry");
throw new IllegalArgumentException("Could not find dimension " + dimensionKey + " in dimension registry");
}
// Add biome category and track biomes
@@ -17,14 +17,14 @@
*/
package com.viaversion.viabackwards.protocol.v1_19to1_18_2.storage;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viabackwards.protocol.v1_19to1_18_2.Protocol1_19To1_18_2;
import com.viaversion.viaversion.api.connection.StorableObject;
import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectMap;
import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectOpenHashMap;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viaversion.util.Key;
import java.util.HashMap;
import java.util.Map;
import com.viaversion.viaversion.util.Key;
import org.checkerframework.checker.nullness.qual.Nullable;
public final class DimensionRegistryStorage implements StorableObject {
@@ -53,9 +53,4 @@ public final class DimensionRegistryStorage implements StorableObject {
dimensions.clear();
chatTypes.clear();
}
@Override
public boolean clearOnServerSwitch() {
return false;
}
}
@@ -17,6 +17,7 @@
*/
package com.viaversion.viabackwards.protocol.v1_20_2to1_20.rewriter;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viabackwards.api.rewriters.EntityRewriter;
import com.viaversion.viabackwards.protocol.v1_20_2to1_20.Protocol1_20_2To1_20;
import com.viaversion.viabackwards.protocol.v1_20_2to1_20.storage.ConfigurationPacketStorage;
@@ -29,7 +30,6 @@ import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.version.Types1_20;
import com.viaversion.viaversion.api.type.types.version.Types1_20_2;
import com.viaversion.viaversion.protocols.v1_19_3to1_19_4.packet.ClientboundPackets1_19_4;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viaversion.protocols.v1_20to1_20_2.packet.ClientboundPackets1_20_2;
public final class EntityPacketRewriter1_20_2 extends EntityRewriter<ClientboundPackets1_20_2, Protocol1_20_2To1_20> {
@@ -21,9 +21,4 @@ import com.viaversion.viaversion.api.connection.StorableObject;
import java.util.UUID;
public record ResourcepackIDStorage(UUID uuid) implements StorableObject {
@Override
public boolean clearOnServerSwitch() {
return false;
}
}
@@ -28,9 +28,4 @@ public final class CookieStorage implements StorableObject {
public Map<String, byte[]> cookies() {
return cookies;
}
@Override
public boolean clearOnServerSwitch() {
return false;
}
}
@@ -30,10 +30,10 @@ import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.data.entity.EntityTrackerBase;
import com.viaversion.viaversion.protocols.v1_19_3to1_19_4.packet.ClientboundPackets1_19_4;
import com.viaversion.viaversion.protocols.v1_19_3to1_19_4.packet.ServerboundPackets1_19_4;
import com.viaversion.viaversion.rewriter.text.ComponentRewriterBase;
import com.viaversion.viaversion.rewriter.ParticleRewriter;
import com.viaversion.viaversion.rewriter.StatisticsRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
import com.viaversion.viaversion.rewriter.text.ComponentRewriterBase;
import com.viaversion.viaversion.util.ArrayUtil;
public final class Protocol1_20To1_19_4 extends BackwardsProtocol<ClientboundPackets1_19_4, ClientboundPackets1_19_4, ServerboundPackets1_19_4, ServerboundPackets1_19_4> {
@@ -17,9 +17,9 @@
*/
package com.viaversion.viabackwards.protocol.v1_20to1_19_4.data;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viabackwards.api.data.BackwardsMappingData;
import com.viaversion.viabackwards.api.data.BackwardsMappingDataLoader;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viaversion.protocols.v1_19_4to1_20.Protocol1_19_4To1_20;
public class BackwardsMappingData1_20 extends BackwardsMappingData {
@@ -18,6 +18,9 @@
package com.viaversion.viabackwards.protocol.v1_20to1_19_4.rewriter;
import com.google.common.collect.Sets;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viabackwards.api.rewriters.EntityRewriter;
import com.viaversion.viabackwards.protocol.v1_20to1_19_4.Protocol1_20To1_19_4;
import com.viaversion.viaversion.api.minecraft.Quaternion;
@@ -29,9 +32,6 @@ import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.version.Types1_19_4;
import com.viaversion.viaversion.api.type.types.version.Types1_20;
import com.viaversion.viaversion.protocols.v1_19_3to1_19_4.packet.ClientboundPackets1_19_4;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viaversion.util.Key;
import java.util.Set;
@@ -316,14 +316,7 @@ public final class EntityPacketRewriter1_21_2 extends EntityRewriter<Clientbound
// Player input no longer sets the sneaking state on the server
// Send the change separately if needed (= when in a vehicle and player commands aren't sent by the old client)
final PlayerStorage sneakingStorage = wrapper.user().get(PlayerStorage.class);
if (sneakingStorage.setSneaking(sneaking)) {
final PacketWrapper playerCommandPacket = wrapper.create(ServerboundPackets1_21_2.PLAYER_COMMAND);
playerCommandPacket.write(Types.VAR_INT, tracker(wrapper.user()).clientEntityId());
playerCommandPacket.write(Types.VAR_INT, sneaking ? 0 : 1); // Start/stop sneaking
playerCommandPacket.write(Types.VAR_INT, 0); // Data
playerCommandPacket.sendToServer(Protocol1_21_2To1_21.class);
}
sendSneakingPlayerCommand(wrapper, sneaking);
});
protocol.registerServerbound(ServerboundPackets1_20_5.MOVE_PLAYER_POS, wrapper -> {
@@ -416,6 +409,7 @@ public final class EntityPacketRewriter1_21_2 extends EntityRewriter<Clientbound
final ClientVehicleStorage storage = wrapper.user().get(ClientVehicleStorage.class);
if (storage != null && vehicleId == storage.vehicleId()) {
wrapper.user().remove(ClientVehicleStorage.class);
sendSneakingPlayerCommand(wrapper, false);
}
final int clientEntityId = tracker(wrapper.user()).clientEntityId();
@@ -436,6 +430,7 @@ public final class EntityPacketRewriter1_21_2 extends EntityRewriter<Clientbound
for (final int entityId : entityIds) {
if (entityId == vehicleStorage.vehicleId()) {
wrapper.user().remove(ClientVehicleStorage.class);
sendSneakingPlayerCommand(wrapper, false);
break;
}
}
@@ -561,6 +556,17 @@ public final class EntityPacketRewriter1_21_2 extends EntityRewriter<Clientbound
}
}
private void sendSneakingPlayerCommand(final PacketWrapper wrapper, final boolean sneaking) {
final PlayerStorage sneakingStorage = wrapper.user().get(PlayerStorage.class);
if (sneakingStorage.setSneaking(sneaking)) {
final PacketWrapper playerCommandPacket = wrapper.create(ServerboundPackets1_21_2.PLAYER_COMMAND);
playerCommandPacket.write(Types.VAR_INT, tracker(wrapper.user()).clientEntityId());
playerCommandPacket.write(Types.VAR_INT, sneaking ? 0 : 1); // Start/stop sneaking
playerCommandPacket.write(Types.VAR_INT, 0); // Data
playerCommandPacket.sendToServer(Protocol1_21_2To1_21.class);
}
}
private int boatTypeFromEntityType(final EntityType type) {
if (type == EntityTypes1_21_2.OAK_BOAT) {
return 0;
@@ -168,7 +168,7 @@ public final class RecipeStorage implements StorableObject {
final String[] recipeKeys = new String[recipes.size()];
final List<String> highlightRecipes = new ArrayList<>();
for (int i = 0; i < recipes.size(); i++) {
recipeKeys[i] = identifier(i);
recipeKeys[i] = identifier(recipes.get(i).index);
if (recipes.get(i).highlight) {
highlightRecipes.add(recipeKeys[i]);
}
@@ -55,6 +55,7 @@ import com.viaversion.viaversion.rewriter.ParticleRewriter;
import com.viaversion.viaversion.rewriter.StatisticsRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
import com.viaversion.viaversion.util.Key;
import com.viaversion.viaversion.util.Limit;
import static com.viaversion.viaversion.util.ProtocolUtil.packetTypeMap;
@@ -160,7 +161,7 @@ public final class Protocol1_21_5To1_21_4 extends BackwardsProtocol<ClientboundP
wrapper.passthrough(Types.STRING); // Command
wrapper.passthrough(Types.LONG); // Timestamp
wrapper.passthrough(Types.LONG); // Salt
final int signatures = wrapper.passthrough(Types.VAR_INT);
final int signatures = Limit.max(wrapper.passthrough(Types.VAR_INT), 8);
for (int i = 0; i < signatures; i++) {
wrapper.passthrough(Types.STRING); // Argument name
wrapper.passthrough(Types.SIGNATURE_BYTES); // Signature
@@ -91,7 +91,7 @@ public final class BlockItemPacketRewriter1_21_5 extends BackwardsStructuredItem
private static final int SIGN_BOCK_ENTITY_ID = 7;
private static final int HANGING_SIGN_BOCK_ENTITY_ID = 8;
private static final int SADDLE_EQUIPMENT_SLOT = 7;
private static final byte SADDLED_FLAG = 4;
static final byte SADDLED_FLAG = 4;
public BlockItemPacketRewriter1_21_5(final Protocol1_21_5To1_21_4 protocol) {
super(protocol);
@@ -187,7 +187,8 @@ public final class BlockItemPacketRewriter1_21_5 extends BackwardsStructuredItem
final int equipmentSlot = value & 0x7F;
if (equipmentSlot == SADDLE_EQUIPMENT_SLOT) {
if (trackedEntity != null && trackedEntity.entityType().isOrHasParent(EntityTypes1_21_5.ABSTRACT_HORSE)) {
sendSaddledEntityData(wrapper.user(), trackedEntity, entityId);
final Item item = wrapper.read(itemType());
sendSaddledEntityData(wrapper.user(), trackedEntity, entityId, item.identifier() == 800);
}
wrapper.cancel();
return;
@@ -268,16 +269,24 @@ public final class BlockItemPacketRewriter1_21_5 extends BackwardsStructuredItem
wrapper.write(Types.STRING, namespace + ":textures/" + path + ".png");
}
private void sendSaddledEntityData(final UserConnection connection, final TrackedEntity trackedEntity, final int entityId) {
private void sendSaddledEntityData(final UserConnection connection, final TrackedEntity trackedEntity, final int entityId, final boolean saddled) {
byte data = 0;
if (trackedEntity.hasData()) {
final HorseDataStorage horseDataStorage = trackedEntity.data().get(HorseDataStorage.class);
if (horseDataStorage != null) {
if (horseDataStorage.saddled() == saddled) {
return;
}
data = horseDataStorage.data();
}
}
trackedEntity.data().put(new HorseDataStorage(data, true));
data = (byte) (data | SADDLED_FLAG);
trackedEntity.data().put(new HorseDataStorage(data, saddled));
if (saddled) {
data = (byte) (data | SADDLED_FLAG);
}
final PacketWrapper entityDataPacket = PacketWrapper.create(ClientboundPackets1_21_2.SET_ENTITY_DATA, connection);
final List<EntityData> entityDataList = new ArrayList<>();
@@ -81,7 +81,14 @@ public final class ComponentRewriter1_21_5 extends NBTComponentRewriter<Clientbo
switch (action) {
case "open_url" -> clickEventTag.put("value", clickEventTag.getStringTag("url"));
case "change_page" -> clickEventTag.putString("value", Integer.toString(clickEventTag.getInt("page")));
case "run_command", "suggest_command" -> clickEventTag.put("value", clickEventTag.getStringTag("command"));
case "run_command" -> {
final StringTag command = clickEventTag.getStringTag("command");
if (command != null && !command.getValue().startsWith("/")) {
command.setValue("/" + command.getValue());
}
clickEventTag.put("value", command);
}
case "suggest_command" -> clickEventTag.put("value", clickEventTag.getStringTag("command"));
}
}
@@ -119,6 +119,12 @@ public final class EntityPacketRewriter1_21_5 extends EntityRewriter<Clientbound
updateTrim(entries, trimPatternRegistry ? "template_item" : "ingredient");
return super.handle(connection, key, entries);
}
if (key.equals("enchantment")) {
updateEnchantment(entries);
return super.handle(connection, key, entries);
}
if (!key.equals("wolf_variant")) {
return super.handle(connection, key, entries);
}
@@ -209,6 +215,20 @@ public final class EntityPacketRewriter1_21_5 extends EntityRewriter<Clientbound
});
}
private void updateEnchantment(final RegistryEntry[] entries) {
for (final RegistryEntry entry : entries) {
if (entry.tag() == null) {
continue;
}
final CompoundTag enchantment = (CompoundTag) entry.tag();
final ListTag<StringTag> slots = enchantment.getListTag("slots", StringTag.class);
if (slots != null) {
slots.getValue().removeIf(tag -> tag.getValue().equals("saddle")); // Remove saddle slot
}
}
}
private String visibility(final int id) {
return switch (id) {
case 0 -> "always";
@@ -274,6 +294,11 @@ public final class EntityPacketRewriter1_21_5 extends EntityRewriter<Clientbound
filter().type(EntityTypes1_21_5.ABSTRACT_MINECART).addIndex(13); // Custom display
filter().type(EntityTypes1_21_5.ABSTRACT_MINECART).index(11).handler((event, data) -> {
final int state = (int) data.getValue();
if (state == 0) {
event.cancel();
return;
}
final int mappedBlockState = protocol.getMappingData().getNewBlockStateId(state);
data.setTypeAndValue(entityDataTypes.varIntType, mappedBlockState);
event.createExtraData(new EntityData(13, mappedEntityDataTypes.booleanType, true));
@@ -286,16 +311,18 @@ public final class EntityPacketRewriter1_21_5 extends EntityRewriter<Clientbound
}));
filter().type(EntityTypes1_21_5.ABSTRACT_HORSE).index(17).handler((event, data) -> {
// Store data for later
// Store data and set saddled flag if needed
final TrackedEntity entity = event.trackedEntity();
if (entity.hasData()) {
final HorseDataStorage horseDataStorage = entity.data().get(HorseDataStorage.class);
if (horseDataStorage != null && horseDataStorage.saddled()) {
entity.data().put(new HorseDataStorage(data.value(), true));
return;
}
final byte horseData = data.value();
boolean saddled = false;
final HorseDataStorage horseDataStorage;
if (entity.hasData() && (horseDataStorage = entity.data().get(HorseDataStorage.class)) != null && horseDataStorage.saddled()) {
saddled = true;
data.setValue((byte) (horseData | BlockItemPacketRewriter1_21_5.SADDLED_FLAG));
}
entity.data().put(new HorseDataStorage(data.value(), false));
entity.data().put(new HorseDataStorage(horseData, saddled));
});
filter().type(EntityTypes1_21_5.CHICKEN).cancel(17); // Chicken variant
@@ -17,15 +17,26 @@
*/
package com.viaversion.viabackwards.protocol.v1_21_6to1_21_5;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.data.BackwardsMappingData;
import com.viaversion.viabackwards.api.rewriters.SoundRewriter;
import com.viaversion.viabackwards.api.rewriters.text.NBTComponentRewriter;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.data.Dialog;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.provider.ChestDialogViewProvider;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.provider.DialogViewProvider;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.rewriter.BlockItemPacketRewriter1_21_6;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.rewriter.ComponentRewriter1_21_6;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.rewriter.EntityPacketRewriter1_21_6;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.storage.ChestDialogStorage;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.storage.ClickEvents;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.storage.RegistryAndTags;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.storage.ServerLinks;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_21_6;
import com.viaversion.viaversion.api.platform.providers.ViaProviders;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.packet.provider.PacketTypesProvider;
import com.viaversion.viaversion.api.protocol.packet.provider.SimplePacketTypesProvider;
@@ -52,6 +63,7 @@ import com.viaversion.viaversion.rewriter.AttributeRewriter;
import com.viaversion.viaversion.rewriter.ParticleRewriter;
import com.viaversion.viaversion.rewriter.StatisticsRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
import com.viaversion.viaversion.util.Key;
import com.viaversion.viaversion.util.SerializerVersion;
import static com.viaversion.viaversion.util.ProtocolUtil.packetTypeMap;
@@ -73,14 +85,27 @@ public final class Protocol1_21_6To1_21_5 extends BackwardsProtocol<ClientboundP
protected void registerPackets() {
super.registerPackets();
tagRewriter.removeTags("dialog");
tagRewriter.registerGeneric(ClientboundPackets1_21_6.UPDATE_TAGS);
tagRewriter.registerGeneric(ClientboundConfigurationPackets1_21_6.UPDATE_TAGS);
registerClientbound(ClientboundPackets1_21_6.UPDATE_TAGS, this::updateTags);
registerClientbound(ClientboundConfigurationPackets1_21_6.UPDATE_TAGS, this::updateTags);
final SoundRewriter<ClientboundPacket1_21_6> soundRewriter = new SoundRewriter<>(this);
soundRewriter.registerSound1_19_3(ClientboundPackets1_21_6.SOUND);
appendClientbound(ClientboundPackets1_21_6.SOUND, wrapper -> {
wrapper.passthrough(Types.VAR_INT); // Source
fixSoundSource(wrapper);
});
soundRewriter.registerSound1_19_3(ClientboundPackets1_21_6.SOUND_ENTITY);
appendClientbound(ClientboundPackets1_21_6.SOUND_ENTITY, wrapper -> {
wrapper.passthrough(Types.VAR_INT); // Source
fixSoundSource(wrapper);
});
soundRewriter.registerStopSound(ClientboundPackets1_21_6.STOP_SOUND);
appendClientbound(ClientboundPackets1_21_6.STOP_SOUND, wrapper -> {
final byte flags = wrapper.get(Types.BYTE, 0);
if ((flags & 0x01) != 0) {
fixSoundSource(wrapper);
}
});
new StatisticsRewriter<>(this).register(ClientboundPackets1_21_6.AWARD_STATS);
new AttributeRewriter<>(this).register1_21(ClientboundPackets1_21_6.UPDATE_ATTRIBUTES);
@@ -112,17 +137,193 @@ public final class Protocol1_21_6To1_21_5 extends BackwardsProtocol<ClientboundP
particleRewriter.registerLevelParticles1_21_4(ClientboundPackets1_21_6.LEVEL_PARTICLES);
particleRewriter.registerExplode1_21_2(ClientboundPackets1_21_6.EXPLODE);
registerClientbound(ClientboundPackets1_21_6.CHANGE_DIFFICULTY, wrapper -> {
final int difficulty = wrapper.read(Types.VAR_INT);
wrapper.write(Types.UNSIGNED_BYTE, (short) difficulty);
});
registerServerbound(ServerboundPackets1_21_5.CHANGE_DIFFICULTY, wrapper -> {
final short difficulty = wrapper.read(Types.UNSIGNED_BYTE);
wrapper.write(Types.VAR_INT, (int) difficulty);
});
// Are you sure you want to see this? This is your last chance to turn back.
registerClientbound(ClientboundPackets1_21_6.SHOW_DIALOG, null, wrapper -> {
wrapper.cancel();
final RegistryAndTags registryAndTags = wrapper.user().get(RegistryAndTags.class);
final ServerLinks serverLinks = wrapper.user().get(ServerLinks.class);
final int id = wrapper.read(Types.VAR_INT) - 1;
CompoundTag tag;
if (id == -1) {
tag = (CompoundTag) wrapper.read(Types.TAG);
} else {
tag = registryAndTags.fromRegistry(id);
}
final DialogViewProvider provider = Via.getManager().getProviders().get(DialogViewProvider.class);
provider.openDialog(wrapper.user(), new Dialog(registryAndTags, serverLinks, tag));
});
registerClientbound(ClientboundConfigurationPackets1_21_6.SHOW_DIALOG, null, wrapper -> {
wrapper.cancel();
final RegistryAndTags registryAndTags = wrapper.user().get(RegistryAndTags.class);
final ServerLinks serverLinks = wrapper.user().get(ServerLinks.class);
final CompoundTag tag = (CompoundTag) wrapper.read(Types.TAG);
final DialogViewProvider provider = Via.getManager().getProviders().get(DialogViewProvider.class);
provider.openDialog(wrapper.user(), new Dialog(registryAndTags, serverLinks, tag));
});
registerClientbound(ClientboundPackets1_21_6.CLEAR_DIALOG, null, this::clearDialog);
registerClientbound(ClientboundConfigurationPackets1_21_6.CLEAR_DIALOG, null, this::clearDialog);
registerClientbound(ClientboundPackets1_21_6.SERVER_LINKS, this::storeServerLinks);
registerClientbound(ClientboundConfigurationPackets1_21_6.SERVER_LINKS, this::storeServerLinks);
registerServerbound(ServerboundPackets1_21_5.CHAT_COMMAND, wrapper -> {
final String command = wrapper.passthrough(Types.STRING);
final ClickEvents clickEvents = wrapper.user().get(ClickEvents.class);
if (clickEvents.handleChatCommand(wrapper.user(), command)) {
wrapper.cancel();
}
});
// The ones below are specific to the chest dialog view provider
registerServerbound(ServerboundPackets1_21_5.CONTAINER_CLOSE, wrapper -> {
final ChestDialogStorage storage = wrapper.user().get(ChestDialogStorage.class);
if (storage == null) {
return;
}
final ChestDialogViewProvider provider = (ChestDialogViewProvider) Via.getManager().getProviders().get(DialogViewProvider.class);
if (storage.phase() == ChestDialogStorage.Phase.ANVIL_VIEW) {
wrapper.cancel();
provider.openChestView(wrapper.user(), storage, ChestDialogStorage.Phase.DIALOG_VIEW);
return;
}
if (storage.phase() == ChestDialogStorage.Phase.WAITING_FOR_RESPONSE) {
wrapper.cancel();
if (storage.closeButtonEnabled()) {
provider.openChestView(wrapper.user(), storage, ChestDialogStorage.Phase.DIALOG_VIEW);
} else {
provider.openChestView(wrapper.user(), storage, ChestDialogStorage.Phase.WAITING_FOR_RESPONSE);
}
return;
}
final boolean allowClosing = storage.allowClosing();
if (!allowClosing) {
wrapper.cancel();
if (storage.dialog().canCloseWithEscape()) {
provider.clickButton(wrapper.user(), Dialog.AfterAction.CLOSE, storage.dialog().actionButton());
} else {
provider.openChestView(wrapper.user(), storage, ChestDialogStorage.Phase.DIALOG_VIEW);
}
}
storage.setAllowClosing(false);
});
registerServerbound(ServerboundPackets1_21_5.RENAME_ITEM, wrapper -> {
final ChestDialogStorage storage = wrapper.user().get(ChestDialogStorage.class);
if (storage == null || storage.phase() != ChestDialogStorage.Phase.ANVIL_VIEW) {
return;
}
wrapper.cancel();
final String name = wrapper.read(Types.STRING);
final ChestDialogViewProvider provider = (ChestDialogViewProvider) Via.getManager().getProviders().get(DialogViewProvider.class);
provider.updateAnvilText(wrapper.user(), name);
});
appendServerbound(ServerboundPackets1_21_5.CONTAINER_CLICK, wrapper -> {
final ChestDialogViewProvider provider = (ChestDialogViewProvider) Via.getManager().getProviders().get(DialogViewProvider.class);
if (provider == null) {
return;
}
final int containerId = wrapper.get(Types.VAR_INT, 0);
final int slot = wrapper.get(Types.SHORT, 0);
final byte button = wrapper.get(Types.BYTE, 0);
final int mode = wrapper.get(Types.VAR_INT, 2);
if (provider.clickDialog(wrapper.user(), containerId, slot, button, mode)) {
wrapper.cancel();
}
});
cancelClientbound(ClientboundPackets1_21_6.TRACKED_WAYPOINT);
cancelClientbound(ClientboundPackets1_21_6.CLEAR_DIALOG);
cancelClientbound(ClientboundPackets1_21_6.SHOW_DIALOG);
cancelClientbound(ClientboundConfigurationPackets1_21_6.CLEAR_DIALOG);
cancelClientbound(ClientboundConfigurationPackets1_21_6.SHOW_DIALOG);
}
private void fixSoundSource(final PacketWrapper wrapper) {
final int source = wrapper.get(Types.VAR_INT, 0);
if (source == 10) { // New ui source, map to master
wrapper.set(Types.VAR_INT, 0, 0);
}
}
private void updateTags(final PacketWrapper wrapper) {
tagRewriter.handleGeneric(wrapper);
wrapper.resetReader();
final RegistryAndTags registryAndTags = wrapper.user().get(RegistryAndTags.class);
final int length = wrapper.passthrough(Types.VAR_INT);
for (int i = 0; i < length; i++) {
final String registryKey = wrapper.read(Types.STRING);
final boolean dialog = "dialog".equals(Key.stripMinecraftNamespace(registryKey));
if (dialog) {
final int tagsSize = wrapper.read(Types.VAR_INT);
for (int j = 0; j < tagsSize; j++) {
final String key = wrapper.read(Types.STRING);
final int[] ids = wrapper.read(Types.VAR_INT_ARRAY_PRIMITIVE);
registryAndTags.storeTags(key, ids);
}
} else {
wrapper.write(Types.STRING, registryKey); // Write back
final int tagsSize = wrapper.passthrough(Types.VAR_INT);
for (int j = 0; j < tagsSize; j++) {
wrapper.passthrough(Types.STRING);
wrapper.passthrough(Types.VAR_INT_ARRAY_PRIMITIVE);
}
}
}
if (registryAndTags.tagsSent()) {
wrapper.set(Types.VAR_INT, 0, length - 1); // Dialog tags have been read, remove from size
}
}
private void clearDialog(final PacketWrapper wrapper) {
wrapper.cancel();
final DialogViewProvider provider = Via.getManager().getProviders().get(DialogViewProvider.class);
provider.closeDialog(wrapper.user());
}
private void storeServerLinks(final PacketWrapper wrapper) {
final ServerLinks serverLinks = new ServerLinks();
final int length = wrapper.passthrough(Types.VAR_INT);
for (int i = 0; i < length; i++) {
if (wrapper.passthrough(Types.BOOLEAN)) {
final int id = wrapper.passthrough(Types.VAR_INT);
final String url = wrapper.passthrough(Types.STRING);
serverLinks.storeLink(id, url);
} else {
final Tag tag = wrapper.passthrough(Types.COMPOUND_TAG);
final String url = wrapper.passthrough(Types.STRING);
serverLinks.storeLink(tag, url);
}
}
wrapper.user().put(serverLinks);
}
@Override
public void init(final UserConnection user) {
addEntityTracker(user, new EntityTrackerBase(user, EntityTypes1_21_6.PLAYER));
addItemHasher(user, new ItemHasherBase(this, user, SerializerVersion.V1_21_5, SerializerVersion.V1_21_5));
user.put(new RegistryAndTags());
user.put(new ClickEvents());
}
@Override
public void register(final ViaProviders providers) {
providers.register(DialogViewProvider.class, new ChestDialogViewProvider(this));
}
@Override
@@ -0,0 +1,171 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.data;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.data.input.Input;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.data.widget.Widget;
import com.viaversion.viaversion.util.Key;
import java.util.HashMap;
import java.util.Map;
import org.checkerframework.checker.nullness.qual.Nullable;
public class Button implements Widget {
public static final Button DEFAULT = defaulted();
private static final String[] CLICK_EVENTS = {
"open_url",
"run_command",
"suggest_command",
"show_dialog",
"change_page",
"copy_to_clipboard",
"custom"
};
private final Dialog dialog;
private final Tag label;
private final int width;
private final @Nullable Tag tooltip;
private @Nullable CompoundTag clickEvent;
private @Nullable Template template;
private @Nullable String id;
private @Nullable CompoundTag additions;
public Button(final Dialog dialog, final CompoundTag tag) {
this.dialog = dialog;
this.label = tag.get("label");
this.tooltip = tag.get("tooltip");
final int width = tag.getInt("width", 150);
if (width < 1 || width > 1024) {
throw new IllegalArgumentException("Width must be between 1 and 1024, got: " + width);
}
this.width = width;
final CompoundTag actionTag = tag.getCompoundTag("action");
if (actionTag == null) {
return;
}
final String type = actionTag.getString("type");
if (type == null) {
throw new IllegalArgumentException("Action type is missing in tag: " + tag);
}
for (final String event : CLICK_EVENTS) {
if (Key.stripMinecraftNamespace(type).equals(event)) {
clickEvent = actionTag;
clickEvent.put("action", clickEvent.remove("type"));
return;
}
}
if (Key.stripMinecraftNamespace(type).equals("dynamic/run_command")) {
template = Template.fromString(actionTag.getString("template"));
} else if (Key.stripMinecraftNamespace(type).equals("dynamic/custom")) {
id = actionTag.getString("id");
additions = actionTag.getCompoundTag("additions");
}
}
private static Button defaulted() {
final CompoundTag tag = new CompoundTag();
final CompoundTag label = new CompoundTag();
tag.put("label", label);
label.putString("translate", "gui.ok");
return new Button(null, tag);
}
public static Button openUrl(final Tag label, final String url) {
final CompoundTag tag = new CompoundTag();
final CompoundTag actionTag = new CompoundTag();
final CompoundTag openUrlTag = new CompoundTag();
tag.put("label", label);
tag.put("action", actionTag);
actionTag.putString("type", "open_url");
actionTag.put("action", openUrlTag);
openUrlTag.putString("url", url);
return new Button(null, tag);
}
/**
* Creates a click event for this button based on the provided inputs.
*
* @return a CompoundTag representing the click event, which can be used in a button action.
*/
public @Nullable CompoundTag clickEvent() {
if (clickEvent != null) {
return clickEvent;
}
if (dialog == null) {
return null;
}
final Input[] inputs = dialog.widgets()
.stream()
.filter(widget -> widget instanceof Input)
.toArray(Input[]::new);
if (template != null) {
final Map<String, String> substitutions = new HashMap<>();
for (final Input input : inputs) {
substitutions.put(input.key(), input.asCommandSubstitution());
}
final CompoundTag tag = new CompoundTag();
tag.putString("action", "run_command");
tag.putString("command", template.instantiate(substitutions));
return tag;
}
if (id != null) {
final CompoundTag additions = this.additions != null ? this.additions.copy() : new CompoundTag();
for (final Input input : inputs) {
additions.put(input.key(), input.asTag());
}
final CompoundTag tag = new CompoundTag();
tag.putString("action", "custom");
tag.putString("id", id);
tag.put("payload", additions);
return tag;
}
return null;
}
public Tag label() {
return label;
}
public @Nullable Tag tooltip() {
return tooltip;
}
public int width() {
return width;
}
}
@@ -0,0 +1,253 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.data;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.data.input.BooleanInput;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.data.input.NumberRangeInput;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.data.input.SingleOptionInput;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.data.input.TextInput;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.data.widget.ItemWidget;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.data.widget.TextWidget;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.data.widget.Widget;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.provider.ChestDialogViewProvider;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.storage.RegistryAndTags;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.storage.ServerLinks;
import com.viaversion.viaversion.util.Key;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* The dialog structure. See the used subclasses for further details on the
* specific structure. Note that the data hold here is directly from the server
* and needs to be remapped manually when used. See {@link ChestDialogViewProvider} for an example
*/
public final class Dialog implements Widget {
private final List<Widget> widgets = new ArrayList<>();
private final Tag title;
private final @Nullable Tag externalTitle;
private final boolean canCloseWithEscape;
private final AfterAction afterAction;
private @Nullable Button actionButton;
private @Nullable Button yesButton;
private @Nullable Button noButton;
private int columns;
private int buttonWidth;
public Dialog(final RegistryAndTags registryAndTags, final ServerLinks serverLinks, final CompoundTag tag) {
final String type = tag.getString("type");
if (type == null) {
throw new IllegalArgumentException("Dialog type is missing in tag: " + tag);
}
this.title = tag.get("title");
this.externalTitle = tag.get("external_title");
this.canCloseWithEscape = tag.getBoolean("can_close_with_escape", true);
this.afterAction = AfterAction.valueOf(tag.getString("after_action", "close").toUpperCase(Locale.ROOT));
ListTag<CompoundTag> bodyListTag = tag.getListTag("body", CompoundTag.class);
if (bodyListTag == null) {
CompoundTag bodyTag = tag.getCompoundTag("body");
if (bodyTag != null) {
bodyListTag = new ListTag<>(CompoundTag.class);
bodyListTag.add(bodyTag);
}
}
if (bodyListTag != null) {
for (final CompoundTag bodyTag : bodyListTag) {
fillBodyWidget(bodyTag);
}
}
final ListTag<CompoundTag> inputListTag = tag.getListTag("inputs", CompoundTag.class);
if (inputListTag != null) {
for (final CompoundTag inputTag : inputListTag) {
fillInputWidget(inputTag);
}
}
switch (Key.stripMinecraftNamespace(type)) {
case "notice" -> fillNoticeDialog(tag);
case "server_links" -> fillServerLinksDialog(serverLinks, tag);
case "dialog_list" -> fillDialogList(registryAndTags, serverLinks, tag);
case "multi_action" -> fillMultiActionDialog(tag);
case "confirmation" -> fillConfirmationDialog(tag);
default -> throw new IllegalArgumentException("Unknown dialog type: " + type + " in tag: " + tag);
}
}
private void fillBodyWidget(final CompoundTag tag) {
final String type = tag.getString("type");
if (type == null) {
throw new IllegalArgumentException("Dialog type is missing in tag: " + tag);
}
if (Key.stripMinecraftNamespace(type).equals("plain_message")) {
widgets.add(new TextWidget(tag));
} else if (Key.stripMinecraftNamespace(type).equals("item")) {
widgets.add(new ItemWidget(tag));
} else {
throw new IllegalArgumentException("Unknown dialog body type: " + type + " in tag: " + tag);
}
}
private void fillInputWidget(final CompoundTag tag) {
final String type = tag.getString("type");
if (type == null) {
throw new IllegalArgumentException("Dialog type is missing in tag: " + tag);
}
widgets.add(switch (Key.stripMinecraftNamespace(type)) {
case "boolean" -> new BooleanInput(tag);
case "number_range" -> new NumberRangeInput(tag);
case "single_option" -> new SingleOptionInput(tag);
case "text" -> new TextInput(tag);
default -> throw new IllegalArgumentException("Unknown dialog input type: " + type + " in tag: " + tag);
});
}
private void fillNoticeDialog(final CompoundTag tag) {
final CompoundTag actionTag = tag.getCompoundTag("action");
actionButton = actionTag == null ? Button.DEFAULT : actionButton;
}
private void fillServerLinksDialog(final ServerLinks serverLinks, final CompoundTag tag) {
fillDialogBase(tag);
buttonWidth = tag.getInt("button_width", 150);
if (serverLinks == null) {
return;
}
for (final Map.Entry<Tag, String> entry : serverLinks.links().entrySet()) {
final Tag label = entry.getKey();
final String url = entry.getValue();
widgets.add(Button.openUrl(label, url));
}
}
private void fillDialogList(final RegistryAndTags registryAndTags, final ServerLinks serverLinks, final CompoundTag tag) {
// Hold them as either a list of inlined, a singleton inlined, a registry entry or a tag.
ListTag<CompoundTag> dialogsTag = tag.getListTag("dialogs", CompoundTag.class);
if (dialogsTag == null) {
CompoundTag dialogTag = tag.getCompoundTag("dialogs");
if (dialogTag != null) {
dialogsTag = new ListTag<>(CompoundTag.class);
dialogsTag.add(dialogTag);
}
StringTag registryDialogTag = tag.getStringTag("dialogs");
if (registryDialogTag != null) {
dialogsTag = new ListTag<>(CompoundTag.class);
final String key = registryDialogTag.getValue();
if (key.startsWith("#")) {
for (final CompoundTag entry : registryAndTags.fromRegistryKey(key.substring(1))) {
dialogsTag.add(entry);
}
} else {
dialogsTag.add(registryAndTags.fromRegistry(key));
}
}
}
widgets.addAll(dialogsTag.stream().map(dialog -> new Dialog(registryAndTags, serverLinks, dialog)).toList());
fillDialogBase(tag);
buttonWidth = tag.getInt("button_width", 150);
}
private void fillDialogBase(final CompoundTag tag) {
final CompoundTag exitActionTag = tag.getCompoundTag("exit_action");
actionButton = exitActionTag == null ? null : new Button(this, exitActionTag);
final int columns = tag.getInt("columns", 2);
if (columns < 1) {
throw new IllegalArgumentException("Columns must be non-negative, got: " + columns);
}
this.columns = columns;
}
private void fillMultiActionDialog(final CompoundTag tag) {
final ListTag<CompoundTag> actionsTag = tag.getListTag("actions", CompoundTag.class);
if (actionsTag == null || actionsTag.isEmpty()) {
throw new IllegalArgumentException("Actions must not be empty in tag: " + tag);
}
widgets.addAll(actionsTag.stream().map(actionTag -> new Button(this, actionTag)).toList());
fillDialogBase(tag);
}
private void fillConfirmationDialog(final CompoundTag tag) {
yesButton = new Button(this, tag.getCompoundTag("yes"));
noButton = new Button(this, tag.getCompoundTag("no"));
}
public Tag title() {
return title;
}
public @Nullable Tag externalTitle() {
return externalTitle;
}
public boolean canCloseWithEscape() {
return canCloseWithEscape;
}
public AfterAction afterAction() {
return afterAction;
}
public enum AfterAction {
CLOSE,
NONE,
WAIT_FOR_RESPONSE
}
public @Nullable Button actionButton() {
return actionButton;
}
public @Nullable Button yesButton() {
return yesButton;
}
public @Nullable Button noButton() {
return noButton;
}
public int columns() {
return columns;
}
public int buttonWidth() {
return buttonWidth;
}
public List<Widget> widgets() {
return widgets;
}
}
@@ -0,0 +1,97 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.data;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
import java.util.List;
import java.util.Map;
public record Template(List<String> segments, List<String> variables) {
private static final int MAX_LENGTH = 2000000;
public static Template fromString(final String string) {
final Builder<String> segmentsBuilder = ImmutableList.builder();
final Builder<String> variablesBuilder = ImmutableList.builder();
int currentIndex = 0;
int dollarIndex = string.indexOf('$');
while (dollarIndex != -1) {
if (dollarIndex != string.length() - 1 && string.charAt(dollarIndex + 1) == '(') {
segmentsBuilder.add(string.substring(currentIndex, dollarIndex));
final int closingParenIndex = string.indexOf(41, dollarIndex + 1);
if (closingParenIndex == -1) {
throw new IllegalArgumentException("Unterminated macro variable");
}
final String variableName = string.substring(dollarIndex + 2, closingParenIndex);
if (!isValidVariableName(variableName)) {
throw new IllegalArgumentException("Invalid macro variable name '" + variableName + "'");
}
variablesBuilder.add(variableName);
currentIndex = closingParenIndex + 1;
dollarIndex = string.indexOf(36, currentIndex);
} else {
dollarIndex = string.indexOf(36, dollarIndex + 1);
}
}
if (currentIndex == 0) {
throw new IllegalArgumentException("No variables in macro");
}
if (currentIndex != string.length()) {
segmentsBuilder.add(string.substring(currentIndex));
}
return new Template(segmentsBuilder.build(), variablesBuilder.build());
}
private static boolean isValidVariableName(final String string) {
for (int i = 0; i < string.length(); i++) {
final char c = string.charAt(i);
if (!Character.isLetterOrDigit(c) && c != '_') {
return false;
}
}
return true;
}
public String instantiate(final Map<String, String> map) {
return substitute(variables().stream().map(string -> map.getOrDefault(string, "")).toList());
}
private String substitute(final List<String> list) {
final StringBuilder out = new StringBuilder();
for (int i = 0; i < this.variables.size(); i++) {
out.append(this.segments.get(i)).append(list.get(i));
if (out.length() > MAX_LENGTH) {
throw new IllegalArgumentException("Output too long (> " + MAX_LENGTH + ")");
}
}
if (this.segments.size() > this.variables.size()) {
out.append(this.segments.get(this.segments.size() - 1));
if (out.length() > MAX_LENGTH) {
throw new IllegalArgumentException("Output too long (> " + MAX_LENGTH + ")");
}
}
return out.toString();
}
}
@@ -0,0 +1,82 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.data.input;
import com.viaversion.nbt.tag.ByteTag;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.Tag;
public final class BooleanInput implements Input {
private final String key;
private final Tag label;
private final boolean initial;
private final String onTrue;
private final String onFalse;
private boolean value;
public BooleanInput(final CompoundTag tag) {
this.key = tag.getString("key");
this.label = tag.get("label");
this.initial = tag.getBoolean("initial", false);
this.onTrue = tag.getString("on_true", "true");
this.onFalse = tag.getString("on_false", "false");
this.value = initial;
}
@Override
public String key() {
return key;
}
@Override
public String asCommandSubstitution() {
return value ? onTrue : onFalse;
}
@Override
public Tag asTag() {
return new ByteTag(value);
}
public Tag label() {
return label;
}
public boolean initial() {
return initial;
}
public String onTrue() {
return onTrue;
}
public String onFalse() {
return onFalse;
}
public boolean value() {
return value;
}
public void setValue(final boolean value) {
this.value = value;
}
}
@@ -0,0 +1,31 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.data.input;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.data.widget.Widget;
public interface Input extends Widget {
String key();
String asCommandSubstitution();
Tag asTag();
}
@@ -0,0 +1,114 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.data.input;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.FloatTag;
import com.viaversion.nbt.tag.Tag;
import static com.viaversion.viabackwards.utils.ChatUtil.text;
import static com.viaversion.viabackwards.utils.ChatUtil.translate;
public final class NumberRangeInput implements Input {
private final String key;
private final Tag label;
private final String labelFormat;
private final float start;
private final float end;
private final Float initial;
private final Float step;
private float value;
public NumberRangeInput(final CompoundTag tag) {
this.key = tag.getString("key");
this.label = tag.get("label");
this.labelFormat = tag.getString("label_format", "options.generic_value");
this.start = tag.getFloat("start");
this.end = tag.getFloat("end");
this.initial = tag.getFloat("initial", (this.start + this.end) / 2F);
final FloatTag stepTag = tag.getFloatTag("step");
if (stepTag != null && stepTag.asFloat() < 0F) {
throw new IllegalArgumentException("Step must be non-negative, got: " + stepTag.asFloat());
}
this.step = stepTag == null ? -1F : stepTag.asFloat();
this.value = initial;
}
@Override
public String key() {
return key;
}
@Override
public String asCommandSubstitution() {
return valueAsString();
}
@Override
public Tag asTag() {
return new FloatTag(value);
}
public Tag label() {
return label;
}
public String labelFormat() {
return labelFormat;
}
public float start() {
return start;
}
public float end() {
return end;
}
public float initial() {
return initial;
}
public float step() {
return step;
}
public float value() {
return value;
}
public String valueAsString() {
final int asInt = (int) value;
return asInt == value ? Integer.toString(asInt) : Float.toString(value);
}
public void setValue(final float value) {
this.value = value;
}
public void setClampedValue(final float value) {
this.value = (value < start) ? start : Math.min(value, end);
}
public Tag displayName() {
return translate(labelFormat, label, text(valueAsString()));
}
}
@@ -0,0 +1,126 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.data.input;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import java.util.Objects;
import org.checkerframework.checker.nullness.qual.Nullable;
public final class SingleOptionInput implements Input {
private final String key;
private final Entry[] options;
private final @Nullable Tag label;
private int value;
public SingleOptionInput(final CompoundTag tag) {
final ListTag<CompoundTag> options = tag.getListTag("options", CompoundTag.class);
if (options == null || options.isEmpty()) {
throw new IllegalArgumentException("Options must not be empty in tag: " + tag);
}
this.key = tag.getString("key");
this.options = options.stream().map(Entry::new).toArray(Entry[]::new);
this.label = tag.getBoolean("label_visible", true) ? tag.get("label") : null;
for (int i = 0; i < this.options.length; i++) {
if (this.options[i].initial()) {
if (this.value != 0) {
throw new IllegalArgumentException("Multiple initial options found in tag: " + tag);
}
this.value = i;
}
}
}
@Override
public String key() {
return key;
}
@Override
public String asCommandSubstitution() {
return this.options[value].id;
}
@Override
public Tag asTag() {
return new StringTag(asCommandSubstitution());
}
public Entry[] options() {
return options;
}
public @Nullable Tag label() {
return label;
}
public int value() {
return value;
}
public void setValue(final int value) {
if (value < 0 || value >= options.length) {
throw new IllegalArgumentException("Value must be between 0 and " + (options.length - 1));
}
this.value = value;
}
public void setClampedValue(final int value) {
if (value < 0) {
this.value = 0;
} else if (value >= options.length) {
this.value = 0;
} else {
this.value = value;
}
}
public static class Entry {
private final String id;
private final Tag display;
private final boolean initial;
public Entry(final CompoundTag tag) {
id = tag.getString("id");
display = tag.get("display");
initial = tag.getBoolean("initial", false);
}
public String id() {
return id;
}
public Tag display() {
return display;
}
public boolean initial() {
return initial;
}
public Tag computeDisplay() {
return Objects.requireNonNullElseGet(display, () -> new StringTag(id));
}
}
}
@@ -0,0 +1,121 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.data.input;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.IntTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import org.checkerframework.checker.nullness.qual.Nullable;
public final class TextInput implements Input {
private final String key;
private final @Nullable Tag label;
private final String initial;
private final int maxLength;
private final @Nullable MultilineOptions[] options;
private String value;
public TextInput(final CompoundTag tag) {
this.key = tag.getString("key");
this.label = tag.getBoolean("label_visible", true) ? tag.get("label") : null;
this.initial = tag.getString("initial", "");
this.maxLength = tag.getInt("max_length", 32);
if (this.maxLength < 1) {
throw new IllegalArgumentException("Max length must be at least 1, got: " + this.maxLength);
}
final ListTag<CompoundTag> multilineList = tag.getListTag("multiline", CompoundTag.class);
if (multilineList != null && !multilineList.isEmpty()) {
this.options = multilineList.stream().map(MultilineOptions::new).toArray(MultilineOptions[]::new);
} else {
this.options = null;
}
this.value = initial;
}
@Override
public String key() {
return key;
}
@Override
public String asCommandSubstitution() {
return value;
}
@Override
public Tag asTag() {
return new StringTag(value);
}
public @Nullable Tag label() {
return label;
}
public String initial() {
return initial;
}
public int maxLength() {
return maxLength;
}
public @Nullable MultilineOptions[] options() {
return options;
}
public String value() {
return value;
}
public void setValue(final String value) {
if (value.length() > maxLength) {
throw new IllegalArgumentException("Value exceeds max length of " + maxLength + ": " + value);
}
this.value = value;
}
public void setClampedValue(final String value) {
if (value.length() > maxLength) {
this.value = value.substring(0, maxLength);
} else {
this.value = value;
}
}
public static class MultilineOptions {
private final @Nullable Integer maxLines;
public MultilineOptions(final CompoundTag tag) {
final IntTag maxLinesTag = tag.getIntTag("max_lines");
if (maxLinesTag != null && maxLinesTag.asInt() < 1) {
throw new IllegalArgumentException("Max lines must be at least 1, got: " + maxLinesTag);
}
this.maxLines = maxLinesTag != null ? maxLinesTag.asInt() : null;
}
public @Nullable Integer maxLines() {
return maxLines;
}
}
}
@@ -0,0 +1,69 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.data.widget;
import com.viaversion.nbt.tag.CompoundTag;
import org.checkerframework.checker.nullness.qual.Nullable;
public final class ItemWidget implements Widget {
private final CompoundTag item;
private final @Nullable TextWidget description;
private final boolean showTooltip;
private final int width;
private final int height;
public ItemWidget(final CompoundTag tag) {
this.item = tag.getCompoundTag("item");
if (this.item == null) {
throw new IllegalArgumentException("Item tag is missing in ItemWidget tag: " + tag);
}
this.description = tag.contains("description") ? new TextWidget(tag.getCompoundTag("description")) : null;
this.showTooltip = tag.getBoolean("show_tooltip", true);
final int width = tag.getInt("width", 16);
final int height = tag.getInt("height", 16);
if (width < 1 || width > 256) {
throw new IllegalArgumentException("Width must be between 1 and 256, got: " + width);
}
if (height < 1 || height > 256) {
throw new IllegalArgumentException("Height must be between 1 and 256, got: " + height);
}
this.width = width;
this.height = height;
}
public CompoundTag item() {
return item;
}
public @Nullable TextWidget description() {
return description;
}
public boolean showTooltip() {
return showTooltip;
}
public int width() {
return width;
}
public int height() {
return height;
}
}
@@ -0,0 +1,40 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.data.widget;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.Tag;
public final class TextWidget implements Widget {
private final Tag label;
private final int width;
public TextWidget(final CompoundTag tag) {
this.label = tag.get("contents");
this.width = tag.getInt("width", 200);
}
public Tag label() {
return label;
}
public int width() {
return width;
}
}
@@ -0,0 +1,21 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.data.widget;
public interface Widget {
}
@@ -0,0 +1,598 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.provider;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.Protocol1_21_6To1_21_5;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.data.Button;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.data.Dialog;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.data.input.BooleanInput;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.data.input.NumberRangeInput;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.data.input.SingleOptionInput;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.data.input.TextInput;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.data.widget.ItemWidget;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.data.widget.TextWidget;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.data.widget.Widget;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.storage.ChestDialogStorage;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.storage.ClickEvents;
import com.viaversion.viabackwards.utils.ChatUtil;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataContainer;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.minecraft.item.StructuredItem;
import com.viaversion.viaversion.api.minecraft.item.data.TooltipDisplay;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.packet.State;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.version.VersionedTypes;
import com.viaversion.viaversion.libs.fastutil.ints.IntSortedSets;
import com.viaversion.viaversion.protocols.v1_21_4to1_21_5.packet.ClientboundPackets1_21_5;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ServerboundPackets1_21_6;
import com.viaversion.viaversion.util.Key;
import com.viaversion.viaversion.util.MathUtil;
import java.util.ArrayList;
import java.util.List;
import org.checkerframework.checker.nullness.qual.Nullable;
import static com.viaversion.viabackwards.utils.ChatUtil.fixStyle;
import static com.viaversion.viabackwards.utils.ChatUtil.text;
import static com.viaversion.viabackwards.utils.ChatUtil.translate;
/**
* Default dialog view emulator. The layout has been stretched into a lot sub-functions for plugins to override.
*/
public class ChestDialogViewProvider implements DialogViewProvider {
private static final int INVENTORY_SIZE = 27;
private static final int INVENTORY_LAST_ROW = INVENTORY_SIZE - 9;
private final Protocol1_21_6To1_21_5 protocol;
public ChestDialogViewProvider(final Protocol1_21_6To1_21_5 protocol) {
this.protocol = protocol;
}
@Override
public void openDialog(final UserConnection connection, final Dialog dialog) {
final State state = connection.getProtocolInfo().getClientState();
if (state == State.CONFIGURATION) {
// TODO Implement by ending and re-starting the configuration phase
return;
}
// Batch text widgets following one another into a single MultiTextWidget to be display properly.
final List<Tag> texts = new ArrayList<>();
for (final Widget widget : new ArrayList<>(dialog.widgets())) {
if (widget instanceof final TextWidget textWidget) {
texts.add(textWidget.label());
dialog.widgets().remove(textWidget);
} else if (!texts.isEmpty()) {
dialog.widgets().add(dialog.widgets().indexOf(widget), new MultiTextWidget(texts.toArray(Tag[]::new)));
texts.clear();
}
}
final ChestDialogStorage previousStorage = connection.get(ChestDialogStorage.class);
final ChestDialogStorage storage = new ChestDialogStorage(this, dialog);
if (previousStorage != null) {
storage.setPreviousDialog(previousStorage.dialog());
}
connection.put(storage);
openChestView(connection, storage, ChestDialogStorage.Phase.DIALOG_VIEW);
}
public void openChestView(final UserConnection connection, final ChestDialogStorage storage, ChestDialogStorage.Phase phase) {
storage.setPhase(connection, phase);
final PacketWrapper openScreen = PacketWrapper.create(ClientboundPackets1_21_5.OPEN_SCREEN, connection);
openScreen.write(Types.VAR_INT, storage.containerId());
openScreen.write(Types.VAR_INT, 2); // Container type id
openScreen.write(Types.TAG, storage.dialog().title());
openScreen.send(Protocol1_21_6To1_21_5.class);
updateDialog(connection, storage.dialog());
}
@Override
public void closeDialog(final UserConnection connection) {
final State state = connection.getProtocolInfo().getClientState();
if (state == State.CONFIGURATION) {
// TODO Implement by ending and re-starting the configuration phase
return;
}
final ChestDialogStorage storage = connection.get(ChestDialogStorage.class);
final PacketWrapper containerClose = PacketWrapper.create(ClientboundPackets1_21_5.CONTAINER_CLOSE, connection);
containerClose.write(Types.VAR_INT, storage.containerId());
containerClose.send(Protocol1_21_6To1_21_5.class);
if (storage.previousDialog() != null) {
openDialog(connection, storage.previousDialog());
} else {
connection.remove(ChestDialogStorage.class);
}
}
public boolean clickDialog(final UserConnection connection, final int container, int slot, final byte mouse, final int mode) {
final ChestDialogStorage storage = connection.get(ChestDialogStorage.class);
if (storage == null || storage.containerId() != container) {
return false;
}
if (mode != 0 || slot < 0 || slot >= INVENTORY_SIZE) {
updateDialog(connection, storage.dialog()); // Resync inventory view
return true;
}
if (storage.phase() == ChestDialogStorage.Phase.ANVIL_VIEW) {
openChestView(connection, storage, ChestDialogStorage.Phase.DIALOG_VIEW);
return true;
}
if (storage.phase() == ChestDialogStorage.Phase.WAITING_FOR_RESPONSE) {
if (slot == storage.actionIndex() && storage.closeButtonEnabled()) {
closeDialog(connection);
} else {
updateDialog(connection, storage.dialog()); // Resync inventory view
}
return true;
}
// Page navigation
if (slot == INVENTORY_SIZE - 1) {
final int pages = MathUtil.ceil(storage.items().length / (float) INVENTORY_LAST_ROW);
if (mouse == 0) {
storage.page++;
} else if (mouse == 1) {
storage.page--;
}
storage.page = MathUtil.clamp(storage.page, 0, pages - 1);
}
slot += storage.page * INVENTORY_LAST_ROW;
// Input widgets
final List<Widget> widgets = storage.dialog().widgets();
if (slot < widgets.size()) {
final Widget widget = widgets.get(slot);
if (widget instanceof final BooleanInput booleanInput) {
clickBooleanInput(booleanInput);
} else if (widget instanceof final NumberRangeInput numberRangeInput) {
clickNumberRangeInput(numberRangeInput, mouse);
} else if (widget instanceof final TextInput textInput) {
clickTextInput(connection, textInput);
} else if (widget instanceof final SingleOptionInput singleOptionInput) {
clickSingleOptionInput(singleOptionInput);
} else if (widget instanceof final Button button) {
clickButton(connection, storage.dialog().afterAction(), button);
} else if (widget instanceof final Dialog dialog) {
clickDialogButton(connection, dialog);
}
}
// And some special cases.
if (slot == storage.confirmationYesIndex()) {
final Button yesButton = storage.dialog().yesButton();
if (yesButton != null) {
clickButton(connection, storage.dialog().afterAction(), yesButton);
}
}
if (slot == storage.confirmationNoIndex()) {
final Button noButton = storage.dialog().noButton();
if (noButton != null) {
clickButton(connection, storage.dialog().afterAction(), noButton);
}
}
if (slot == storage.actionIndex()) {
final Button actionButton = storage.dialog().actionButton();
if (actionButton != null) {
clickButton(connection, storage.dialog().afterAction(), actionButton);
}
}
// Resync inventory view if the actions above didn't close the dialog.
if (connection.has(ChestDialogStorage.class) && storage.phase() == ChestDialogStorage.Phase.DIALOG_VIEW) {
updateDialog(connection, storage.dialog());
}
return true;
}
public void updateDialog(final UserConnection connection, final Dialog dialog) {
final ChestDialogStorage storage = connection.get(ChestDialogStorage.class);
final PacketWrapper containerSetContent = PacketWrapper.create(ClientboundPackets1_21_5.CONTAINER_SET_CONTENT, connection);
containerSetContent.write(Types.VAR_INT, storage.containerId());
containerSetContent.write(Types.VAR_INT, 0); // Revision
containerSetContent.write(VersionedTypes.V1_21_5.itemArray, getItems(connection, storage, dialog));
containerSetContent.write(VersionedTypes.V1_21_5.item, StructuredItem.empty());
containerSetContent.send(Protocol1_21_6To1_21_5.class);
}
protected Item createPageNavigationItem() {
return createItem(
"minecraft:arrow",
text("§9§lPage navigation"),
"§9Left click: §6Go to next page",
"§9Right click: §6Go to previous page"
);
}
protected Item createActionButtonItem(final UserConnection connection, final Button button) {
final Tag label = handleTag(connection, button.label());
if (button.tooltip() == null) {
return createItem("minecraft:oak_button", label);
} else {
return createItem("minecraft:oak_button", label, handleTag(connection, button.tooltip()));
}
}
protected Item createCloseButtonItem(final Tag label) {
return createItem("minecraft:oak_button", label);
}
protected Item getItemWidget(final UserConnection connection, final ItemWidget itemWidget) {
final String identifier = itemWidget.item().getString("id");
final int count = itemWidget.item().getInt("count", 1);
final Tag label = text(Key.stripMinecraftNamespace(identifier));
final Item item = createItem(identifier, label);
item.setAmount(count);
if (itemWidget.description() != null) {
item.dataContainer().set(StructuredDataKey.LORE, new Tag[]{
handleTag(connection, fixStyle(itemWidget.description().label()))
});
}
if (!itemWidget.showTooltip()) {
item.dataContainer().set(StructuredDataKey.TOOLTIP_DISPLAY, new TooltipDisplay(true, IntSortedSets.EMPTY_SET));
}
// If we were to parse item components from NBT for chat items they would be parsed here and stored into the data container.
// In VV, chat items are rewritten manually at the time being and therefore no conversion code exists.
return item;
}
protected Item getMultiTextWidget(final UserConnection connection, final MultiTextWidget multiTextWidget) {
final Tag name = handleTag(connection, multiTextWidget.labels()[0]);
final int length = multiTextWidget.labels().length;
if (length == 1) {
return createItem("minecraft:paper", name);
}
final Tag[] lore = new Tag[length - 1];
for (int i = 1; i < length; i++) {
lore[i - 1] = handleTag(connection, fixStyle(multiTextWidget.labels()[i]));
}
return createItem("minecraft:paper", name, lore);
}
protected Item getBooleanInput(final UserConnection connection, final BooleanInput booleanInput) {
final String item = booleanInput.value() ? "minecraft:lime_dye" : "minecraft:gray_dye";
final Tag[] label = ChatUtil.split(booleanInput.label(), "\n");
// The only one that supports newlines in the label
if (label.length == 1) {
return createItem(
item,
handleTag(connection, booleanInput.label()),
text("§9Left click: §6Toggle value")
);
} else {
final Tag[] lore = new Tag[label.length];
for (int i = 1; i < label.length; i++) {
lore[i - 1] = handleTag(connection, fixStyle(label[i]));
}
lore[lore.length - 1] = text("§9Left click: §6Toggle value");
return createItem(
item,
handleTag(connection, label[0]),
lore
);
}
}
protected void clickBooleanInput(final BooleanInput booleanInput) {
booleanInput.setValue(!booleanInput.value());
}
protected Item getNumberRangeInput(final UserConnection connection, final NumberRangeInput numberRangeInput) {
final Tag label = handleTag(connection, numberRangeInput.displayName());
return createItem(
"minecraft:clock",
label,
"§9Left click: §6Increase value by " + numberRangeInput.step(),
"§9Right click: §6Decrease value by " + numberRangeInput.step(),
"§7(Value between §a" + numberRangeInput.start() + " §7and §a" + numberRangeInput.end() + "§7)"
);
}
protected void clickNumberRangeInput(final NumberRangeInput numberRangeInput, final int mouse) {
float value = numberRangeInput.value();
if (mouse == 0) { // Left click
value += numberRangeInput.step();
} else if (mouse == 1) { // Right click
value -= numberRangeInput.step();
}
numberRangeInput.setClampedValue(value);
}
protected Item getTextInput(final UserConnection connection, final TextInput textInput) {
final Tag currentValue = text("§7Current value: §a" + textInput.value());
if (textInput.label() == null) {
return createItem("minecraft:writable_book", currentValue);
} else {
final Tag label = handleTag(connection, textInput.label());
return createItem("minecraft:writable_book", label, currentValue, text("§9Left click: §6Edit text"));
}
}
protected void clickTextInput(final UserConnection connection, final TextInput textInput) {
final ChestDialogStorage storage = connection.get(ChestDialogStorage.class);
openAnvilView(connection, storage, text("§7Edit text"), textInput.value(), textInput);
}
protected Item getSingleOptionInput(final UserConnection connection, final SingleOptionInput singleOptionInput) {
final Tag displayName = singleOptionInput.options()[singleOptionInput.value()].computeDisplay();
final Tag label;
if (singleOptionInput.label() != null) {
label = translate("options.generic_value", singleOptionInput.label(), displayName);
} else {
label = displayName;
}
return createItem(
"minecraft:bookshelf",
handleTag(connection, label),
"§9Left click: §6Go to next option",
"§9Right click: §6Go to previous option"
);
}
protected void clickSingleOptionInput(final SingleOptionInput singleOptionInput) {
singleOptionInput.setClampedValue(singleOptionInput.value() + 1);
}
protected Item getButton(final UserConnection connection, final Button button) {
return createItem("minecraft:oak_button", handleTag(connection, button.label()));
}
public void clickButton(final UserConnection connection, final Dialog.AfterAction afterAction, @Nullable final Button button) {
final ChestDialogStorage storage = connection.get(ChestDialogStorage.class);
switch (afterAction) {
case CLOSE -> closeDialog(connection);
case WAIT_FOR_RESPONSE -> storage.setPhase(null, ChestDialogStorage.Phase.WAITING_FOR_RESPONSE);
}
if (button == null || button.clickEvent() == null) {
return;
}
final CompoundTag clickEvent = button.clickEvent();
final String action = Key.stripMinecraftNamespace(clickEvent.getString("action"));
switch (action) {
case "open_url" -> {
// We can't open a URL for the client, so roughly emulate by opening an Anvil containing the URL.
final String url = clickEvent.getString("url");
openAnvilView(connection, storage, text("Open URL"), url, null);
}
case "run_command" -> {
// The vanilla client validates for signed argument types and has more requirements for this click event,
// but we can't do this here and therefore just always send the packet assuming this is correct...
final PacketWrapper chatCommand = PacketWrapper.create(ServerboundPackets1_21_6.CHAT_COMMAND, connection);
String command = clickEvent.getString("command");
if (command.startsWith("/")) {
command = command.substring(1);
}
chatCommand.write(Types.STRING, command);
chatCommand.sendToServer(Protocol1_21_6To1_21_5.class);
}
case "copy_to_clipboard" -> {
// Same as above, we can't access the clipboard
final String value = clickEvent.getString("value");
openAnvilView(connection, storage, text("Copy to clipboard"), value, null);
}
}
ClickEvents.handleClickEvent(connection, clickEvent); // Handle show_dialog and custom
}
protected Item createTextInputItem(final String value) {
return createItem("minecraft:paper", text(value), "§9Left click/close: §6Set text");
}
protected Item createTextCopyItem(final String value) {
return createItem("minecraft:paper", text(value), "§9Left click: §6Close");
}
private void openAnvilView(
final UserConnection connection,
final ChestDialogStorage storage,
final Tag title,
final String value,
final TextInput textInput
) {
storage.setPhase(connection, ChestDialogStorage.Phase.ANVIL_VIEW);
final PacketWrapper openScreen = PacketWrapper.create(ClientboundPackets1_21_5.OPEN_SCREEN, connection);
openScreen.write(Types.VAR_INT, storage.containerId());
openScreen.write(Types.VAR_INT, 8); // Container type id
openScreen.write(Types.TAG, title);
openScreen.send(Protocol1_21_6To1_21_5.class);
final Item[] items = new Item[1];
items[0] = textInput != null ? createTextInputItem(value) : createTextCopyItem(value);
storage.setCurrentTextInput(textInput);
final PacketWrapper containerSetContent = PacketWrapper.create(ClientboundPackets1_21_5.CONTAINER_SET_CONTENT, connection);
containerSetContent.write(Types.VAR_INT, storage.containerId());
containerSetContent.write(Types.VAR_INT, 0); // Revision
containerSetContent.write(VersionedTypes.V1_21_5.itemArray, items);
containerSetContent.write(VersionedTypes.V1_21_5.item, StructuredItem.empty());
containerSetContent.send(Protocol1_21_6To1_21_5.class);
}
public void updateAnvilText(final UserConnection connection, final String value) {
if (value.isEmpty()) {
return;
}
final ChestDialogStorage storage = connection.get(ChestDialogStorage.class);
if (storage.currentTextInput() != null) {
storage.currentTextInput().setClampedValue(value);
}
}
protected Item getDialog(final UserConnection connection, final Dialog dialog) {
final Tag title = dialog.externalTitle() != null ? dialog.externalTitle() : dialog.title();
return createItem("minecraft:command_block", handleTag(connection, title));
}
protected void clickDialogButton(final UserConnection connection, final Dialog dialog) {
closeDialog(connection);
openDialog(connection, dialog);
}
protected Item getItem(final UserConnection connection, final Widget widget) {
if (widget instanceof final ItemWidget itemWidget) {
return getItemWidget(connection, itemWidget);
} else if (widget instanceof final MultiTextWidget multiTextWidget) {
return getMultiTextWidget(connection, multiTextWidget);
} else if (widget instanceof final BooleanInput booleanInput) {
return getBooleanInput(connection, booleanInput);
} else if (widget instanceof final NumberRangeInput numberRangeInput) {
return getNumberRangeInput(connection, numberRangeInput);
} else if (widget instanceof TextInput textInput) {
return getTextInput(connection, textInput);
} else if (widget instanceof SingleOptionInput singleOptionInput) {
return getSingleOptionInput(connection, singleOptionInput);
} else if (widget instanceof Button button) {
return getButton(connection, button);
} else if (widget instanceof Dialog dialog) {
return getDialog(connection, dialog);
}
throw new IllegalArgumentException("Unknown widget type: " + widget.getClass().getName());
}
protected Item[] getItems(final UserConnection connection, final ChestDialogStorage storage, final Dialog dialog) {
final Item[] items = StructuredItem.emptyArray(INVENTORY_SIZE);
int confirmationYesIndex = -1;
int confirmationNoIndex = -1;
int actionIndex = -1;
if (storage.phase() == ChestDialogStorage.Phase.WAITING_FOR_RESPONSE) {
actionIndex = 13;
items[actionIndex] = createCloseButtonItem(storage.closeButtonLabel());
storage.setItems(items, confirmationYesIndex, confirmationNoIndex, actionIndex);
return items;
}
final List<Widget> widgets = dialog.widgets();
if (widgets.size() > INVENTORY_LAST_ROW) {
final int begin = storage.page * INVENTORY_LAST_ROW;
final int end = Math.min((storage.page + 1) * INVENTORY_LAST_ROW, widgets.size());
for (int i = 0; i < end - begin; i++) {
items[i] = getItem(connection, widgets.get(begin + i));
}
items[INVENTORY_SIZE - 1] = createPageNavigationItem();
} else {
for (int i = 0; i < widgets.size(); i++) {
items[i] = getItem(connection, widgets.get(i));
}
}
// And some special cases.
if (dialog.yesButton() != null && dialog.noButton() != null) {
confirmationYesIndex = widgets.isEmpty() ? 11 : INVENTORY_SIZE - 7;
confirmationNoIndex = widgets.isEmpty() ? 15 : INVENTORY_SIZE - 3;
items[confirmationYesIndex] = createActionButtonItem(connection, dialog.yesButton());
items[confirmationNoIndex] = createActionButtonItem(connection, dialog.noButton());
}
if (dialog.actionButton() != null) {
actionIndex = widgets.isEmpty() ? 13 : INVENTORY_SIZE - 9;
items[actionIndex] = createActionButtonItem(connection, dialog.actionButton());
}
storage.setItems(items, confirmationYesIndex, confirmationNoIndex, actionIndex);
return items;
}
/**
* Handles the 1.21.6 tag inside the Dialog structure and rewrites it to the 1.21.5 format. This is necessary
* for replacing translations used by Dialogs which only exist in 1.21.6+. Call this function for every text component
* you display from the server.
*
* @param connection the user connection
* @param tag the text component as a tag, or null if no tag is present
* @return the rewritten tag, or null if the input tag was null
*/
private @Nullable Tag handleTag(final UserConnection connection, final @Nullable Tag tag) {
if (tag == null) {
return null;
}
protocol.getComponentRewriter().processTag(connection, tag);
return tag;
}
/**
* This doesn't actually exist in Minecraft but is created if multiple {@link TextWidget} follow one another in order
* to improve readability in chest inventories.
*/
public record MultiTextWidget(Tag[] labels) implements Widget {
}
// -------------------------------------------------------------------------------------
protected Item createItem(final String identifier, final Tag name) {
return createItem(identifier, name, new String[0]);
}
protected Item createItem(final String identifier, final Tag name, final Tag... description) {
final int id = protocol.getMappingData().getFullItemMappings().mappedId(identifier);
final StructuredDataContainer data = new StructuredDataContainer();
data.setIdLookup(protocol, true);
data.set(StructuredDataKey.ITEM_NAME, name);
if (description != null) {
data.set(StructuredDataKey.LORE, description);
}
return new StructuredItem(id, 1, data);
}
protected Item createItem(final String identifier, final Tag name, final String... description) {
final int id = protocol.getMappingData().getFullItemMappings().mappedId(identifier);
final StructuredDataContainer data = new StructuredDataContainer();
data.setIdLookup(protocol, true);
data.set(StructuredDataKey.ITEM_NAME, name);
if (description.length > 0) {
final List<Tag> lore = new ArrayList<>();
for (final String s : description) {
lore.add(text(s));
}
data.set(StructuredDataKey.LORE, lore.toArray(new Tag[0]));
}
return new StructuredItem(id, 1, data);
}
}
@@ -0,0 +1,38 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.provider;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.data.Dialog;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.platform.providers.Provider;
/**
* Interface for providing dialog view functionality to this protocol. Requires a storage
* to save per-user data while being able to have open and close logic static.
* <p>
* See {@link Dialog} for the structure of a dialog.
* <p>
* See {@link ChestDialogViewProvider} for the protocol level emulation using a chest.
*/
public interface DialogViewProvider extends Provider {
void openDialog(final UserConnection connection, final Dialog dialog);
void closeDialog(final UserConnection connection);
}
@@ -142,10 +142,10 @@ public final class BlockItemPacketRewriter1_21_6 extends BackwardsStructuredItem
final CompoundTag equippableTag = backupTag.getCompoundTag("equippable");
if (equippableTag != null) {
container.replace(StructuredDataKey.EQUIPPABLE1_21_5, StructuredDataKey.EQUIPPABLE1_21_6, equippable -> new Equippable(
equippable.equipmentSlot(), equippable.soundEvent(), equippable.model(), equippable.cameraOverlay(), equippable.allowedEntities(),
equippable.dispensable(), equippable.swappable(), equippable.damageOnHurt(), equippable.equipOnInteract(),
equippableTag.getBoolean("can_be_sheared"),
restoreSoundEventHolder(equippableTag)
equippable.equipmentSlot(), equippable.soundEvent(), equippable.model(), equippable.cameraOverlay(), equippable.allowedEntities(),
equippable.dispensable(), equippable.swappable(), equippable.damageOnHurt(), equippable.equipOnInteract(),
equippableTag.getBoolean("can_be_sheared"),
restoreSoundEventHolder(equippableTag)
));
}
}
@@ -20,6 +20,8 @@ package com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.rewriter;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.rewriters.text.NBTComponentRewriter;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.storage.ChestDialogStorage;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.storage.ClickEvents;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundPacket1_21_6;
@@ -39,8 +41,32 @@ public final class ComponentRewriter1_21_6 extends NBTComponentRewriter<Clientbo
}
final String action = clickEvent.getString("action");
if ("custom".equals(action)) {
tag.remove("click_event");
final ChestDialogStorage chestDialogStorage = connection.get(ChestDialogStorage.class);
if (chestDialogStorage != null) {
// Short way out - remove when in dialog, buttons are handled separately
if ("show_dialog".equals(action) || "custom".equals(action)) {
tag.remove("click_event");
return;
}
}
// Make them run a command generated by us executing the actual logic
if ("show_dialog".equals(action)) {
final ClickEvents clickEvents = connection.get(ClickEvents.class);
final String command = clickEvents.storeClickEvent(clickEvent.copy());
clickEvent.putString("action", "run_command");
clickEvent.putString("command", command);
clickEvent.remove("dialog");
} else if ("custom".equals(action)) {
final ClickEvents clickEvents = connection.get(ClickEvents.class);
final String command = clickEvents.storeClickEvent(clickEvent.copy());
clickEvent.putString("action", "run_command");
clickEvent.putString("command", command);
clickEvent.remove("id");
clickEvent.remove("payload");
}
}
}
@@ -17,19 +17,29 @@
*/
package com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.rewriter;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viabackwards.api.rewriters.BackwardsRegistryRewriter;
import com.viaversion.viabackwards.api.rewriters.EntityRewriter;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.Protocol1_21_6To1_21_5;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.storage.RegistryAndTags;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.RegistryEntry;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_21_6;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_21_5;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.version.VersionedTypes;
import com.viaversion.viaversion.libs.fastutil.objects.Object2ObjectArrayMap;
import com.viaversion.viaversion.libs.fastutil.objects.Object2ObjectMap;
import com.viaversion.viaversion.protocols.v1_21_4to1_21_5.packet.ClientboundPackets1_21_5;
import com.viaversion.viaversion.protocols.v1_21_4to1_21_5.packet.ServerboundPackets1_21_5;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundConfigurationPackets1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundPacket1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundPackets1_21_6;
import com.viaversion.viaversion.rewriter.RegistryDataRewriter;
import com.viaversion.viaversion.util.Key;
import com.viaversion.viaversion.util.KeyMappings;
public final class EntityPacketRewriter1_21_6 extends EntityRewriter<ClientboundPacket1_21_6, Protocol1_21_6To1_21_5> {
@@ -39,7 +49,6 @@ public final class EntityPacketRewriter1_21_6 extends EntityRewriter<Clientbound
@Override
public void registerPackets() {
registerTrackerWithData1_19(ClientboundPackets1_21_6.ADD_ENTITY, EntityTypes1_21_6.FALLING_BLOCK);
registerSetEntityData(ClientboundPackets1_21_6.SET_ENTITY_DATA);
registerRemoveEntities(ClientboundPackets1_21_6.REMOVE_ENTITIES);
registerPlayerAbilities(ClientboundPackets1_21_6.PLAYER_ABILITIES);
@@ -47,8 +56,59 @@ public final class EntityPacketRewriter1_21_6 extends EntityRewriter<Clientbound
registerLogin1_20_5(ClientboundPackets1_21_6.LOGIN);
registerRespawn1_20_5(ClientboundPackets1_21_6.RESPAWN);
final RegistryDataRewriter registryDataRewriter = new BackwardsRegistryRewriter(protocol);
registryDataRewriter.remove("dialog");
protocol.appendClientbound(ClientboundPackets1_21_6.ADD_ENTITY, wrapper -> {
final int entityId = wrapper.passthrough(Types.VAR_INT);
wrapper.passthrough(Types.UUID); // Entity UUID
final int entityType = wrapper.passthrough(Types.VAR_INT);
wrapper.passthrough(Types.DOUBLE); // X
wrapper.passthrough(Types.DOUBLE); // Y
wrapper.passthrough(Types.DOUBLE); // Z
wrapper.passthrough(Types.BYTE); // Pitch
wrapper.passthrough(Types.BYTE); // Yaw
wrapper.passthrough(Types.BYTE); // Head yaw
wrapper.passthrough(Types.VAR_INT); // Data
final short velocityX = wrapper.passthrough(Types.SHORT);
final short velocityY = wrapper.passthrough(Types.SHORT);
final short velocityZ = wrapper.passthrough(Types.SHORT);
getSpawnTrackerWithDataHandler1_19(EntityTypes1_21_6.FALLING_BLOCK).handle(wrapper);
if (velocityX != 0 || velocityY != 0 || velocityZ != 0) {
if (!typeFromId(entityType).isOrHasParent(EntityTypes1_21_6.LIVING_ENTITY)) {
// Send movement separately
final PacketWrapper motionPacket = wrapper.create(ClientboundPackets1_21_5.SET_ENTITY_MOTION);
motionPacket.write(Types.VAR_INT, entityId);
motionPacket.write(Types.SHORT, velocityX);
motionPacket.write(Types.SHORT, velocityY);
motionPacket.write(Types.SHORT, velocityZ);
wrapper.send(Protocol1_21_6To1_21_5.class);
motionPacket.send(Protocol1_21_6To1_21_5.class);
wrapper.cancel();
}
}
});
final RegistryDataRewriter registryDataRewriter = new BackwardsRegistryRewriter(protocol) {
@Override
public RegistryEntry[] handle(final UserConnection connection, final String key, final RegistryEntry[] entries) {
if (Key.stripMinecraftNamespace(key).equals("dialog")) {
final String[] keys = new String[entries.length];
for (int i = 0; i < entries.length; i++) {
keys[i] = Key.stripMinecraftNamespace(entries[i].key());
}
final Object2ObjectMap<String, CompoundTag> dialogs = new Object2ObjectArrayMap<>();
for (final RegistryEntry entry : entries) {
if (entry.tag() instanceof final CompoundTag tag) {
dialogs.put(Key.stripMinecraftNamespace(entry.key()), tag);
}
}
final RegistryAndTags registryAndTags = connection.get(RegistryAndTags.class);
registryAndTags.storeRegistry(new KeyMappings(keys), dialogs);
}
return super.handle(connection, key, entries);
}
};
registryDataRewriter.remove("dialog"); // Tracked and now removed
protocol.registerClientbound(ClientboundConfigurationPackets1_21_6.REGISTRY_DATA, registryDataRewriter::handle);
protocol.registerServerbound(ServerboundPackets1_21_5.PLAYER_COMMAND, wrapper -> {
@@ -0,0 +1,193 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.storage;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.Protocol1_21_6To1_21_5;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.data.Dialog;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.data.input.TextInput;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.provider.ChestDialogViewProvider;
import com.viaversion.viaversion.api.connection.StorableObject;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_21_4to1_21_5.packet.ClientboundPackets1_21_5;
import java.util.concurrent.atomic.AtomicInteger;
import org.checkerframework.checker.nullness.qual.Nullable;
import static com.viaversion.viabackwards.utils.ChatUtil.text;
import static com.viaversion.viabackwards.utils.ChatUtil.translate;
/**
* Per-user storage for {@link ChestDialogViewProvider}
*/
public final class ChestDialogStorage implements StorableObject {
private static final byte MIN_FAKE_ID = Byte.MAX_VALUE / 2 + 1;
private static final byte MAX_FAKE_ID = Byte.MAX_VALUE - 1;
private static final AtomicInteger FAKE_ID_COUNTER = new AtomicInteger(MIN_FAKE_ID);
private static final Tag[] RESPONSE_BUTTON_LABELS = new Tag[]{
text(""),
translate("gui.waitingForResponse.button.inactive", 4),
translate("gui.waitingForResponse.button.inactive", 3),
translate("gui.waitingForResponse.button.inactive", 2),
translate("gui.waitingForResponse.button.inactive", 1),
translate("gui.back")
};
private final ChestDialogViewProvider provider;
private final Dialog dialog;
private int containerId;
private Dialog previousDialog;
public int page;
private Item[] items;
private int confirmationYesIndex = -1;
private int confirmationNoIndex = -1;
private int actionIndex = -1;
private @Nullable Phase phase;
private int ticksWaitingForResponse = 0;
private boolean closeButtonEnabled;
private Tag closeButtonLabel;
private TextInput currentTextInput;
private boolean allowClosing;
public ChestDialogStorage(final ChestDialogViewProvider provider, final Dialog dialog) {
this.provider = provider;
this.dialog = dialog;
}
public void tick(final UserConnection connection) {
if (phase != Phase.WAITING_FOR_RESPONSE) {
return;
}
final int index = ticksWaitingForResponse++ / 20;
if (index > RESPONSE_BUTTON_LABELS.length - 1) {
return;
}
closeButtonEnabled = index >= 1;
closeButtonLabel = RESPONSE_BUTTON_LABELS[index];
provider.updateDialog(connection, dialog);
}
public Dialog dialog() {
return dialog;
}
public @Nullable Dialog previousDialog() {
return previousDialog;
}
public void setPreviousDialog(final Dialog previousDialog) {
this.previousDialog = previousDialog;
}
public int containerId() {
return containerId;
}
public Item[] items() {
return items;
}
public void setItems(final Item[] items, final int confirmationYesIndex, final int confirmationNoIndex, final int actionIndex) {
this.items = items;
this.confirmationYesIndex = confirmationYesIndex;
this.confirmationNoIndex = confirmationNoIndex;
this.actionIndex = actionIndex;
}
public int confirmationYesIndex() {
return confirmationYesIndex;
}
public int confirmationNoIndex() {
return confirmationNoIndex;
}
public int actionIndex() {
return actionIndex;
}
public @Nullable Phase phase() {
return phase;
}
public boolean closeButtonEnabled() {
return closeButtonEnabled;
}
public Tag closeButtonLabel() {
return closeButtonLabel;
}
public TextInput currentTextInput() {
return currentTextInput;
}
public boolean allowClosing() {
return allowClosing;
}
public void setPhase(final UserConnection connection, final @Nullable Phase phase) {
if (phase == Phase.DIALOG_VIEW || phase == Phase.ANVIL_VIEW) {
if (this.phase != null) {
final PacketWrapper containerClose = PacketWrapper.create(ClientboundPackets1_21_5.CONTAINER_CLOSE, connection);
containerClose.write(Types.VAR_INT, containerId);
containerClose.send(Protocol1_21_6To1_21_5.class);
}
currentTextInput = null;
final int id = FAKE_ID_COUNTER.getAndIncrement();
if (id > MAX_FAKE_ID) {
FAKE_ID_COUNTER.set(MIN_FAKE_ID);
containerId = MIN_FAKE_ID;
} else {
containerId = (byte) id;
}
}
this.phase = phase;
}
public void setCurrentTextInput(final TextInput currentTextInput) {
this.currentTextInput = currentTextInput;
}
public void setAllowClosing(final boolean allowClosing) {
this.allowClosing = allowClosing;
}
public enum Phase {
DIALOG_VIEW,
ANVIL_VIEW,
WAITING_FOR_RESPONSE
}
}
@@ -0,0 +1,87 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.storage;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.Protocol1_21_6To1_21_5;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.data.Dialog;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.provider.DialogViewProvider;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.StorableObject;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.libs.fastutil.objects.Object2ObjectArrayMap;
import com.viaversion.viaversion.libs.fastutil.objects.Object2ObjectMap;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ServerboundPackets1_21_6;
import com.viaversion.viaversion.util.Key;
import java.util.UUID;
public final class ClickEvents implements StorableObject {
private final Object2ObjectMap<String, CompoundTag> clickEvents = new Object2ObjectArrayMap<>();
public String storeClickEvent(final CompoundTag clickEvent) {
final String id = "vv_" + UUID.randomUUID();
if (clickEvents.containsKey(id)) {
return storeClickEvent(clickEvent); // Ensure unique ID
}
clickEvents.put(id, clickEvent);
return id;
}
public boolean handleChatCommand(final UserConnection connection, final String command) {
final CompoundTag clickEvent = clickEvents.get(command);
if (clickEvent != null) {
handleClickEvent(connection, clickEvent);
return true;
} else {
return false;
}
}
public static void handleClickEvent(final UserConnection connection, final CompoundTag clickEvent) {
final String action = Key.stripMinecraftNamespace(clickEvent.getString("action"));
if ("show_dialog".equals(action)) {
final RegistryAndTags registryAndTags = connection.get(RegistryAndTags.class);
final ServerLinks serverLinks = connection.get(ServerLinks.class);
CompoundTag dialogTag = clickEvent.getCompoundTag("dialog");
if (dialogTag == null) {
final StringTag dialogReferenceTag = clickEvent.getStringTag("dialog");
if (dialogReferenceTag != null) { // No tags here
dialogTag = registryAndTags.fromRegistry(Key.stripMinecraftNamespace(dialogReferenceTag.getValue()));
}
}
final DialogViewProvider provider = Via.getManager().getProviders().get(DialogViewProvider.class);
provider.openDialog(connection, new Dialog(registryAndTags, serverLinks, dialogTag));
} else if ("custom".equals(action)) {
final String id = clickEvent.getString("id");
final CompoundTag payload = clickEvent.getCompoundTag("payload");
final PacketWrapper customClickAction = PacketWrapper.create(ServerboundPackets1_21_6.CUSTOM_CLICK_ACTION, connection);
customClickAction.write(Types.STRING, id);
customClickAction.write(Types.CUSTOM_CLICK_ACTION_TAG, payload);
customClickAction.sendToServer(Protocol1_21_6To1_21_5.class);
}
}
}
@@ -0,0 +1,74 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.storage;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viaversion.api.connection.StorableObject;
import com.viaversion.viaversion.libs.fastutil.objects.Object2ObjectArrayMap;
import com.viaversion.viaversion.libs.fastutil.objects.Object2ObjectMap;
import com.viaversion.viaversion.util.Key;
import com.viaversion.viaversion.util.KeyMappings;
public final class RegistryAndTags implements StorableObject {
private KeyMappings dialogMappings;
private Object2ObjectMap<String, CompoundTag> dialogs;
private Object2ObjectMap<String, int[]> dialogTags;
public void storeRegistry(final KeyMappings dialogMappings, final Object2ObjectMap<String, CompoundTag> dialogs) {
this.dialogMappings = dialogMappings;
this.dialogs = dialogs;
}
public CompoundTag fromRegistry(final int id) {
return dialogs.get(dialogMappings.idToKey(id));
}
public CompoundTag fromRegistry(final String key) {
return dialogs.get(Key.stripMinecraftNamespace(key));
}
public boolean tagsSent() {
return dialogTags != null && !dialogTags.isEmpty();
}
public void storeTags(final String key, final int[] ids) {
if (dialogTags == null) {
dialogTags = new Object2ObjectArrayMap<>();
}
dialogTags.put(Key.stripMinecraftNamespace(key), ids);
}
public int[] fromKey(final String key) {
return dialogTags.get(Key.stripMinecraftNamespace(key));
}
public CompoundTag[] fromRegistryKey(final String key) {
final int[] ids = fromKey(key);
if (ids == null) {
return null;
}
final CompoundTag[] tags = new CompoundTag[ids.length];
for (int i = 0; i < ids.length; i++) {
tags[i] = fromRegistry(ids[i]);
}
return tags;
}
}
@@ -0,0 +1,65 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.storage;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.api.connection.StorableObject;
import com.viaversion.viaversion.libs.fastutil.objects.Object2ObjectArrayMap;
import com.viaversion.viaversion.libs.fastutil.objects.Object2ObjectMap;
import static com.viaversion.viabackwards.utils.ChatUtil.translate;
public final class ServerLinks implements StorableObject {
private static final CompoundTag REPORT_BUG = translate("known_server_link.report_bug");
private static final CompoundTag COMMUNITY_GUIDELINES = translate("known_server_link.community_guidelines");
private static final CompoundTag SUPPORT = translate("known_server_link.support");
private static final CompoundTag STATUS = translate("known_server_link.status");
private static final CompoundTag FEEDBACK = translate("known_server_link.feedback");
private static final CompoundTag COMMUNITY = translate("known_server_link.community");
private static final CompoundTag WEBSITE = translate("known_server_link.website");
private static final CompoundTag FORUMS = translate("known_server_link.forums");
private static final CompoundTag NEWS = translate("known_server_link.news");
private static final CompoundTag ANNOUNCEMENTS = translate("known_server_link.announcements");
private final Object2ObjectMap<Tag, String> links = new Object2ObjectArrayMap<>();
public void storeLink(final Tag tag, final String uri) {
links.put(tag, uri);
}
public void storeLink(final int id, final String uri) {
switch (id) {
case 1 -> storeLink(COMMUNITY_GUIDELINES, uri);
case 2 -> storeLink(SUPPORT, uri);
case 3 -> storeLink(STATUS, uri);
case 4 -> storeLink(FEEDBACK, uri);
case 5 -> storeLink(COMMUNITY, uri);
case 6 -> storeLink(WEBSITE, uri);
case 7 -> storeLink(FORUMS, uri);
case 8 -> storeLink(NEWS, uri);
case 9 -> storeLink(ANNOUNCEMENTS, uri);
default -> storeLink(REPORT_BUG, uri);
}
}
public Object2ObjectMap<Tag, String> links() {
return links;
}
}
@@ -0,0 +1,38 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.task;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.Protocol1_21_6To1_21_5;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.storage.ChestDialogStorage;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.protocol.ProtocolRunnable;
public final class ChestDialogViewTask extends ProtocolRunnable {
public ChestDialogViewTask() {
super(Protocol1_21_6To1_21_5.class);
}
@Override
public void run(final UserConnection connection) {
final ChestDialogStorage storage = connection.get(ChestDialogStorage.class);
if (storage != null) {
storage.tick(connection);
}
}
}
@@ -0,0 +1,150 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viabackwards.protocol.v1_21_7to1_21_6;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.data.BackwardsMappingData;
import com.viaversion.viabackwards.api.rewriters.SoundRewriter;
import com.viaversion.viabackwards.api.rewriters.text.NBTComponentRewriter;
import com.viaversion.viabackwards.api.rewriters.text.TranslatableRewriter;
import com.viaversion.viabackwards.protocol.v1_21_7to1_21_6.rewriter.BlockItemPacketRewriter1_21_7;
import com.viaversion.viabackwards.protocol.v1_21_7to1_21_6.rewriter.EntityPacketRewriter1_21_7;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.data.version.StructuredDataKeys1_21_5;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_21_6;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_21_5;
import com.viaversion.viaversion.api.protocol.packet.provider.PacketTypesProvider;
import com.viaversion.viaversion.api.protocol.packet.provider.SimplePacketTypesProvider;
import com.viaversion.viaversion.api.type.types.version.Types1_20_5;
import com.viaversion.viaversion.api.type.types.version.VersionedTypes;
import com.viaversion.viaversion.data.entity.EntityTrackerBase;
import com.viaversion.viaversion.data.item.ItemHasherBase;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundConfigurationPackets1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundPacket1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundPackets1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ServerboundConfigurationPackets1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ServerboundPacket1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ServerboundPackets1_21_6;
import com.viaversion.viaversion.protocols.v1_21_6to1_21_7.Protocol1_21_6To1_21_7;
import com.viaversion.viaversion.rewriter.ParticleRewriter;
import com.viaversion.viaversion.rewriter.StatisticsRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
import com.viaversion.viaversion.util.SerializerVersion;
import static com.viaversion.viaversion.util.ProtocolUtil.packetTypeMap;
public final class Protocol1_21_7To1_21_6 extends BackwardsProtocol<ClientboundPacket1_21_6, ClientboundPacket1_21_6, ServerboundPacket1_21_6, ServerboundPacket1_21_6> {
public static final BackwardsMappingData MAPPINGS = new BackwardsMappingData("1.21.7", "1.21.6", Protocol1_21_6To1_21_7.class);
private final EntityPacketRewriter1_21_7 entityRewriter = new EntityPacketRewriter1_21_7(this);
private final BlockItemPacketRewriter1_21_7 itemRewriter = new BlockItemPacketRewriter1_21_7(this);
private final ParticleRewriter<ClientboundPacket1_21_6> particleRewriter = new ParticleRewriter<>(this);
private final NBTComponentRewriter<ClientboundPacket1_21_6> translatableRewriter = new NBTComponentRewriter<>(this);
private final TagRewriter<ClientboundPacket1_21_6> tagRewriter = new TagRewriter<>(this);
public Protocol1_21_7To1_21_6() {
super(ClientboundPacket1_21_6.class, ClientboundPacket1_21_6.class, ServerboundPacket1_21_6.class, ServerboundPacket1_21_6.class);
}
@Override
protected void registerPackets() {
super.registerPackets();
tagRewriter.registerGeneric(ClientboundPackets1_21_6.UPDATE_TAGS);
tagRewriter.registerGeneric(ClientboundConfigurationPackets1_21_6.UPDATE_TAGS);
final SoundRewriter<ClientboundPacket1_21_6> soundRewriter = new SoundRewriter<>(this);
soundRewriter.registerSound1_19_3(ClientboundPackets1_21_6.SOUND);
soundRewriter.registerSound1_19_3(ClientboundPackets1_21_6.SOUND_ENTITY);
soundRewriter.registerStopSound(ClientboundPackets1_21_6.STOP_SOUND);
new StatisticsRewriter<>(this).register(ClientboundPackets1_21_6.AWARD_STATS);
translatableRewriter.registerComponentPacket(ClientboundPackets1_21_6.SET_ACTION_BAR_TEXT);
translatableRewriter.registerComponentPacket(ClientboundPackets1_21_6.SET_TITLE_TEXT);
translatableRewriter.registerComponentPacket(ClientboundPackets1_21_6.SET_SUBTITLE_TEXT);
translatableRewriter.registerBossEvent(ClientboundPackets1_21_6.BOSS_EVENT);
translatableRewriter.registerComponentPacket(ClientboundPackets1_21_6.DISCONNECT);
translatableRewriter.registerTabList(ClientboundPackets1_21_6.TAB_LIST);
translatableRewriter.registerPlayerCombatKill1_20(ClientboundPackets1_21_6.PLAYER_COMBAT_KILL);
translatableRewriter.registerPlayerInfoUpdate1_21_4(ClientboundPackets1_21_6.PLAYER_INFO_UPDATE);
translatableRewriter.registerComponentPacket(ClientboundPackets1_21_6.SYSTEM_CHAT);
translatableRewriter.registerDisguisedChat(ClientboundPackets1_21_6.DISGUISED_CHAT);
translatableRewriter.registerPlayerChat1_21_5(ClientboundPackets1_21_6.PLAYER_CHAT);
translatableRewriter.registerPing();
particleRewriter.registerLevelParticles1_21_4(ClientboundPackets1_21_6.LEVEL_PARTICLES);
particleRewriter.registerExplode1_21_2(ClientboundPackets1_21_6.EXPLODE);
}
@Override
public void init(final UserConnection connection) {
addEntityTracker(connection, new EntityTrackerBase(connection, EntityTypes1_21_6.PLAYER));
addItemHasher(connection, new ItemHasherBase(this, connection, SerializerVersion.V1_21_6, SerializerVersion.V1_21_6));
}
@Override
public BackwardsMappingData getMappingData() {
return MAPPINGS;
}
@Override
public Types1_20_5<StructuredDataKeys1_21_5, EntityDataTypes1_21_5> types() {
return VersionedTypes.V1_21_6;
}
@Override
public Types1_20_5<StructuredDataKeys1_21_5, EntityDataTypes1_21_5> mappedTypes() {
return VersionedTypes.V1_21_6;
}
@Override
public TranslatableRewriter getComponentRewriter() {
return translatableRewriter;
}
@Override
public EntityPacketRewriter1_21_7 getEntityRewriter() {
return entityRewriter;
}
@Override
public BlockItemPacketRewriter1_21_7 getItemRewriter() {
return itemRewriter;
}
@Override
public ParticleRewriter<ClientboundPacket1_21_6> getParticleRewriter() {
return particleRewriter;
}
@Override
public TagRewriter<ClientboundPacket1_21_6> getTagRewriter() {
return tagRewriter;
}
@Override
protected PacketTypesProvider<ClientboundPacket1_21_6, ClientboundPacket1_21_6, ServerboundPacket1_21_6, ServerboundPacket1_21_6> createPacketTypesProvider() {
return new SimplePacketTypesProvider<>(
packetTypeMap(unmappedClientboundPacketType, ClientboundPackets1_21_6.class, ClientboundConfigurationPackets1_21_6.class),
packetTypeMap(mappedClientboundPacketType, ClientboundPackets1_21_6.class, ClientboundConfigurationPackets1_21_6.class),
packetTypeMap(mappedServerboundPacketType, ServerboundPackets1_21_6.class, ServerboundConfigurationPackets1_21_6.class),
packetTypeMap(unmappedServerboundPacketType, ServerboundPackets1_21_6.class, ServerboundConfigurationPackets1_21_6.class)
);
}
}
@@ -0,0 +1,63 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viabackwards.protocol.v1_21_7to1_21_6.rewriter;
import com.viaversion.viabackwards.api.rewriters.BackwardsStructuredItemRewriter;
import com.viaversion.viabackwards.protocol.v1_21_7to1_21_6.Protocol1_21_7To1_21_6;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_21_5;
import com.viaversion.viaversion.protocols.v1_21_4to1_21_5.rewriter.RecipeDisplayRewriter1_21_5;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundPacket1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundPackets1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ServerboundPacket1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ServerboundPackets1_21_6;
import com.viaversion.viaversion.rewriter.BlockRewriter;
import com.viaversion.viaversion.rewriter.RecipeDisplayRewriter;
public final class BlockItemPacketRewriter1_21_7 extends BackwardsStructuredItemRewriter<ClientboundPacket1_21_6, ServerboundPacket1_21_6, Protocol1_21_7To1_21_6> {
public BlockItemPacketRewriter1_21_7(final Protocol1_21_7To1_21_6 protocol) {
super(protocol);
}
@Override
public void registerPackets() {
final BlockRewriter<ClientboundPacket1_21_6> blockRewriter = BlockRewriter.for1_20_2(protocol);
blockRewriter.registerBlockEvent(ClientboundPackets1_21_6.BLOCK_EVENT);
blockRewriter.registerBlockUpdate(ClientboundPackets1_21_6.BLOCK_UPDATE);
blockRewriter.registerSectionBlocksUpdate1_20(ClientboundPackets1_21_6.SECTION_BLOCKS_UPDATE);
blockRewriter.registerLevelEvent1_21(ClientboundPackets1_21_6.LEVEL_EVENT, 2001);
blockRewriter.registerLevelChunk1_19(ClientboundPackets1_21_6.LEVEL_CHUNK_WITH_LIGHT, ChunkType1_21_5::new);
blockRewriter.registerBlockEntityData(ClientboundPackets1_21_6.BLOCK_ENTITY_DATA);
registerSetCursorItem(ClientboundPackets1_21_6.SET_CURSOR_ITEM);
registerSetPlayerInventory(ClientboundPackets1_21_6.SET_PLAYER_INVENTORY);
registerCooldown1_21_2(ClientboundPackets1_21_6.COOLDOWN);
registerSetContent1_21_2(ClientboundPackets1_21_6.CONTAINER_SET_CONTENT);
registerSetSlot1_21_2(ClientboundPackets1_21_6.CONTAINER_SET_SLOT);
registerAdvancements1_20_3(ClientboundPackets1_21_6.UPDATE_ADVANCEMENTS);
registerSetEquipment(ClientboundPackets1_21_6.SET_EQUIPMENT);
registerMerchantOffers1_20_5(ClientboundPackets1_21_6.MERCHANT_OFFERS);
registerContainerClick1_21_5(ServerboundPackets1_21_6.CONTAINER_CLICK);
registerSetCreativeModeSlot1_21_5(ServerboundPackets1_21_6.SET_CREATIVE_MODE_SLOT);
final RecipeDisplayRewriter<ClientboundPacket1_21_6> recipeRewriter = new RecipeDisplayRewriter1_21_5<>(protocol);
recipeRewriter.registerUpdateRecipes(ClientboundPackets1_21_6.UPDATE_RECIPES);
recipeRewriter.registerRecipeBookAdd(ClientboundPackets1_21_6.RECIPE_BOOK_ADD);
recipeRewriter.registerPlaceGhostRecipe(ClientboundPackets1_21_6.PLACE_GHOST_RECIPE);
}
}
@@ -0,0 +1,71 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viabackwards.protocol.v1_21_7to1_21_6.rewriter;
import com.viaversion.viabackwards.api.rewriters.BackwardsRegistryRewriter;
import com.viaversion.viabackwards.api.rewriters.EntityRewriter;
import com.viaversion.viabackwards.protocol.v1_21_7to1_21_6.Protocol1_21_7To1_21_6;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_21_4;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_21_6;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_21_5;
import com.viaversion.viaversion.api.type.types.version.VersionedTypes;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundConfigurationPackets1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundPacket1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundPackets1_21_6;
import com.viaversion.viaversion.rewriter.RegistryDataRewriter;
public final class EntityPacketRewriter1_21_7 extends EntityRewriter<ClientboundPacket1_21_6, Protocol1_21_7To1_21_6> {
public EntityPacketRewriter1_21_7(final Protocol1_21_7To1_21_6 protocol) {
super(protocol, VersionedTypes.V1_21_6.entityDataTypes.optionalComponentType, VersionedTypes.V1_21_6.entityDataTypes.booleanType);
}
@Override
public void registerPackets() {
registerTrackerWithData1_19(ClientboundPackets1_21_6.ADD_ENTITY, EntityTypes1_21_4.FALLING_BLOCK);
registerSetEntityData(ClientboundPackets1_21_6.SET_ENTITY_DATA);
registerRemoveEntities(ClientboundPackets1_21_6.REMOVE_ENTITIES);
registerPlayerAbilities(ClientboundPackets1_21_6.PLAYER_ABILITIES);
registerGameEvent(ClientboundPackets1_21_6.GAME_EVENT);
registerLogin1_20_5(ClientboundPackets1_21_6.LOGIN);
registerRespawn1_20_5(ClientboundPackets1_21_6.RESPAWN);
final RegistryDataRewriter registryDataRewriter = new BackwardsRegistryRewriter(protocol);
protocol.registerClientbound(ClientboundConfigurationPackets1_21_6.REGISTRY_DATA, registryDataRewriter::handle);
}
@Override
protected void registerRewrites() {
final EntityDataTypes1_21_5 mappedEntityDataTypes = VersionedTypes.V1_21_6.entityDataTypes;
registerEntityDataTypeHandler1_20_3(
mappedEntityDataTypes.itemType,
mappedEntityDataTypes.blockStateType,
mappedEntityDataTypes.optionalBlockStateType,
mappedEntityDataTypes.particleType,
mappedEntityDataTypes.particlesType,
mappedEntityDataTypes.componentType,
mappedEntityDataTypes.optionalComponentType
);
}
@Override
public EntityType typeFromId(final int type) {
return EntityTypes1_21_6.getTypeFromId(type);
}
}
@@ -19,6 +19,7 @@ package com.viaversion.viabackwards.protocol.v1_21to1_20_5.rewriter;
import com.viaversion.nbt.tag.ByteTag;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viabackwards.api.rewriters.BackwardsStructuredItemRewriter;
@@ -35,6 +36,9 @@ import com.viaversion.viaversion.api.minecraft.SoundEvent;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataContainer;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.minecraft.item.data.AttributeModifiers1_21;
import com.viaversion.viaversion.api.minecraft.item.data.AttributeModifiers1_21.AttributeModifier;
import com.viaversion.viaversion.api.minecraft.item.data.AttributeModifiers1_21.ModifierData;
import com.viaversion.viaversion.api.minecraft.item.data.Enchantments;
import com.viaversion.viaversion.api.minecraft.item.data.JukeboxPlayable;
import com.viaversion.viaversion.api.type.Types;
@@ -271,51 +275,79 @@ public final class BlockItemPacketRewriter1_21 extends BackwardsStructuredItemRe
final StructuredDataContainer data = item.dataContainer();
data.setIdLookup(protocol, true);
final CompoundTag backupTag = new CompoundTag();
final JukeboxPlayable jukeboxPlayable = data.get(StructuredDataKey.JUKEBOX_PLAYABLE1_21);
if (jukeboxPlayable == null) {
return;
if (jukeboxPlayable != null) {
final CompoundTag tag = new CompoundTag();
if (jukeboxPlayable.song().hasHolder()) {
final Holder<JukeboxPlayable.JukeboxSong> songHolder = jukeboxPlayable.song().holder();
tag.put("song", holderToTag(songHolder, (song, songTag) -> {
saveSoundEventHolder(songTag, song.soundEvent());
songTag.put("description", song.description());
songTag.putFloat("length_in_seconds", song.lengthInSeconds());
songTag.putInt("comparator_output", song.comparatorOutput());
}));
} else {
tag.putString("song_identifier", jukeboxPlayable.song().key());
}
tag.putBoolean("show_in_tooltip", jukeboxPlayable.showInTooltip());
backupTag.put("jukebox_playable", tag);
}
final CompoundTag tag = new CompoundTag();
if (jukeboxPlayable.song().hasHolder()) {
final Holder<JukeboxPlayable.JukeboxSong> songHolder = jukeboxPlayable.song().holder();
tag.put("song", holderToTag(songHolder, (song, songTag) -> {
saveSoundEventHolder(songTag, song.soundEvent());
songTag.put("description", song.description());
songTag.putFloat("length_in_seconds", song.lengthInSeconds());
songTag.putInt("comparator_output", song.comparatorOutput());
}));
} else {
tag.putString("song_identifier", jukeboxPlayable.song().key());
final AttributeModifiers1_21 attributeModifiers = data.get(StructuredDataKey.ATTRIBUTE_MODIFIERS1_21);
if (attributeModifiers != null) {
final ListTag<StringTag> attributeIds = new ListTag<>(StringTag.class);
for (final AttributeModifier modifier : attributeModifiers.modifiers()) {
attributeIds.add(new StringTag(modifier.modifier().id()));
}
backupTag.put("attribute_modifiers", attributeIds);
}
tag.putBoolean("show_in_tooltip", jukeboxPlayable.showInTooltip());
saveTag(createCustomTag(item), tag, "jukebox_playable");
if (!backupTag.isEmpty()) {
saveTag(createCustomTag(item), backupTag, "inconvertible_data");
}
}
private void restoreInconvertibleData(final Item item) {
final StructuredDataContainer data = item.dataContainer();
final CompoundTag customData = data.get(StructuredDataKey.CUSTOM_DATA);
if (customData == null || !(customData.remove(nbtTagName("jukebox_playable")) instanceof CompoundTag tag)) {
if (customData == null || !(customData.remove(nbtTagName("inconvertible_data")) instanceof CompoundTag tag)) {
return;
}
final EitherHolder<JukeboxPlayable.JukeboxSong> song;
final String songIdentifier = tag.getString("song_identifier");
if (songIdentifier != null) {
song = EitherHolder.of(songIdentifier);
} else {
song = EitherHolder.of(restoreHolder(tag, "song", songTag -> {
final Holder<SoundEvent> soundEvent = restoreSoundEventHolder(songTag);
final Tag description = songTag.get("description");
final float lengthInSeconds = songTag.getFloat("length_in_seconds");
final int comparatorOutput = songTag.getInt("comparator_output");
return new JukeboxPlayable.JukeboxSong(soundEvent, description, lengthInSeconds, comparatorOutput);
}));
final CompoundTag jukeboxPlayableTag = tag.getCompoundTag("jukebox_playable");
if (jukeboxPlayableTag != null) {
final EitherHolder<JukeboxPlayable.JukeboxSong> song;
final String songIdentifier = tag.getString("song_identifier");
if (songIdentifier != null) {
song = EitherHolder.of(songIdentifier);
} else {
song = EitherHolder.of(restoreHolder(tag, "song", songTag -> {
final Holder<SoundEvent> soundEvent = restoreSoundEventHolder(songTag);
final Tag description = songTag.get("description");
final float lengthInSeconds = songTag.getFloat("length_in_seconds");
final int comparatorOutput = songTag.getInt("comparator_output");
return new JukeboxPlayable.JukeboxSong(soundEvent, description, lengthInSeconds, comparatorOutput);
}));
}
final JukeboxPlayable jukeboxPlayable = new JukeboxPlayable(song, tag.getBoolean("show_in_tooltip"));
data.set(StructuredDataKey.JUKEBOX_PLAYABLE1_21, jukeboxPlayable);
}
final ListTag<StringTag> attributeIds = tag.getListTag("attribute_modifiers", StringTag.class);
final AttributeModifiers1_21 attributeModifiers = data.get(StructuredDataKey.ATTRIBUTE_MODIFIERS1_21);
if (attributeIds != null && attributeModifiers != null && attributeIds.size() == attributeModifiers.modifiers().length) {
for (int i = 0; i < attributeIds.size(); i++) {
final String id = attributeIds.get(i).getValue();
final AttributeModifier modifier = attributeModifiers.modifiers()[i];
final ModifierData updatedModifierData = new ModifierData(id, modifier.modifier().amount(), modifier.modifier().operation());
attributeModifiers.modifiers()[i] = new AttributeModifier(modifier.attribute(), updatedModifierData, modifier.slotType());
}
}
final JukeboxPlayable jukeboxPlayable = new JukeboxPlayable(song, tag.getBoolean("show_in_tooltip"));
data.set(StructuredDataKey.JUKEBOX_PLAYABLE1_21, jukeboxPlayable);
removeCustomTag(data, customData);
}
@@ -34,8 +34,6 @@ import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.version.Types1_20_5;
import com.viaversion.viaversion.api.type.types.version.Types1_21;
import com.viaversion.viaversion.api.type.types.version.VersionedTypes;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ServerboundPackets1_20_5;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.data.Paintings1_20_5;
Loaded 100 of 112 files, more files were not shown because too many files have changed in this diff. Show more