Compare commits

..
7 Commits
Author SHA1 Message Date
NotAlexNoyle 4bbcf6511f Exclude CODEOWNERS from language statistics 2026-10-28 08:31:40 -04:00
NotAlexNoyle c33be26ef2 Add CODEOWNERS (one staff approval) 2026-10-28 08:31:40 -04:00
NotAlexNoyle b50d3bb759 Fix 1.8 combat packet handling 2026-08-09 14:35:28 -04:00
NotAlexNoyle 2dc6ac8c02 Update setting for TAB-OG 2026-07-12 16:54:33 -04:00
NotAlexNoyle c56b44d826 Fix raid messages for legacy clients 2026-06-17 13:02:42 -04:00
NotAlexNoyle bb282dce6b Merge branch 'ViaVersion:master' into master 2026-06-17 12:52:28 -04:00
NotAlexNoyle 00a0db26e3 TrueOG fork patches
Cumulative customizations on top of upstream ViaBackwards master:
- build.gradle.kts: enable Eclipse gradle plugin
- common/.../config.yml: TrueOG network production config,
  inventory title tweak for 1.8 clients

Squashes: Add eclipse library to build.gradle.kts (ee65f8a6),
Use live TrueOG Network config file (f6f2486c), Try to fix
inventory titles on 1.8 (50194b4d), Bee anger field iterations
(06ff7bc5, b3da4f1c), Fix packets (3cc57bfe).
2026-06-05 12:29:03 -04:00
198 changed files with 1172 additions and 5492 deletions

No files matched your search

+1
View File
@@ -0,0 +1 @@
.gitea/CODEOWNERS linguist-detectable=false
+3
View File
@@ -0,0 +1,3 @@
# Pull requests request review from the eligible staff team(s).
# One approval from either an Admin or Developer satisfies branch protection.
* @trueog/Admins @trueog/Developers
-3
View File
@@ -1,5 +1,4 @@
version: 2
# Disabled for the time being, being done manually instead
updates:
- package-ecosystem: "github-actions"
cooldown:
@@ -7,11 +6,9 @@ updates:
directory: "/"
schedule:
interval: "monthly"
open-pull-requests-limit: 0
- package-ecosystem: "gradle"
cooldown:
default-days: 7
directory: "/"
schedule:
interval: "monthly"
open-pull-requests-limit: 0
+3 -3
View File
@@ -11,16 +11,16 @@ jobs:
timeout-minutes: 30
steps:
- name: Checkout Repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Set up Gradle
uses: gradle/actions/setup-gradle@v6.4.0
uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0
with:
cache-disabled: false
cache-provider: basic
- name: Set up JDK 17
uses: actions/setup-java@v6.1.0
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
with:
distribution: 'temurin'
java-version: 17
+4 -4
View File
@@ -16,16 +16,16 @@ jobs:
timeout-minutes: 30
steps:
- name: Checkout Repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Set up Gradle
uses: gradle/actions/setup-gradle@v6.4.0
uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0
with:
cache-disabled: false
cache-provider: basic
- name: Set up JDK 17
uses: actions/setup-java@v6.1.0
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
with:
distribution: 'temurin'
java-version: 17
@@ -40,5 +40,5 @@ jobs:
- name: Publish to Modrinth
env:
MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}
run: ./gradlew publishMods --stacktrace
run: ./gradlew modrinth --stacktrace
continue-on-error: true
-2
View File
@@ -34,6 +34,4 @@ bin/
# Misc
run/
.claude/
!.claude/CLAUDE.md
AGENTS.override.md
+2 -1
View File
@@ -7,7 +7,8 @@ repositories {
}
dependencies {
implementation("com.gradleup.shadow:shadow-gradle-plugin:9.6.1")
// version must be manually kept in sync with the one in root project settings.gradle.kts
implementation("com.gradleup.shadow:shadow-gradle-plugin:9.4.1")
// A nice no-conflict comment for patching in downgrading
}
@@ -51,6 +51,15 @@ abstract class GitCommand : ValueSource<String, GitCommand.GitCommandParameters>
}
fun Project.parseMinecraftSnapshotVersion(version: String): String? {
val separatorIndex = version.indexOf('-')
val lastSeparatorIndex = version.lastIndexOf('-')
if (separatorIndex == -1 || separatorIndex == lastSeparatorIndex) {
return null
}
return version.substring(separatorIndex + 1, lastSeparatorIndex)
}
fun JavaPluginExtension.javaTarget(version: Int) {
toolchain.languageVersion.set(JavaLanguageVersion.of(version))
}
Whitespace-only changes.
+2 -2
View File
@@ -1,7 +1,7 @@
plugins {
base
id("vb.base-conventions") apply false
id("vb.shadow-conventions") apply false
eclipse
id("vb.build-logic")
}
allprojects {
+6 -9
View File
@@ -27,8 +27,7 @@ java {
// Task to quickly test/debug code changes using https://github.com/ViaVersion/ViaProxy
// For further instructions see the ViaProxy repository README
val prepareViaProxyFiles = tasks.register<Copy>("prepareViaProxyFiles") {
description = "Prepares the ViaProxy run dir for the runViaProxy task"
val prepareViaProxyFiles by tasks.registering(Copy::class) {
dependsOn(project.tasks.shadowJar)
from(project.tasks.shadowJar.map { it.archiveFile.get().asFile })
@@ -38,29 +37,27 @@ val prepareViaProxyFiles = tasks.register<Copy>("prepareViaProxyFiles") {
rename { "${projectName}.jar" }
}
val cleanupViaProxyFiles = tasks.register<Delete>("cleanupViaProxyFiles") {
description = "Deletes ViaProxy logs and the compiled project jar from its jars dir"
val cleanupViaProxyFiles by tasks.registering(Delete::class) {
delete(
layout.projectDirectory.file("run/jars/${project.name}.jar"),
layout.projectDirectory.dir("run/logs")
)
}
val viaProxyConfiguration: Configuration = configurations.create("viaProxyConfiguration") {
val viaProxyConfiguration: Configuration by configurations.creating {
dependencies.add(rootProject.libs.viaProxy.get().copy().setTransitive(false))
}
tasks.register<JavaExec>("runViaProxy") {
description = "Runs ViaProxy locally"
dependsOn(prepareViaProxyFiles)
finalizedBy(cleanupViaProxyFiles)
mainClass.set("net.raphimc.viaproxy.ViaProxy")
classpath = viaProxyConfiguration
workingDir = layout.projectDirectory.dir("run").asFile
jvmArgs = listOf("-DskipUpdateCheck", "-Dviaproxy.gui.autoStart")
jvmArgs = listOf("-DskipUpdateCheck")
if (System.getProperty("viaproxy.disableExtraPlatforms") != null) {
jvmArgs("-Dviaproxy.enableViaBedrock=false", "-Dviaproxy.enableViaLegacy=false", "-Dviaproxy.enableViaAprilFools=false")
if (System.getProperty("viaproxy.gui.autoStart") != null) {
jvmArgs("-Dviaproxy.gui.autoStart")
}
}
@@ -69,8 +69,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.protocol.v26_1to1_21_11.Protocol26_1To1_21_11;
import com.viaversion.viabackwards.protocol.v26_2to26_1.Protocol26_2To26_1;
import com.viaversion.viabackwards.protocol.v26_3to26_2.Protocol26_3To26_2;
import com.viaversion.viabackwards.utils.VersionInfo;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.protocol.ProtocolManager;
@@ -82,7 +80,7 @@ import java.util.logging.Logger;
public interface ViaBackwardsPlatform {
String MINIMUM_VV_VERSION = "5.12.2";
String MINIMUM_VV_VERSION = "5.9.2";
default void init(final File configFile) {
init(new ViaBackwardsConfig(configFile, getLogger()));
@@ -169,8 +167,6 @@ public interface ViaBackwardsPlatform {
protocolManager.registerProtocol(new Protocol1_21_11To1_21_9(), ProtocolVersion.v1_21_9, ProtocolVersion.v1_21_11);
protocolManager.registerProtocol(new Protocol26_1To1_21_11(), ProtocolVersion.v1_21_11, ProtocolVersion.v26_1);
protocolManager.registerProtocol(new Protocol26_2To26_1(), ProtocolVersion.v26_1, ProtocolVersion.v26_2);
protocolManager.registerProtocol(new Protocol26_3To26_2(), ProtocolVersion.v26_2, ProtocolVersion.v26_3);
}
default void enable() {
@@ -34,7 +34,7 @@ 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.viaversion.util.Key;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -44,6 +44,7 @@ public class BackwardsMappingData extends MappingDataBase {
private final Class<? extends Protocol<?, ?, ?, ?>> vvProtocolClass;
protected Int2ObjectMap<MappedItem> backwardsItemMappings;
private Map<String, String> entityNames;
private Int2ObjectMap<String> enchantmentNames;
public BackwardsMappingData(final String unmappedVersion, final String mappedVersion) {
@@ -58,23 +59,42 @@ public class BackwardsMappingData extends MappingDataBase {
@Override
protected void loadExtras(final CompoundTag data) {
final CompoundTag itemCustomModelDatas = data.getCompoundTag("custom_model_data");
if (itemCustomModelDatas != null) {
final CompoundTag itemNames = data.getCompoundTag("itemnames");
if (itemNames != null) {
Preconditions.checkNotNull(itemMappings);
backwardsItemMappings = new Int2ObjectOpenHashMap<>(itemCustomModelDatas.size());
loadBackwardsItemMappings(itemCustomModelDatas);
backwardsItemMappings = new Int2ObjectOpenHashMap<>(itemNames.size());
final CompoundTag extraItemData = data.getCompoundTag("itemdata");
for (final Map.Entry<String, Tag> entry : itemNames.entrySet()) {
final StringTag name = (StringTag) entry.getValue();
final int id = Integer.parseInt(entry.getKey());
Integer customModelData = null;
if (extraItemData != null && extraItemData.contains(entry.getKey())) {
final CompoundTag entryTag = extraItemData.getCompoundTag(entry.getKey());
final NumberTag customModelDataTag = entryTag.getNumberTag("custom_model_data");
customModelData = customModelDataTag != null ? customModelDataTag.asInt() : null;
}
backwardsItemMappings.put(id, new MappedItem(getNewItemId(id), name.getValue(), customModelData));
}
}
this.entityNames = loadNameByStringMappings(data, "entitynames");
this.enchantmentNames = loadNameByIdMappings(data, "enchantmentnames");
}
protected void loadBackwardsItemMappings(final CompoundTag itemCustomModelDatas) {
for (final Map.Entry<String, Tag> entry : itemCustomModelDatas.entrySet()) {
final int id = Integer.parseInt(entry.getKey());
final int customModelData = ((NumberTag) entry.getValue()).asInt();
final String identifier = getFullItemMappings().identifier(id);
final String fallbackName = unmappedVersion + " " + nameFromIdentifier(identifier);
backwardsItemMappings.put(id, new MappedItem(getNewItemId(id), identifier, fallbackName, customModelData));
private @Nullable Map<String, String> loadNameByStringMappings(final CompoundTag data, final String key) {
final CompoundTag nameMappings = data.getCompoundTag(key);
if (nameMappings == null) {
return null;
}
final Map<String, String> map = new HashMap<>(nameMappings.size());
for (final Map.Entry<String, Tag> entry : nameMappings.entrySet()) {
final StringTag mappedTag = (StringTag) entry.getValue();
map.put(entry.getKey(), mappedTag.getValue());
}
return map;
}
private @Nullable Int2ObjectMap<String> loadNameByIdMappings(final CompoundTag data, final String key) {
@@ -141,6 +161,14 @@ public class BackwardsMappingData extends MappingDataBase {
return getFullSoundMappings().mappedIdentifier(id);
}
public @Nullable String mappedEntityName(final String entityName) {
if (entityNames == null) {
getLogger().log(Level.SEVERE, "No entity mappings found when requesting them for " + entityName, new RuntimeException());
return null;
}
return entityNames.get(entityName);
}
public @Nullable String mappedEnchantmentName(final int enchantmentId) {
if (enchantmentNames == null) {
ViaBackwards.getPlatform().getLogger().log(Level.SEVERE, "No enchantment name mappings found when requesting " + enchantmentId, new RuntimeException());
@@ -166,12 +194,4 @@ public class BackwardsMappingData extends MappingDataBase {
protected @Nullable CompoundTag readMappingsFile(final String name) {
return BackwardsMappingDataLoader.INSTANCE.loadNBTFromDir(name);
}
public static String nameFromIdentifier(final String identifier) {
final StringBuilder result = new StringBuilder();
for (final String split : Key.stripMinecraftNamespace(identifier).split("_")) {
result.append(' ').append(Character.toUpperCase(split.charAt(0))).append(split.substring(1));
}
return result.substring(1);
}
}
@@ -17,45 +17,28 @@
*/
package com.viaversion.viabackwards.api.data;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.libs.gson.JsonPrimitive;
import com.viaversion.viaversion.util.Key;
import com.viaversion.viaversion.util.ComponentUtil;
import org.checkerframework.checker.nullness.qual.Nullable;
public class MappedItem {
private final int id;
private final String jsonName;
private final Tag tagName;
private final int customModelData;
private final Integer customModelData;
public MappedItem(final int id, String identifier, final String fallbackName, final int customModelData) {
public MappedItem(final int id, final String name) {
this(id, name, null);
}
public MappedItem(final int id, final String name, @Nullable final Integer customModelData) {
this.id = id;
identifier = Key.stripMinecraftNamespace(identifier);
final String translateKey = "vb.item." + identifier;
this.jsonName = itemJsonName(fallbackName);
this.tagName = itemTagName(translateKey, fallbackName);
this.jsonName = ComponentUtil.legacyToJsonString("§f" + name, true);
this.tagName = ComponentUtil.jsonStringToTag(jsonName);
this.customModelData = customModelData;
}
// Make explicitly non-italic and white to override default item formatting.
// Properly parsing is expensive...
private static String itemJsonName(final String name) {
return """
{"italic":false,"color":"white","text":%s}
""".formatted(new JsonPrimitive(name).toString());
}
private static Tag itemTagName(final String translateKey, final String fallbackName) {
// Proper translate with fallback field (valid for 1.19.4+ clients)
final CompoundTag tag = new CompoundTag();
tag.putString("color", "white");
tag.putString("translate", translateKey);
tag.putString("fallback", fallbackName);
tag.putBoolean("italic", false);
return tag;
}
public int id() {
return id;
}
@@ -65,10 +48,10 @@ public class MappedItem {
}
public Tag tagName() {
return tagName.copy();
return tagName;
}
public int customModelData() {
public @Nullable Integer customModelData() {
return customModelData;
}
}
@@ -1,48 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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.api.entities;
import com.viaversion.viaversion.api.connection.StorableObject;
import com.viaversion.viaversion.api.data.entity.TrackedEntity;
/**
* Storage object used within {@link TrackedEntity} to track the scaling state of an entity.
* This ensures that scale updates are only sent when the calculated scale actually changes.
*/
public final class EntityScaleData implements StorableObject {
private boolean isBaby;
private float scale = 1.0f;
public boolean isBaby() {
return isBaby;
}
public void setBaby(boolean baby) {
this.isBaby = baby;
}
public float scale() {
return scale;
}
public void setScale(float scale) {
this.scale = scale;
}
}
@@ -1,102 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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.api.entities;
import com.google.common.base.Preconditions;
import com.viaversion.viaversion.api.data.FullMappings;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.rewriter.EntityRewriter;
import com.viaversion.viaversion.rewriter.entitydata.EntityDataHandlerEvent;
/**
* A helper for injecting entity scaling on older clients.
* This helper listens for the baby entity data flag and sends an UPDATE_ATTRIBUTES packet
* to scale the entity, since older clients might not support the newer entity variants natively.
*/
public class EntityScaleHelper {
private final ClientboundPacketType updateAttributesPacket;
private final EntityRewriter<?, ?> rewriter;
/**
* Constructs a new entity scale helper.
*
* @param rewriter entity rewriter
* @param updateAttributesPacket UPDATE_ATTRIBUTES packet of the mapped protocol
* @param <CM> mapped clientbound packet type
*/
public <CM extends ClientboundPacketType, P extends Protocol<?, CM, ?, ?>> EntityScaleHelper(final EntityRewriter<?, P> rewriter, final CM updateAttributesPacket) {
this.rewriter = rewriter;
this.updateAttributesPacket = updateAttributesPacket;
}
/**
* Registers a scaling factor for a specific baby entity type.
*
* @param type entity type that requires scaling when it is a baby
* @param babyScaleFactor multiplier to apply to the minecraft:scale attribute when it is a baby
* @param babyIndex entity data index for the baby property in this specific protocol
*/
public void addBabyScale(final EntityType type, final float babyScaleFactor, final int babyIndex) {
rewriter.filter().type(type).index(babyIndex).handler(((event, data) -> trackAndSend(event, data, babyScaleFactor)));
}
/**
* Checks the entity data, tracks the scale state and sends an UPDATE_ATTRIBUTES packet if needed.
*/
public void trackAndSend(final EntityDataHandlerEvent event, final EntityData data, final float babyScaleFactor) {
if (event.trackedEntity() == null) {
return;
}
EntityScaleData scaleData = event.trackedEntity().get(EntityScaleData.class);
if (scaleData == null) {
scaleData = new EntityScaleData();
event.trackedEntity().put(scaleData);
}
final boolean isBaby = data.value();
if (scaleData.isBaby() == isBaby) {
return;
}
scaleData.setBaby(isBaby);
scaleData.setScale(isBaby ? babyScaleFactor : 1.0f);
final FullMappings attributeMappings = rewriter.protocol().getMappingData().getAttributeMappings();
int attributeId = attributeMappings.mappedId("scale");
if (attributeId == -1) {
attributeId = attributeMappings.mappedId("generic.scale");
Preconditions.checkArgument(attributeId != -1);
}
final PacketWrapper attributesPacket = PacketWrapper.create(updateAttributesPacket, event.user());
attributesPacket.write(Types.VAR_INT, event.entityId());
attributesPacket.write(Types.VAR_INT, 1); // 1 attribute
attributesPacket.write(Types.VAR_INT, attributeId);
attributesPacket.write(Types.DOUBLE, (double) scaleData.scale());
attributesPacket.write(Types.VAR_INT, 0); // 0 modifiers
attributesPacket.send(rewriter.protocol().getClass());
}
}
@@ -18,10 +18,12 @@
package com.viaversion.viabackwards.api.entities.storage;
import com.viaversion.viabackwards.api.rewriters.EntityRewriterBase;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.entity.TrackedEntity;
import com.viaversion.viaversion.api.data.entity.StoredEntityData;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.util.ProtocolLogger;
import java.util.function.Supplier;
public class EntityPositionHandler {
@@ -30,6 +32,7 @@ public class EntityPositionHandler {
private final EntityRewriterBase<?, ?> entityRewriter;
private final Class<? extends EntityPositionStorage> storageClass;
private final Supplier<? extends EntityPositionStorage> storageSupplier;
private boolean warnedForMissingEntity;
public EntityPositionHandler(EntityRewriterBase<?, ?> entityRewriter,
Class<? extends EntityPositionStorage> storageClass, Supplier<? extends EntityPositionStorage> storageSupplier) {
@@ -48,18 +51,27 @@ public class EntityPositionHandler {
}
public void cacheEntityPosition(PacketWrapper wrapper, int entityId, double x, double y, double z, boolean create, boolean relative) {
final TrackedEntity entity = entityRewriter.tracker(wrapper.user()).entity(entityId);
if (entity == null) {
// Bad plugins
StoredEntityData storedEntity = entityRewriter.tracker(wrapper.user()).entityData(entityId);
if (storedEntity == null) {
if (Via.getManager().isDebug()) { // There is too many plugins violating this out there, and reading seems to be hard! :>
ProtocolLogger logger = entityRewriter.protocol().getLogger();
logger.warning("Stored entity with id " + entityId + " missing at position: " + x + " - " + y + " - " + z + " in " + storageClass.getSimpleName());
if (entityId == -1 && x == 0 && y == 0 && z == 0) {
logger.warning("DO NOT REPORT THIS TO VIA, THIS IS A PLUGIN ISSUE");
} else if (!warnedForMissingEntity) {
warnedForMissingEntity = true;
logger.warning("This is very likely caused by a plugin sending a teleport packet for an entity outside of the player's range.");
}
}
return;
}
EntityPositionStorage positionStorage;
if (create) {
positionStorage = storageSupplier.get();
entity.put(positionStorage);
storedEntity.put(positionStorage);
} else {
positionStorage = entity.get(storageClass);
positionStorage = storedEntity.get(storageClass);
if (positionStorage == null) {
entityRewriter.protocol().getLogger().warning("Stored entity with id " + entityId + " missing " + storageClass.getSimpleName());
return;
@@ -74,9 +86,9 @@ public class EntityPositionHandler {
}
public EntityPositionStorage getStorage(UserConnection user, int entityId) {
final TrackedEntity entity = entityRewriter.tracker(user).entity(entityId);
StoredEntityData storedEntity = entityRewriter.tracker(user).entityData(entityId);
EntityPositionStorage entityStorage;
if (entity == null || (entityStorage = entity.get(EntityPositionStorage.class)) == null) {
if (storedEntity == null || (entityStorage = storedEntity.get(EntityPositionStorage.class)) == null) {
entityRewriter.protocol().getLogger().warning("Untracked entity with id " + entityId + " in " + storageClass.getSimpleName());
return null;
}
@@ -17,9 +17,7 @@
*/
package com.viaversion.viabackwards.api.entities.storage;
import com.viaversion.viaversion.api.connection.StorableObject;
public abstract class EntityPositionStorage implements StorableObject {
public abstract class EntityPositionStorage {
private double x;
private double y;
private double z;
@@ -18,10 +18,8 @@
package com.viaversion.viabackwards.api.entities.storage;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.data.BackwardsMappingData;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.util.ComponentUtil;
import java.util.Locale;
@@ -32,22 +30,18 @@ public class EntityReplacement {
private final int id;
private final int replacementId;
private final String key;
private final String translateKey;
private final String fallbackName;
private ComponentType componentType = ComponentType.NONE;
private EntityDataCreator defaultData;
public EntityReplacement(BackwardsProtocol<?, ?, ?, ?> protocol, EntityType type, int replacementId) {
this(protocol, type.name().toLowerCase(Locale.ROOT), type.getId(), replacementId);
this(protocol, type.name(), type.getId(), replacementId);
}
public EntityReplacement(BackwardsProtocol<?, ?, ?, ?> protocol, String key, int id, int replacementId) {
this.protocol = protocol;
this.id = id;
this.replacementId = replacementId;
this.key = key;
this.translateKey = "vb.entity." + key;
this.fallbackName = BackwardsMappingData.nameFromIdentifier(this.key);
this.key = key.toLowerCase(Locale.ROOT);
}
public EntityReplacement jsonName() {
@@ -79,26 +73,24 @@ public class EntityReplacement {
}
/**
* Returns the custom entity name. Can be either a {@link String}, {@link StringTag} or {@link com.viaversion.viaversion.libs.gson.JsonElement}.
*
* @return custom entity name
* @return custom mobname, can be either a String or a JsonElement
*/
public @Nullable Object entityName() {
if (componentType == ComponentType.NONE) {
return null;
}
if (componentType == ComponentType.JSON) {
return ComponentUtil.plainToJson(fallbackName); // Pass on as plain, with or without section symbols
} else if (componentType == ComponentType.TAG) {
final CompoundTag tag = new CompoundTag();
tag.putString("color", "white");
tag.putString("translate", translateKey);
tag.putString("fallback", fallbackName);
tag.putBoolean("italic", false);
return tag;
final String name = protocol.getMappingData().mappedEntityName(key);
if (name == null) {
return null;
}
return fallbackName;
if (componentType == ComponentType.JSON) {
return ComponentUtil.legacyToJson(name);
} else if (componentType == ComponentType.TAG) {
return new StringTag(name);
}
return name;
}
public int replacementId() {
@@ -1,57 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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.api.entities.storage;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Types;
public class PlayerPosRotStorage extends PlayerPositionStorage {
private float yRot; // yaw
private float xRot; // pitch
public float yRot() {
return yRot;
}
public void setYRot(final float yRot) {
this.yRot = yRot;
}
public float xRot() {
return xRot;
}
public void setXRot(final float xRot) {
this.xRot = xRot;
}
public void setRotation(final float yRot, final float xRot) {
this.yRot = yRot;
this.xRot = xRot;
}
public void setRotFromPacket(final PacketWrapper wrapper) {
this.yRot = wrapper.passthrough(Types.FLOAT);
this.xRot = wrapper.passthrough(Types.FLOAT);
}
public void setPosRotFromPacket(final PacketWrapper wrapper) {
this.setPosFromPacket(wrapper);
this.setRotFromPacket(wrapper);
}
}
@@ -18,14 +18,15 @@
package com.viaversion.viabackwards.api.entities.storage;
import com.viaversion.viaversion.api.connection.StorableObject;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Types;
public class PlayerPositionStorage implements StorableObject {
public abstract class PlayerPositionStorage implements StorableObject {
private double x;
private double y;
private double z;
protected PlayerPositionStorage() {
}
public double x() {
return x;
}
@@ -56,12 +57,6 @@ public class PlayerPositionStorage implements StorableObject {
this.z = z;
}
public void setPosFromPacket(PacketWrapper wrapper) {
this.x = wrapper.passthrough(Types.DOUBLE);
this.y = wrapper.passthrough(Types.DOUBLE);
this.z = wrapper.passthrough(Types.DOUBLE);
}
public void addRelativePosition(double relX, double relY, double relZ) {
this.x += relX;
this.y += relY;
@@ -1,81 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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.api.rewriters;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viaversion.api.connection.ProtocolInfo;
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.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
// 1.20.5-1.21.4
public class BackwardsFullStructuredItemRewriter<C extends ClientboundPacketType, S extends ServerboundPacketType,
T extends BackwardsProtocol<C, ?, ?, S>> extends BackwardsStructuredItemRewriter<C, S, T> {
public BackwardsFullStructuredItemRewriter(final T protocol) {
super(protocol);
}
@Override
public Item handleItemToServer(final UserConnection connection, final Item item) {
if (Item.isEmpty(item)) {
return item;
}
final ProtocolInfo protocolInfo = connection.getProtocolInfo();
if (protocolInfo.serverProtocolVersion().newerThanOrEqualTo(ProtocolVersion.v1_21_5)
&& !protocol.getEntityRewriter().tracker(connection).canInstaBuild()) {
// We don't actually need anything but the amount, id, and hashes.
// Just pass it on without deeper handling, only leaving custom data.
final CompoundTag customData = item.dataContainer().get(StructuredDataKey.CUSTOM_DATA);
if (customData == null) {
// Not valid
item.dataContainer().data().clear();
} else {
customData.keySet().removeIf(key -> !key.equals(ORIGINAL_HASHES_KEY));
item.dataContainer().data().keySet().removeIf(key -> key != StructuredDataKey.CUSTOM_DATA);
}
}
return super.handleItemToServer(connection, item);
}
@Override
protected void restoreBackupData(final Item item, final StructuredDataContainer container, final CompoundTag customData) {
// Keep original hashes intact until 1.21.5
final Tag hashes = customData.get(ORIGINAL_HASHES_KEY);
super.restoreBackupData(item, container, customData);
if (hashes != null) {
customData.put(ORIGINAL_HASHES_KEY, hashes);
// Add back
if (!container.has(StructuredDataKey.CUSTOM_DATA)) {
container.set(StructuredDataKey.CUSTOM_DATA, customData);
customData.putBoolean(MARKER_KEY, true);
}
}
}
}
@@ -24,7 +24,6 @@ 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.BackwardsProtocol;
import com.viaversion.viabackwards.api.data.MappedItem;
import com.viaversion.viabackwards.item.DataItemWithExtras;
@@ -37,7 +36,6 @@ import com.viaversion.viaversion.libs.gson.JsonElement;
import java.util.List;
import org.checkerframework.checker.nullness.qual.Nullable;
// <1.20.5
public class BackwardsItemRewriter<C extends ClientboundPacketType, S extends ServerboundPacketType,
T extends BackwardsProtocol<C, ?, ?, S>> extends BackwardsItemRewriterBase<C, S, T> {
@@ -115,7 +113,7 @@ public class BackwardsItemRewriter<C extends ClientboundPacketType, S extends Se
item.setIdentifier(data.id());
// Add custom model data
if (ViaBackwards.getConfig().passOriginalItemNameToResourcePacks() && !item.tag().contains("CustomModelData")) {
if (data.customModelData() != null && !item.tag().contains("CustomModelData")) {
item.tag().putInt("CustomModelData", data.customModelData());
}
@@ -18,15 +18,11 @@
package com.viaversion.viabackwards.api.rewriters;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.FullMappings;
import com.viaversion.viaversion.api.minecraft.RegistryEntry;
import com.viaversion.viaversion.rewriter.RegistryDataRewriter;
import com.viaversion.viaversion.util.Key;
import com.viaversion.viaversion.util.TagUtil;
import java.util.Map;
public class BackwardsRegistryRewriter extends RegistryDataRewriter {
@@ -48,19 +44,13 @@ public class BackwardsRegistryRewriter extends RegistryDataRewriter {
final CompoundTag effects = biome.getCompoundTag("effects");
updateBiomeEffects(effects);
final CompoundTag attributes = biome.getCompoundTag("attributes");
if (attributes != null) {
updateAttributes(attributes);
}
}
}
return super.handle(connection, key, entries);
}
@Override
public void updateJukeboxSongs(final UserConnection connection, final RegistryEntry[] entries) {
super.updateJukeboxSongs(connection, entries);
public void updateJukeboxSongs(final RegistryEntry[] entries) {
for (final RegistryEntry entry : entries) {
if (entry.tag() == null) {
continue;
@@ -70,28 +60,6 @@ public class BackwardsRegistryRewriter extends RegistryDataRewriter {
}
}
@Override
protected boolean updateBlockState(final Tag blockStateTag) {
if (!(blockStateTag instanceof CompoundTag blockState) || blockState.getStringTag("Name") == null) {
return super.updateBlockState(blockStateTag);
}
// Up to 26.2, block states use "Name" and "Properties" instead of "id" and "properties"
final FullMappings blockMappings = protocol.getMappingData().getFullBlockMappings();
if (blockMappings == null) {
return false;
}
final int blockId = blockMappings.id(blockState.getString("Name"));
if (blockId == -1 || protocol.getMappingData().hasBlockChanged(blockId)) {
// Replace unknown or changed blocks with a dummy state, else the client will fail to load the registry
blockState.putString("Name", "minecraft:dirt");
blockState.remove("Properties");
return true;
}
return false;
}
private void updateBiomeEffects(final CompoundTag effects) {
updateSound(effects.getCompoundTag("mood_sound"), "sound");
updateSound(effects.getCompoundTag("additions_sound"), "sound");
@@ -99,20 +67,6 @@ public class BackwardsRegistryRewriter extends RegistryDataRewriter {
updateSound(effects, "ambient_sound");
}
private void updateAttributes(final CompoundTag attributes) {
final CompoundTag backgroundMusic = TagUtil.getNamespacedCompoundTag(attributes, "audio/background_music");
if (backgroundMusic != null) {
updateSound(backgroundMusic.getCompoundTag("default"), "sound");
}
final CompoundTag ambientSounds = TagUtil.getNamespacedCompoundTag(attributes, "audio/ambient_sounds");
if (ambientSounds != null) {
updateSound(ambientSounds, "loop");
updateSound(ambientSounds, "mood");
updateSound(ambientSounds, "additions");
}
}
private void updateSound(final CompoundTag tag, final String name) {
if (tag == null) {
return;
@@ -124,16 +78,14 @@ public class BackwardsRegistryRewriter extends RegistryDataRewriter {
}
final String mappedSound = protocol.getMappingData().getMappedNamedSound(sound);
if (mappedSound != null) {
tag.putString(name, mappedSound);
} else if (name.equals("sound_id")) {
// If it's already an inlined sound
if (mappedSound == null) {
return;
}
if (mappedSound.isEmpty()) {
tag.putString(name, "minecraft:intentionally_empty");
} else {
// Write as custom sound, so the id doesn't actually need to exist later on
final CompoundTag soundEvent = new CompoundTag();
soundEvent.putString("sound_id", "minecraft:intentionally_empty");
tag.put(name, soundEvent);
tag.putString(name, mappedSound);
}
}
}
@@ -49,7 +49,6 @@ import java.util.function.BiConsumer;
import java.util.function.Function;
import org.checkerframework.checker.nullness.qual.Nullable;
// 1.21.5+
public class BackwardsStructuredItemRewriter<C extends ClientboundPacketType, S extends ServerboundPacketType,
T extends BackwardsProtocol<C, ?, ?, S>> extends StructuredItemRewriter<C, S, T> {
@@ -77,10 +76,11 @@ public class BackwardsStructuredItemRewriter<C extends ClientboundPacketType, S
customTag.putInt(nbtTagName("id"), item.identifier()); // Save original id
// Add custom model data
if (ViaBackwards.getConfig().passOriginalItemNameToResourcePacks()) {
final boolean addOriginalIdentifier = ViaBackwards.getConfig().passOriginalItemNameToResourcePacks();
if (mappedItem.customModelData() != null || addOriginalIdentifier) {
if (connection.getProtocolInfo().protocolVersion().newerThanOrEqualTo(ProtocolVersion.v1_21_4)) {
addCustomModelData(item, mappedItem, customTag);
} else if (!dataContainer.has(StructuredDataKey.CUSTOM_MODEL_DATA1_20_5)) {
addCustomModelData(item, addOriginalIdentifier, mappedItem, customTag);
} else if (mappedItem.customModelData() != null && !dataContainer.has(StructuredDataKey.CUSTOM_MODEL_DATA1_20_5)) {
dataContainer.set(StructuredDataKey.CUSTOM_MODEL_DATA1_20_5, mappedItem.customModelData());
}
}
@@ -92,22 +92,24 @@ public class BackwardsStructuredItemRewriter<C extends ClientboundPacketType, S
}
}
private void addCustomModelData(final Item item, final MappedItem mappedItem, final CompoundTag customTag) {
private void addCustomModelData(final Item item, final boolean addOriginalIdentifier, final MappedItem mappedItem, final CompoundTag customTag) {
final StructuredDataContainer dataContainer = item.dataContainer();
CustomModelData1_21_4 customModelData = dataContainer.get(StructuredDataKey.CUSTOM_MODEL_DATA1_21_4);
if (customModelData == null) {
// Add both the identifier string and custom model data
final String[] strings = addOriginalIdentifier
? new String[]{protocol.getMappingData().getFullItemMappings().identifier(item.identifier())}
: new String[0];
customModelData = new CustomModelData1_21_4(
new float[]{mappedItem.customModelData()},
mappedItem.customModelData() != null ? new float[]{mappedItem.customModelData().floatValue()} : new float[0],
new boolean[0],
new String[]{protocol.getMappingData().getFullItemMappings().identifier(item.identifier())},
strings,
EMPTY_INT_ARRAY
);
dataContainer.set(StructuredDataKey.CUSTOM_MODEL_DATA1_21_4, customModelData);
// Add one global marker and one for this specific version, so it is removed at the correct protocol
customTag.putBoolean(GLOBAL_MODEL_DATA_MARKER, true);
customTag.putBoolean(nbtTagName("added_custom_model_data"), true);
} else if (!customTag.contains(GLOBAL_MODEL_DATA_MARKER)) {
} else if (addOriginalIdentifier && !customTag.contains(GLOBAL_MODEL_DATA_MARKER)) {
final String identifier = protocol.getMappingData().getFullItemMappings().identifier(item.identifier());
dataContainer.set(StructuredDataKey.CUSTOM_MODEL_DATA1_21_4, new CustomModelData1_21_4(
customModelData.floats(), customModelData.booleans(), ArrayUtil.add(customModelData.strings(), identifier), customModelData.colors()
@@ -18,7 +18,8 @@
package com.viaversion.viabackwards.api.rewriters;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viaversion.api.data.entity.TrackedEntity;
import com.viaversion.viaversion.api.data.entity.EntityTracker;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityDataType;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
@@ -36,28 +37,111 @@ public abstract class EntityRewriter<C extends ClientboundPacketType, T extends
super(protocol, displayType, 2, displayVisibilityType, 3);
}
@Override
public void registerTrackerWithData(C packetType) {
protocol.registerClientbound(packetType, wrapper -> {
wrapper.passthrough(Types.VAR_INT); // Entity ID
wrapper.passthrough(Types.UUID); // Entity UUID
wrapper.passthrough(Types.VAR_INT); // Entity Type
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.INT); // Data
getSpawnTrackerWithDataHandler().handle(wrapper);
});
}
@Override
public void registerTrackerWithData1_19(C packetType) {
protocol.registerClientbound(packetType, wrapper -> {
wrapper.passthrough(Types.VAR_INT); // Entity id
wrapper.passthrough(Types.UUID); // Entity UUID
wrapper.passthrough(Types.VAR_INT); // Entity type
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
getSpawnTrackerWithDataHandler1_19().handle(wrapper);
});
}
public PacketHandler getSpawnTrackerWithDataHandler() {
return wrapper -> {
int entityId = wrapper.get(Types.VAR_INT, 0);
int typeId = wrapper.get(Types.VAR_INT, 1);
TrackedEntity entity = trackAndRewrite(wrapper, typeId, entityId);
if (entity.entityType() == fallingBlockType()) {
// Check against the UNMAPPED entity type
EntityType entityType = trackAndMapEntity(wrapper);
if (entityType == typeFromId("falling_block")) {
int blockState = wrapper.get(Types.INT, 0);
wrapper.set(Types.INT, 0, protocol.getMappingData().getNewBlockStateId(blockState));
}
};
}
public void trackSpawnWithData1_19(final PacketWrapper wrapper, final int data) {
if (protocol.getMappingData() == null) {
return;
public PacketHandler getSpawnTrackerWithDataHandler1_19() {
return wrapper -> {
if (protocol.getMappingData() == null) {
return;
}
// Check against the UNMAPPED entity type
EntityType entityType = trackAndMapEntity(wrapper);
if (entityType == typeFromId("falling_block")) {
int blockState = wrapper.get(Types.VAR_INT, 2);
wrapper.set(Types.VAR_INT, 2, protocol.getMappingData().getNewBlockStateId(blockState));
}
};
}
@Override
public void registerTracker(C packetType) {
protocol.registerClientbound(packetType, wrapper -> {
wrapper.passthrough(Types.VAR_INT); // Entity ID
wrapper.passthrough(Types.UUID); // Entity UUID
wrapper.passthrough(Types.VAR_INT); // Entity Type
trackAndMapEntity(wrapper);
});
}
/**
* Returns a handler to track the current world and uncache entity data on world changes.
*
* @return handler to track the current world
*/
public PacketHandler worldTrackerHandlerByKey() {
return wrapper -> {
EntityTracker tracker = tracker(wrapper.user());
String world = wrapper.get(Types.STRING, 1);
if (tracker.currentWorld() != null && !tracker.currentWorld().equals(world)) {
tracker.clearEntities();
}
tracker.setCurrentWorld(world);
};
}
/**
* Sets the mapped entity id and returns the unmapped entity type.
*
* @param wrapper packet wrapper
* @return unmapped (!) entity type
*/
protected EntityType trackAndMapEntity(PacketWrapper wrapper) {
int typeId = wrapper.get(Types.VAR_INT, 1);
EntityType entityType = typeFromId(typeId);
if (entityType == null) {
return null;
}
int entityId = wrapper.get(Types.VAR_INT, 0);
int typeId = wrapper.get(Types.VAR_INT, 1);
TrackedEntity entity = trackAndRewrite(wrapper, typeId, entityId);
if (entity.entityType() == fallingBlockType()) {
wrapper.set(Types.VAR_INT, 2, protocol.getMappingData().getNewBlockStateId(data));
tracker(wrapper.user()).addEntity(wrapper.get(Types.VAR_INT, 0), entityType);
int mappedTypeId = newEntityId(entityType.getId());
if (typeId != mappedTypeId) {
wrapper.set(Types.VAR_INT, 1, mappedTypeId);
}
return entityType;
}
}
@@ -23,6 +23,8 @@ import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.entities.storage.EntityReplacement;
import com.viaversion.viabackwards.api.entities.storage.WrappedEntityData;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.entity.EntityTracker;
import com.viaversion.viaversion.api.data.entity.StoredEntityData;
import com.viaversion.viaversion.api.data.entity.TrackedEntity;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.Particle;
@@ -37,6 +39,7 @@ import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectMap;
import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectOpenHashMap;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.rewriter.EntityRewriter;
import com.viaversion.viaversion.rewriter.entitydata.EntityDataHandlerEvent;
import java.util.List;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -83,12 +86,12 @@ public abstract class EntityRewriterBase<C extends ClientboundPacketType, T exte
// Add it as new entity data
entityDataList.add(new EntityData(displayNameIndex, displayNameDataType, displayNameObject));
addDisplayVisibilityData(entityDataList);
} else if (isEmptyDisplayName(displayName.getValue())) {
} else if (displayName.getValue() == null || displayName.getValue().toString().isEmpty()) {
// Overwrite the existing null/empty display name
displayName.setValue(displayNameObject);
addDisplayVisibilityData(entityDataList);
}
} else if (displayName != null && (isEmptyDisplayName(displayName))) {
} else if (displayName != null && (displayName.getValue() == null || displayName.getValue().toString().isEmpty())) {
// Overwrite null/empty display name
displayName.setValue(displayNameObject);
addDisplayVisibilityData(entityDataList);
@@ -101,17 +104,6 @@ public abstract class EntityRewriterBase<C extends ClientboundPacketType, T exte
}
}
private boolean isEmptyDisplayName(@Nullable Object o) {
if (o == null) {
return true;
} else if (o instanceof String s) {
return s.isEmpty();
} else if (o instanceof JsonElement element) {
return element.isJsonNull() || (element.isJsonPrimitive() && element.getAsJsonPrimitive().getAsString().isEmpty());
}
return false;
}
private void addDisplayVisibilityData(List<EntityData> entityDataList) {
if (alwaysShowOriginalMobName()) {
removeData(displayVisibilityIndex, entityDataList);
@@ -148,6 +140,10 @@ public abstract class EntityRewriterBase<C extends ClientboundPacketType, T exte
return entityDataMappings.get(type.getId());
}
protected @Nullable StoredEntityData storedEntityData(EntityDataHandlerEvent event) {
return tracker(event.user()).entityData(event.entityId());
}
/**
* Maps an entity type to another with extra data.
* Note that both types should be of the same version.
@@ -231,8 +227,6 @@ public abstract class EntityRewriterBase<C extends ClientboundPacketType, T exte
});
}
// ------------------ Legacy methods
// ONLY TRACKS, DOESN'T REWRITE IDS
protected PacketHandler getTrackerHandler(Type<? extends Number> intType, int typeIndex) {
return wrapper -> {
@@ -248,9 +242,23 @@ public abstract class EntityRewriterBase<C extends ClientboundPacketType, T exte
return getTrackerHandler(Types.VAR_INT, 1);
}
protected PacketHandler getTrackerHandler(EntityType entityType) {
return wrapper -> tracker(wrapper.user()).addEntity(wrapper.get(Types.VAR_INT, 0), entityType);
}
protected PacketHandler getPlayerTrackerHandler() {
return wrapper -> {
final int entityId = wrapper.get(Types.INT, 0);
final EntityTracker tracker = tracker(wrapper.user());
tracker(wrapper.user()).setClientEntityId(entityId);
tracker.addEntity(entityId, tracker.playerType());
};
}
protected PacketHandler getDimensionHandler(int index) {
return wrapper -> {
ClientWorld clientWorld = wrapper.user().storables(this.protocol).clientWorld();
ClientWorld clientWorld = wrapper.user().getClientWorld(this.protocol.getClass());
int dimensionId = wrapper.get(Types.INT, index);
if (clientWorld.setEnvironment(dimensionId)) {
tracker(wrapper.user()).clearEntities();
@@ -21,7 +21,6 @@ import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.entities.storage.EntityObjectData;
import com.viaversion.viabackwards.api.entities.storage.EntityReplacement;
import com.viaversion.viabackwards.api.entities.storage.WrappedEntityData;
import com.viaversion.viaversion.api.data.entity.EntityTracker;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.ObjectType;
@@ -36,7 +35,6 @@ import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -52,7 +50,7 @@ public abstract class LegacyEntityRewriter<C extends ClientboundPacketType, T ex
}
protected EntityObjectData mapObjectType(ObjectType oldObjectType, ObjectType replacement, int data) {
EntityObjectData entData = new EntityObjectData(protocol, oldObjectType.getType().name().toLowerCase(Locale.ROOT), oldObjectType.getId(), replacement.getId(), data);
EntityObjectData entData = new EntityObjectData(protocol, oldObjectType.getType().name(), oldObjectType.getId(), replacement.getId(), data);
objectTypes.put(oldObjectType, entData);
return entData;
}
@@ -67,7 +65,7 @@ public abstract class LegacyEntityRewriter<C extends ClientboundPacketType, T ex
public void register() {
map(Types.INT);
handler(wrapper -> {
ClientWorld clientWorld = wrapper.user().storables(protocol).clientWorld();
ClientWorld clientWorld = wrapper.user().getClientWorld(protocol.getClass());
if (clientWorld.setEnvironment(wrapper.get(Types.INT, 0))) {
tracker(wrapper.user()).clearEntities();
}
@@ -84,13 +82,12 @@ public abstract class LegacyEntityRewriter<C extends ClientboundPacketType, T ex
map(Types.UNSIGNED_BYTE); // 1 - Gamemode
map(Types.INT); // 2 - Dimension
handler(wrapper -> {
ClientWorld clientWorld = wrapper.user().storables(protocol).clientWorld();
ClientWorld clientWorld = wrapper.user().getClientWorld(protocol.getClass());
clientWorld.setEnvironment(wrapper.get(Types.INT, 1));
final int entityId = wrapper.get(Types.INT, 0);
final EntityTracker tracker = tracker(wrapper.user());
tracker.addEntity(entityId, playerType);
tracker.setClientEntityId(entityId);
tracker(wrapper.user()).addEntity(entityId, playerType);
tracker(wrapper.user()).setClientEntityId(entityId);
});
}
});
@@ -33,7 +33,6 @@ import com.viaversion.viaversion.libs.fastutil.ints.Int2IntMap;
import com.viaversion.viaversion.libs.fastutil.objects.ObjectIterator;
import com.viaversion.viaversion.rewriter.IdRewriteFunction;
import com.viaversion.viaversion.util.ComponentUtil;
import com.viaversion.viaversion.util.Limit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -196,12 +195,7 @@ public class StructuredEnchantmentRewriter {
}
final Enchantments enchantments = new Enchantments(tag.remove(itemRewriter.nbtTagName("show_" + key.identifier())) != null);
int i = 0;
for (final CompoundTag enchantment : enchantmentsTag) {
if (i++ > 255) {
break;
}
enchantments.add(enchantment.getInt("id"), enchantment.getInt("lvl"));
}
data.set(key, enchantments);
@@ -22,19 +22,22 @@ import com.viaversion.viabackwards.api.data.BackwardsMappingData;
import com.viaversion.viabackwards.api.rewriters.BackwardsRegistryRewriter;
import com.viaversion.viabackwards.api.rewriters.text.NBTComponentRewriter;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_21_11;
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.chunk.ChunkType26_1;
import com.viaversion.viaversion.api.type.types.version.VersionedTypes;
import com.viaversion.viaversion.api.type.types.version.VersionedTypesHolder;
import com.viaversion.viaversion.data.entity.EntityTrackerBase;
import com.viaversion.viaversion.data.item.ItemHasherBase;
import com.viaversion.viaversion.protocols.v1_21_11to26_1.Protocol1_21_11To26_1;
import com.viaversion.viaversion.protocols.v1_21_11to26_1.packet.ClientboundPacket26_1;
import com.viaversion.viaversion.protocols.v1_21_11to26_1.packet.ClientboundPackets26_1;
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.ServerboundPackets1_21_6;
import com.viaversion.viaversion.protocols.v1_21_7to1_21_9.packet.ClientboundConfigurationPackets1_21_9;
import com.viaversion.viaversion.protocols.v1_21_7to1_21_9.packet.ServerboundConfigurationPackets1_21_9;
import com.viaversion.viaversion.protocols.v1_21_7to1_21_9.packet.ServerboundPacket1_21_9;
import com.viaversion.viaversion.protocols.v26_2to26_3.rewriter.RecipeDisplayRewriter26_3;
import com.viaversion.viaversion.rewriter.BlockRewriter;
import com.viaversion.viaversion.rewriter.ParticleRewriter;
import com.viaversion.viaversion.rewriter.RecipeDisplayRewriter;
@@ -63,7 +66,7 @@ final class Protocol99_1To98_1 extends BackwardsProtocol<ClientboundPacket26_1,
private final TagRewriter<ClientboundPacket26_1> tagRewriter = new TagRewriter<>(this);
private final BackwardsRegistryRewriter registryDataRewriter = new BackwardsRegistryRewriter(this);
private final BlockRewriter<ClientboundPacket26_1> blockRewriter = new BlockRewriter1_21_5<>(this, ChunkType26_1::new);
private final RecipeDisplayRewriter<ClientboundPacket26_1> recipeRewriter = new RecipeDisplayRewriter26_3<>(this);
private final RecipeDisplayRewriter<ClientboundPacket26_1> recipeRewriter = new RecipeDisplayRewriter1_21_5<>(this);
public Protocol99_1To98_1() {
super(ClientboundPacket26_1.class, ClientboundPacket26_1.class, ServerboundPacket1_21_9.class, ServerboundPacket1_21_9.class);
@@ -72,23 +75,14 @@ final class Protocol99_1To98_1 extends BackwardsProtocol<ClientboundPacket26_1,
@Override
protected void registerPackets() {
super.registerPackets();
// Remove newly synchronized registries to prevent errors on older clients
//registryDataRewriter.remove("worldgen/block_state_provider");
}
@Override
public void init(final UserConnection connection) {
addEntityTracker(connection);
addItemHasher(connection);
addEntityTracker(connection, new EntityTrackerBase(connection, EntityTypes1_21_11.PLAYER));
connection.addItemHasher(this.getClass(), new ItemHasherBase(this, connection));
}
// If data beyond the tracker and hasher is required
//@Override
//public ProtocolStorablesBase createStorables() {
// return new ProtocolStorables99_1();
//}
@Override
public BackwardsMappingData getMappingData() {
return MAPPINGS;
@@ -98,8 +98,8 @@ public class Protocol1_10To1_9_3 extends BackwardsProtocol<ClientboundPackets1_9
@Override
public void init(UserConnection user) {
addEntityTracker(user, new EntityTrackerBase(user, EntityTypes1_10.EntityType.PLAYER));
user.storables(this).setClientWorld(new ClientWorld());
user.addEntityTracker(this.getClass(), new EntityTrackerBase(user, EntityTypes1_10.EntityType.PLAYER));
user.addClientWorld(this.getClass(), new ClientWorld());
}
@Override
@@ -50,7 +50,7 @@ public class BlockItemPacketRewriter1_10 extends LegacyBlockItemRewriter<Clientb
registerSetCreativeModeSlot(ServerboundPackets1_9_3.SET_CREATIVE_MODE_SLOT);
protocol.registerClientbound(ClientboundPackets1_9_3.LEVEL_CHUNK, wrapper -> {
ClientWorld clientWorld = wrapper.user().storables(protocol).clientWorld();
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_10To1_9_3.class);
ChunkType1_9_3 type = ChunkType1_9_3.forEnvironment(clientWorld.getEnvironment());
Chunk chunk = wrapper.passthrough(type);
@@ -39,8 +39,8 @@ public class Protocol1_11_1To1_11 extends BackwardsProtocol<ClientboundPackets1_
@Override
public void init(UserConnection user) {
addEntityTracker(user, new EntityTrackerBase(user, EntityTypes1_11.EntityType.PLAYER));
user.storables(this).setClientWorld(new ClientWorld());
user.addEntityTracker(this.getClass(), new EntityTrackerBase(user, EntityTypes1_11.EntityType.PLAYER));
user.addClientWorld(this.getClass(), new ClientWorld());
}
@Override
@@ -56,8 +56,8 @@ public class Protocol1_11To1_10 extends BackwardsProtocol<ClientboundPackets1_9_
@Override
public void init(UserConnection user) {
addEntityTracker(user, new EntityTrackerBase(user, EntityTypes1_11.EntityType.PLAYER));
user.storables(this).setClientWorld(new ClientWorld());
user.addEntityTracker(this.getClass(), new EntityTrackerBase(user, EntityTypes1_11.EntityType.PLAYER));
user.addClientWorld(this.getClass(), new ClientWorld());
if (!user.has(WindowTracker.class)) {
user.put(new WindowTracker());
@@ -22,39 +22,27 @@ import com.viaversion.viaversion.libs.fastutil.ints.Int2IntOpenHashMap;
public class SplashPotionMappings1_10 {
private static final Int2IntMap DATA = new Int2IntOpenHashMap(26, 0.99F);
private static final Int2IntMap DATA = new Int2IntOpenHashMap(14, 0.99F);
static {
DATA.defaultReturnValue(-1);
DATA.put(0x1F1FA1, 5); // night vision
DATA.put(0xC2FF66, 5); // night vision 1.19.4
DATA.put(0x7F8392, 7); // invisibility
DATA.put(0xF6F6F6, 7); // invisibility 1.19.4
DATA.put(0x22FF4C, 9); // jump boost
DATA.put(0xFDFF84, 9); // jump boost 1.19.4
DATA.put(0xE49A3A, 12); // fire resistance
DATA.put(0xFF9900, 12); // fire resistance 1.19.4
DATA.put(0x7CAFC6, 14); // swiftness
DATA.put(0x33EBFF, 14); // swiftness 1.19.4
DATA.put(0x5A6C81, 17); // slowness
DATA.put(0x8BAFE0, 17); // slowness 1.19.4
DATA.put(0x2E5299, 19); // water breathing
DATA.put(0x98DAC0, 19); // water breathing 1.19.4
DATA.put(0xF82423, 21); // instant health
DATA.put(0x430A09, 23); // instant damage
DATA.put(0xA9656A, 23); // instant damage 1.19.4
DATA.put(0x4E9331, 25); // poison
DATA.put(0x87A363, 25); // poison 1.19.4
DATA.put(0xCD5CAB, 28); // regeneration
DATA.put(0x932423, 31); // strength
DATA.put(0xFFC700, 31); // strength 1.19.4
DATA.put(0x484D48, 34); // weakness
DATA.put(0x339900, 36); // luck
DATA.put(0x59C106, 36); // luck 1.19.4
DATA.put(2039713, 5); // night vision
DATA.put(8356754, 7); // invisibility
DATA.put(2293580, 9); // jump boost
DATA.put(14981690, 12); // fire resistance
DATA.put(8171462, 14); // swiftness
DATA.put(5926017, 17); // slowness
DATA.put(3035801, 19); // water breathing
DATA.put(16262179, 21); // instant health
DATA.put(4393481, 23); // instant damage
DATA.put(5149489, 25); // poison
DATA.put(13458603, 28); // regeneration
DATA.put(9643043, 31); // strength
DATA.put(4738376, 34); // weakness
DATA.put(3381504, 36); // luck
}
public static int getOldData(int data) {
// newer servers send as ARGB
return DATA.get(data & 0xFFFFFF);
return DATA.get(data);
}
}
@@ -28,7 +28,7 @@ import com.viaversion.viabackwards.protocol.v1_11to1_10.storage.ChestedHorseStor
import com.viaversion.viabackwards.protocol.v1_11to1_10.storage.WindowTracker;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.entity.EntityTracker;
import com.viaversion.viaversion.api.data.entity.TrackedEntity;
import com.viaversion.viaversion.api.data.entity.StoredEntityData;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_11;
@@ -40,6 +40,7 @@ import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_9_3;
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;
import com.viaversion.viaversion.util.IdAndData;
import java.util.Arrays;
import java.util.Optional;
@@ -146,7 +147,7 @@ public class BlockItemPacketRewriter1_11 extends LegacyBlockItemRewriter<Clientb
registerSetCreativeModeSlot(ServerboundPackets1_9_3.SET_CREATIVE_MODE_SLOT);
protocol.registerClientbound(ClientboundPackets1_9_3.LEVEL_CHUNK, wrapper -> {
ClientWorld clientWorld = wrapper.user().storables(protocol).clientWorld();
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_11To1_10.class);
ChunkType1_9_3 type = ChunkType1_9_3.forEnvironment(clientWorld.getEnvironment()); // Use the 1.10 Chunk type since nothing changed.
Chunk chunk = wrapper.passthrough(type);
@@ -251,7 +252,7 @@ public class BlockItemPacketRewriter1_11 extends LegacyBlockItemRewriter<Clientb
@Override
protected void registerRewrites() {
// Handle spawner block entity (map to itself with custom handler)
MappedLegacyBlockItem data = blockReplacements.computeIfAbsent(compress(52, -1), s -> new MappedLegacyBlockItem(52, (short) -1, null, MappedLegacyBlockItem.Type.BLOCK));
MappedLegacyBlockItem data = itemReplacements.computeIfAbsent(IdAndData.toRawData(52), s -> new MappedLegacyBlockItem(52));
data.setBlockEntityHandler((b, tag) -> EntityMappings1_11.toClientSpawner(tag, true));
enchantmentRewriter = new LegacyEnchantmentRewriter(nbtTagName());
@@ -294,9 +295,9 @@ public class BlockItemPacketRewriter1_11 extends LegacyBlockItemRewriter<Clientb
private boolean isLlama(UserConnection user) {
WindowTracker tracker = user.get(WindowTracker.class);
if (tracker.getInventory() != null && tracker.getInventory().equals("EntityHorse")) {
EntityTracker entTracker = user.getEntityTracker(protocol);
TrackedEntity entityData = entTracker.entity(tracker.getEntityId());
return entityData != null && entityData.entityType().is(EntityTypes1_11.EntityType.LLAMA);
EntityTracker entTracker = user.getEntityTracker(Protocol1_11To1_10.class);
StoredEntityData entityData = entTracker.entityData(tracker.getEntityId());
return entityData != null && entityData.type().is(EntityTypes1_11.EntityType.LLAMA);
}
return false;
}
@@ -304,8 +305,8 @@ public class BlockItemPacketRewriter1_11 extends LegacyBlockItemRewriter<Clientb
private Optional<ChestedHorseStorage> getChestedHorse(UserConnection user) {
WindowTracker tracker = user.get(WindowTracker.class);
if (tracker.getInventory() != null && tracker.getInventory().equals("EntityHorse")) {
EntityTracker entTracker = user.getEntityTracker(protocol);
TrackedEntity entityData = entTracker.entity(tracker.getEntityId());
EntityTracker entTracker = user.getEntityTracker(Protocol1_11To1_10.class);
StoredEntityData entityData = entTracker.entityData(tracker.getEntityId());
if (entityData != null)
return Optional.of(entityData.get(ChestedHorseStorage.class));
}
@@ -23,6 +23,7 @@ import com.viaversion.viabackwards.api.rewriters.LegacyEntityRewriter;
import com.viaversion.viabackwards.protocol.v1_11to1_10.Protocol1_11To1_10;
import com.viaversion.viabackwards.protocol.v1_11to1_10.data.SplashPotionMappings1_10;
import com.viaversion.viabackwards.protocol.v1_11to1_10.storage.ChestedHorseStorage;
import com.viaversion.viaversion.api.data.entity.StoredEntityData;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_11;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
@@ -258,9 +259,9 @@ public class EntityPacketRewriter1_11 extends LegacyEntityRewriter<ClientboundPa
// Handle horse flags
filter().type(EntityTypes1_11.EntityType.ABSTRACT_HORSE).index(13).handler((event, data) -> {
StoredEntityData entityData = storedEntityData(event);
byte b = (byte) data.getValue();
final ChestedHorseStorage chestedHorseStorage = event.trackedEntity().get(ChestedHorseStorage.class);
if (chestedHorseStorage != null && chestedHorseStorage.isChested()) {
if (entityData.has(ChestedHorseStorage.class) && entityData.get(ChestedHorseStorage.class).isChested()) {
b |= 0x08; // Chested
data.setValue(b);
}
@@ -268,8 +269,9 @@ public class EntityPacketRewriter1_11 extends LegacyEntityRewriter<ClientboundPa
// Create chested horse storage
filter().type(EntityTypes1_11.EntityType.CHESTED_HORSE).handler((event, data) -> {
if (!event.trackedEntity().has(ChestedHorseStorage.class)) {
event.trackedEntity().put(new ChestedHorseStorage());
StoredEntityData entityData = storedEntityData(event);
if (!entityData.has(ChestedHorseStorage.class)) {
entityData.put(new ChestedHorseStorage());
}
});
@@ -278,7 +280,8 @@ public class EntityPacketRewriter1_11 extends LegacyEntityRewriter<ClientboundPa
// Handle chested horse
filter().type(EntityTypes1_11.EntityType.CHESTED_HORSE).index(15).handler((event, data) -> {
ChestedHorseStorage storage = event.trackedEntity().get(ChestedHorseStorage.class);
StoredEntityData entityData = storedEntityData(event);
ChestedHorseStorage storage = entityData.get(ChestedHorseStorage.class);
boolean b = (boolean) data.getValue();
storage.setChested(b);
event.cancel();
@@ -286,7 +289,8 @@ public class EntityPacketRewriter1_11 extends LegacyEntityRewriter<ClientboundPa
// Get rid of Liama entity data
filter().type(EntityTypes1_11.EntityType.LLAMA).handler((event, data) -> {
ChestedHorseStorage storage = event.trackedEntity().get(ChestedHorseStorage.class);
StoredEntityData entityData = storedEntityData(event);
ChestedHorseStorage storage = entityData.get(ChestedHorseStorage.class);
int index = event.index();
// Store them for later (:
@@ -18,9 +18,7 @@
package com.viaversion.viabackwards.protocol.v1_11to1_10.storage;
import com.viaversion.viaversion.api.connection.StorableObject;
public final class ChestedHorseStorage implements StorableObject {
public class ChestedHorseStorage {
private boolean chested;
private int liamaStrength;
private int liamaCarpetColor = -1;
@@ -71,8 +71,8 @@ public class Protocol1_12To1_11_1 extends BackwardsProtocol<ClientboundPackets1_
@Override
public void init(UserConnection user) {
addEntityTracker(user, new EntityTrackerBase(user, EntityTypes1_12.EntityType.PLAYER));
user.storables(this).setClientWorld(new ClientWorld());
user.addEntityTracker(this.getClass(), new EntityTrackerBase(user, EntityTypes1_12.EntityType.PLAYER));
user.addClientWorld(this.getClass(), new ClientWorld());
user.put(new ShoulderTracker(user));
}
@@ -18,10 +18,8 @@
package com.viaversion.viabackwards.protocol.v1_12to1_11_1.rewriter;
import com.google.common.primitives.Ints;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.IntArrayTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.LongArrayTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
@@ -133,7 +131,7 @@ public class BlockItemPacketRewriter1_12 extends LegacyBlockItemRewriter<Clientb
registerSetCreativeModeSlot(ServerboundPackets1_9_3.SET_CREATIVE_MODE_SLOT);
protocol.registerClientbound(ClientboundPackets1_12.LEVEL_CHUNK, wrapper -> {
ClientWorld clientWorld = wrapper.user().storables(protocol).clientWorld();
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_12To1_11_1.class);
ChunkType1_9_3 type = ChunkType1_9_3.forEnvironment(clientWorld.getEnvironment()); // Use the 1.9.4 Chunk type since nothing changed.
Chunk chunk = wrapper.passthrough(type);
@@ -232,30 +230,6 @@ public class BlockItemPacketRewriter1_12 extends LegacyBlockItemRewriter<Clientb
backupTag.put(entry.getKey(), fromLongArrayTag(tag));
iterator.remove();
hasLongArrayTag = true;
} else if (entry.getValue() instanceof ListTag<?> tag) {
if (tag.getElementType() == LongArrayTag.class) {
// Lists can't hold mixed tag types, so the whole list has to be removed
ListTag<IntArrayTag> intArrays = new ListTag<>(IntArrayTag.class);
for (Tag longArrayTag : tag) {
intArrays.add(fromLongArrayTag((LongArrayTag) longArrayTag));
}
backupTag.put(entry.getKey(), intArrays);
iterator.remove();
hasLongArrayTag = true;
} else if (tag.getElementType() == CompoundTag.class) {
// Backed up by list index
CompoundTag listBackupTag = new CompoundTag();
for (int i = 0; i < tag.size(); i++) {
CompoundTag nestedBackupTag = new CompoundTag();
if (handleNbtToClient((CompoundTag) tag.get(i), nestedBackupTag)) {
listBackupTag.put(Integer.toString(i), nestedBackupTag);
}
}
if (!listBackupTag.isEmpty()) {
backupTag.put(entry.getKey(), listBackupTag);
hasLongArrayTag = true;
}
}
}
}
return hasLongArrayTag;
@@ -278,33 +252,11 @@ public class BlockItemPacketRewriter1_12 extends LegacyBlockItemRewriter<Clientb
private void handleNbtToServer(CompoundTag compoundTag, CompoundTag backupTag) {
// Restore the removed long array tags
for (Map.Entry<String, Tag> entry : backupTag) {
if (entry.getValue() instanceof CompoundTag nestedBackupTag) {
Tag tag = compoundTag.get(entry.getKey());
if (tag instanceof CompoundTag nestedTag) {
handleNbtToServer(nestedTag, nestedBackupTag);
} else if (tag instanceof ListTag<?> listTag) {
handleListToServer(listTag, nestedBackupTag);
}
} else if (entry.getValue() instanceof IntArrayTag intArrayTag) {
compoundTag.put(entry.getKey(), fromIntArrayTag(intArrayTag));
} else if (entry.getValue() instanceof ListTag<?> intArrays) {
ListTag<LongArrayTag> longArrays = new ListTag<>(LongArrayTag.class);
for (Tag intArrayTag : intArrays) {
if (intArrayTag instanceof IntArrayTag) {
longArrays.add(fromIntArrayTag((IntArrayTag) intArrayTag));
}
}
compoundTag.put(entry.getKey(), longArrays);
}
}
}
private void handleListToServer(ListTag<?> listTag, CompoundTag backupTag) {
for (Map.Entry<String, Tag> entry : backupTag) {
Integer index = Ints.tryParse(entry.getKey());
if (index != null && index >= 0 && index < listTag.size()
&& listTag.get(index) instanceof CompoundTag nestedTag && entry.getValue() instanceof CompoundTag nestedBackupTag) {
handleNbtToServer(nestedTag, nestedBackupTag);
if (entry.getValue() instanceof CompoundTag) {
CompoundTag nestedTag = compoundTag.getCompoundTag(entry.getKey());
handleNbtToServer(nestedTag, (CompoundTag) entry.getValue());
} else {
compoundTag.put(entry.getKey(), fromIntArrayTag((IntArrayTag) entry.getValue()));
}
}
}
@@ -323,7 +275,7 @@ public class BlockItemPacketRewriter1_12 extends LegacyBlockItemRewriter<Clientb
private LongArrayTag fromIntArrayTag(IntArrayTag tag) {
long[] longArray = new long[tag.length() / 2];
int[] intArray = tag.getValue();
for (int i = 0, j = 0; j < longArray.length; i += 2, j++) {
for (int i = 0, j = 0; i < intArray.length; i += 2, j++) {
longArray[j] = (long) intArray[i] << 32 | ((long) intArray[i + 1] & 0xFFFFFFFFL);
}
return new LongArrayTag(longArray);
@@ -23,6 +23,7 @@ import com.viaversion.viabackwards.api.rewriters.LegacyEntityRewriter;
import com.viaversion.viabackwards.protocol.v1_12to1_11_1.Protocol1_12To1_11_1;
import com.viaversion.viabackwards.protocol.v1_12to1_11_1.storage.ParrotStorage;
import com.viaversion.viabackwards.protocol.v1_12to1_11_1.storage.ShoulderTracker;
import com.viaversion.viaversion.api.data.entity.StoredEntityData;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_12;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
@@ -117,7 +118,7 @@ public class EntityPacketRewriter1_12 extends LegacyEntityRewriter<ClientboundPa
map(Types.INT); // 2 - Dimension
handler(getDimensionHandler(1));
handler(playerTrackerHandler());
handler(getPlayerTrackerHandler());
handler(wrapper -> {
ShoulderTracker tracker = wrapper.user().get(ShoulderTracker.class);
@@ -207,14 +208,16 @@ public class EntityPacketRewriter1_12 extends LegacyEntityRewriter<ClientboundPa
// Create Parrot storage
filter().type(EntityTypes1_12.EntityType.PARROT).handler((event, data) -> {
if (!event.trackedEntity().has(ParrotStorage.class)) {
event.trackedEntity().put(new ParrotStorage());
StoredEntityData entityData = storedEntityData(event);
if (!entityData.has(ParrotStorage.class)) {
entityData.put(new ParrotStorage());
}
});
// Parrot remove animal entity data
filter().type(EntityTypes1_12.EntityType.PARROT).cancel(12); // Is baby
filter().type(EntityTypes1_12.EntityType.PARROT).index(13).handler((event, data) -> {
ParrotStorage storage = event.trackedEntity().get(ParrotStorage.class);
StoredEntityData entityData = storedEntityData(event);
ParrotStorage storage = entityData.get(ParrotStorage.class);
boolean isSitting = (((byte) data.getValue()) & 0x01) == 0x01;
boolean isTamed = (((byte) data.getValue()) & 0x04) == 0x04;
@@ -18,9 +18,7 @@
package com.viaversion.viabackwards.protocol.v1_12to1_11_1.storage;
import com.viaversion.viaversion.api.connection.StorableObject;
public final class ParrotStorage implements StorableObject {
public class ParrotStorage {
private boolean tamed = true;
private boolean sitting = true;
@@ -159,8 +159,8 @@ public class Protocol1_13_1To1_13 extends BackwardsProtocol<ClientboundPackets1_
@Override
public void init(UserConnection user) {
user.storables(this).setEntityTracker(new EntityTrackerBase(user, EntityTypes1_13.EntityType.PLAYER));
user.storables(this).setClientWorld(new ClientWorld());
user.addEntityTracker(getClass(), new EntityTrackerBase(user, EntityTypes1_13.EntityType.PLAYER));
user.addClientWorld(getClass(), new ClientWorld());
}
@Override
@@ -34,7 +34,7 @@ public class WorldPacketRewriter1_13_1 {
BlockRewriter<ClientboundPackets1_13> blockRewriter = BlockRewriter.legacy(protocol);
protocol.registerClientbound(ClientboundPackets1_13.LEVEL_CHUNK, wrapper -> {
ClientWorld clientWorld = wrapper.user().storables(protocol).clientWorld();
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_13_1To1_13.class);
Chunk chunk = wrapper.passthrough(ChunkType1_13.forEnvironment(clientWorld.getEnvironment()));
blockRewriter.handleChunk(chunk);
@@ -28,8 +28,10 @@ import com.viaversion.viabackwards.protocol.v1_13to1_12_2.rewriter.BlockItemPack
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.rewriter.EntityPacketRewriter1_13;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.rewriter.PlayerPacketRewriter1_13;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.rewriter.SoundPacketRewriter1_13;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.storage.BackwardsBlockStorage;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.storage.NoteBlockStorage;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.storage.PlayerPositionStorage1_13;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.storage.ProtocolStorables1_13;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.storage.TabCompleteStorage;
import com.viaversion.viabackwards.utils.BackwardsProtocolLogger;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.UserConnection;
@@ -84,7 +86,7 @@ public class Protocol1_13To1_12_2 extends BackwardsProtocol<ClientboundPackets1_
super.registerPackets();
PaintingNames1_13.init();
Via.getManager().getProviders().register(BackwardsBlockEntityProvider.class, new BackwardsBlockEntityProvider(this));
Via.getManager().getProviders().register(BackwardsBlockEntityProvider.class, new BackwardsBlockEntityProvider());
translatableRewriter.registerLoginDisconnect();
translatableRewriter.registerBossEvent(ClientboundPackets1_13.BOSS_EVENT);
@@ -111,18 +113,17 @@ public class Protocol1_13To1_12_2 extends BackwardsProtocol<ClientboundPackets1_
@Override
public void init(UserConnection user) {
addEntityTracker(user, new EntityTrackerBase(user, EntityTypes1_13.EntityType.PLAYER));
final ProtocolStorables1_13 storables = user.storables(this);
storables.setClientWorld(new ClientWorld());
user.addEntityTracker(this.getClass(), new EntityTrackerBase(user, EntityTypes1_13.EntityType.PLAYER));
user.addClientWorld(this.getClass(), new ClientWorld());
if (ViaBackwards.getConfig().isFix1_13FacePlayer()) {
storables.setPlayerPositionStorage(new PlayerPositionStorage1_13());
user.put(new BackwardsBlockStorage());
user.put(new TabCompleteStorage());
if (ViaBackwards.getConfig().isFix1_13FacePlayer() && !user.has(PlayerPositionStorage1_13.class)) {
user.put(new PlayerPositionStorage1_13());
}
}
@Override
public ProtocolStorables1_13 createStorables() {
return new ProtocolStorables1_13();
user.put(new NoteBlockStorage());
}
@Override
@@ -18,15 +18,63 @@
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.viaversion.protocols.v1_12_2to1_13.blockconnections.ConnectionData;
import java.util.Map;
import java.util.StringJoiner;
public class PistonHandler implements BackwardsBlockEntityProvider.BackwardsBlockEntityHandler {
private final Object2IntMap<String> pistonIds = new Object2IntOpenHashMap<>();
public PistonHandler() {
pistonIds.defaultReturnValue(-1);
if (Via.getConfig().isServersideBlockConnections()) {
Map<String, Integer> keyToId = ConnectionData.getKeyToId();
for (Map.Entry<String, Integer> entry : keyToId.entrySet()) {
if (!entry.getKey().contains("piston")) {
continue;
}
addEntries(entry.getKey(), entry.getValue());
}
} else {
ListTag<StringTag> blockStates = MappingDataLoader.INSTANCE.loadNBT("blockstates-1.13.nbt").getListTag("blockstates", StringTag.class);
for (int id = 0; id < blockStates.size(); id++) {
StringTag state = blockStates.get(id);
String key = state.getValue();
if (!key.contains("piston")) {
continue;
}
addEntries(key, id);
}
}
}
// There doesn't seem to be a nicer way around it :(
private void addEntries(String data, int id) {
id = Protocol1_13To1_12_2.MAPPINGS.getNewBlockStateId(id);
pistonIds.put(data, id);
String substring = data.substring(10);
if (!substring.startsWith("piston") && !substring.startsWith("sticky_piston")) return;
// Swap properties and add them to the map
String[] split = data.substring(0, data.length() - 1).split("\\[");
String[] properties = split[1].split(",");
data = split[0] + "[" + properties[1] + "," + properties[0] + "]";
pistonIds.put(data, id);
}
@Override
public CompoundTag transform(int blockId, CompoundTag tag) {
CompoundTag blockState = tag.getCompoundTag("blockState");
@@ -35,7 +83,7 @@ public class PistonHandler implements BackwardsBlockEntityProvider.BackwardsBloc
String dataFromTag = getDataFromTag(blockState);
if (dataFromTag == null) return tag;
int id = Protocol1_13To1_12_2.MAPPINGS.getPistonIds().getInt(dataFromTag);
int id = pistonIds.getInt(dataFromTag);
if (id == -1) {
//TODO see why this could be null and if this is bad
return tag;
@@ -1,140 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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_13to1_12_2.data;
import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectMap;
import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectOpenHashMap;
// The mildly inconvenient alternative to the very inconvenient task of adding full 1.12 identifiers
public final class BackwardsItemMappings {
private static final Int2ObjectMap<String> MODEL_DATA_TO_NAME = new Int2ObjectOpenHashMap<>();
static {
add("acacia_button", 245);
add("birch_button", 243);
add("spruce_button", 242);
add("jungle_button", 244);
add("dark_oak_button", 246);
add("acacia_trapdoor", 191);
add("birch_trapdoor", 189);
add("spruce_trapdoor", 188);
add("jungle_trapdoor", 190);
add("dark_oak_trapdoor", 192);
add("acacia_pressure_plate", 164);
add("birch_pressure_plate", 162);
add("spruce_pressure_plate", 161);
add("jungle_pressure_plate", 163);
add("dark_oak_pressure_plate", 165);
add("acacia_boat", 762);
add("birch_boat", 760);
add("spruce_boat", 759);
add("jungle_boat", 761);
add("dark_oak_boat", 763);
add("blue_ice", 453);
add("pufferfish_bucket", 547);
add("salmon_bucket", 548);
add("cod_bucket", 549);
add("tropical_fish_bucket", 550);
add("heart_of_the_sea", 784);
add("nautilus_shell", 783);
add("phantom_membrane", 782);
add("turtle_helmet", 465);
add("turtle_egg", 427);
add("scute", 466);
add("trident", 781);
add("sea_pickle", 80);
add("seagrass", 79);
add("conduit", 454);
add("kelp", 554);
add("dried_kelp", 611);
add("dried_kelp_block", 555);
add("stripped_oak_log", 38);
add("stripped_acacia_log", 42);
add("stripped_birch_log", 40);
add("stripped_spruce_log", 39);
add("stripped_jungle_log", 41);
add("stripped_dark_oak_log", 43);
add("stripped_oak_wood", 44);
add("stripped_acacia_wood", 48);
add("stripped_birch_wood", 46);
add("stripped_spruce_wood", 45);
add("stripped_jungle_wood", 47);
add("stripped_dark_oak_wood", 49);
add("oak_wood", 50);
add("spruce_wood", 51);
add("birch_wood", 52);
add("jungle_wood", 53);
add("acacia_wood", 54);
add("dark_oak_wood", 55);
add("prismarine_slab", 128);
add("prismarine_brick_slab", 129);
add("dark_prismarine_slab", 130);
add("prismarine_stairs", 346);
add("prismarine_brick_stairs", 347);
add("dark_prismarine_stairs", 348);
add("drowned_spawn_egg", 643);
add("phantom_spawn_egg", 658);
add("dolphin_spawn_egg", 641);
add("turtle_spawn_egg", 674);
add("cod_spawn_egg", 638);
add("salmon_spawn_egg", 663);
add("pufferfish_spawn_egg", 661);
add("tropical_fish_spawn_egg", 673);
add("tube_coral", 438);
add("brain_coral", 439);
add("bubble_coral", 440);
add("fire_coral", 441);
add("horn_coral", 442);
add("tube_coral_fan", 443);
add("brain_coral_fan", 444);
add("bubble_coral_fan", 445);
add("fire_coral_fan", 446);
add("horn_coral_fan", 447);
add("dead_tube_coral_fan", 448);
add("dead_brain_coral_fan", 449);
add("dead_bubble_coral_fan", 450);
add("dead_fire_coral_fan", 451);
add("dead_horn_coral_fan", 452);
add("dead_tube_coral_block", 428);
add("dead_brain_coral_block", 429);
add("dead_bubble_coral_block", 430);
add("dead_fire_coral_block", 431);
add("dead_horn_coral_block", 432);
add("tube_coral_block", 433);
add("brain_coral_block", 434);
add("bubble_coral_block", 435);
add("fire_coral_block", 436);
add("horn_coral_block", 437);
add("smooth_quartz", 131);
add("smooth_red_sandstone", 132);
add("smooth_sandstone", 133);
add("smooth_stone", 134);
add("pumpkin", 181);
add("mushroom_stem", 205);
add("debug_stick", 768);
}
public static String identifier(final int id) {
return MODEL_DATA_TO_NAME.get(id);
}
private static void add(final String key, final int id) {
MODEL_DATA_TO_NAME.put(id, key);
}
}
@@ -19,18 +19,10 @@
package com.viaversion.viabackwards.protocol.v1_13to1_12_2.data;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.NumberTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viabackwards.api.data.BackwardsMappingData;
import com.viaversion.viabackwards.api.data.MappedItem;
import com.viaversion.viaversion.api.data.MappingDataLoader;
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.viaversion.libs.fastutil.objects.Object2IntOpenHashMap;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.Protocol1_12_2To1_13;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.blockconnections.ConnectionData;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.data.BlockStates1_13;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.data.StatisticMappings1_13;
import java.util.HashMap;
import java.util.Map;
@@ -38,7 +30,6 @@ import java.util.Map;
public class BackwardsMappingData1_13 extends BackwardsMappingData {
private final Int2ObjectMap<String> statisticMappings = new Int2ObjectOpenHashMap<>();
private final Map<String, String> translateMappings = new HashMap<>();
private final Object2IntMap<String> pistonIds = new Object2IntOpenHashMap<>();
public BackwardsMappingData1_13() {
super("1.13", "1.12", Protocol1_12_2To1_13.class);
@@ -54,61 +45,21 @@ public class BackwardsMappingData1_13 extends BackwardsMappingData {
for (Map.Entry<String, String> entry : Protocol1_12_2To1_13.MAPPINGS.getTranslateMapping().entrySet()) {
translateMappings.put(entry.getValue(), entry.getKey());
}
pistonIds.defaultReturnValue(-1);
Object2IntMap<String> keyToId = ConnectionData.getKeyToId();
if (!keyToId.isEmpty()) {
for (final Object2IntMap.Entry<String> entry : keyToId.object2IntEntrySet()) {
if (!entry.getKey().contains("piston")) {
continue;
}
addPistonEntries(entry.getKey(), entry.getIntValue());
}
} else { // not loaded by VV
CompoundTag blockStatesData = MappingDataLoader.INSTANCE.loadNBT("blockstates-1.13.nbt");
BlockStates1_13.forEach(blockStatesData, (key, id) -> {
if (key.contains("piston")) {
addPistonEntries(key, id);
}
});
}
}
@Override
protected void loadBackwardsItemMappings(final CompoundTag itemCustomModelDatas) {
for (final Map.Entry<String, Tag> entry : itemCustomModelDatas.entrySet()) {
final int id = Integer.parseInt(entry.getKey());
final int customModelData = ((NumberTag) entry.getValue()).asInt();
final String identifier = BackwardsItemMappings.identifier(id);
final String fallbackName = unmappedVersion + " " + nameFromIdentifier(identifier);
backwardsItemMappings.put(id, new MappedItem(getNewItemId(id), identifier, fallbackName, customModelData));
}
}
private void addPistonEntries(String data, int id) {
id = getNewBlockStateId(id);
pistonIds.put(data, id);
String substring = data.substring(10);
if (!substring.startsWith("piston") && !substring.startsWith("sticky_piston")) return;
// Swap properties and add them to the map
String[] split = data.substring(0, data.length() - 1).split("\\[");
String[] properties = split[1].split(",");
data = split[0] + "[" + properties[1] + "," + properties[0] + "]";
pistonIds.put(data, id);
}
@Override
public int getNewBlockStateId(int id) {
// Always map to unpowered_comparator; powered_comparator is unused in 1.12 https://github.com/ViaVersion/ViaBackwards/issues/1222
// Comparator funkyness: https://github.com/ViaVersion/ViaBackwards/issues/524
if (id >= 5635 && id <= 5650) {
int mappedId = super.getNewBlockStateId(id);
if (mappedId >= 2400) {
mappedId -= 16;
if (id < 5639) {
id += 4;
} else if (id < 5643) {
id -= 4;
} else if (id < 5647) {
id += 4;
} else {
id -= 4;
}
return mappedId;
}
int mappedId = super.getNewBlockStateId(id);
@@ -134,8 +85,4 @@ public class BackwardsMappingData1_13 extends BackwardsMappingData {
public Map<String, String> getTranslateMappings() {
return translateMappings;
}
public Object2IntMap<String> getPistonIds() {
return pistonIds;
}
}
@@ -57,6 +57,6 @@ public class PaintingNames1_13 {
}
public static String getStringId(int id) {
return PAINTINGS.getOrDefault(id, "Kebab");
return PAINTINGS.getOrDefault(id, "kebab");
}
}
@@ -76,11 +76,6 @@ public class ParticleIdMappings1_12_2 {
float b = wrapper.read(Types.FLOAT);
float scale = wrapper.read(Types.FLOAT);
if (r == 0.0) {
// In 1.12.2 and below, a zero x offset becomes r = 1.0
r = Float.MIN_NORMAL;
}
wrapper.set(Types.FLOAT, 3, r); // 5 - Offset X index=3
wrapper.set(Types.FLOAT, 4, g); // 6 - Offset Y index=4
wrapper.set(Types.FLOAT, 5, b); // 7 - Offset Z index=5
@@ -20,7 +20,6 @@ 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.Protocol1_13To1_12_2;
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,7 +27,6 @@ import com.viaversion.viabackwards.protocol.v1_13to1_12_2.block_entity_handlers.
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.block_entity_handlers.SkullHandler;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.block_entity_handlers.SpawnerHandler;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.storage.BackwardsBlockStorage;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.storage.ProtocolStorables1_13;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.BlockPosition;
import com.viaversion.viaversion.api.platform.providers.Provider;
@@ -38,10 +36,8 @@ import java.util.Map;
public class BackwardsBlockEntityProvider implements Provider {
private final Map<String, BackwardsBlockEntityProvider.BackwardsBlockEntityHandler> handlers = new HashMap<>();
private final Protocol1_13To1_12_2 protocol;
public BackwardsBlockEntityProvider(final Protocol1_13To1_12_2 protocol) {
this.protocol = protocol;
public BackwardsBlockEntityProvider() {
handlers.put("flower_pot", new FlowerPotHandler()); // TODO requires special treatment, manually send
handlers.put("bed", new BedHandler());
handlers.put("banner", new BannerHandler());
@@ -79,7 +75,7 @@ public class BackwardsBlockEntityProvider implements Provider {
return tag;
}
BackwardsBlockStorage storage = user.<ProtocolStorables1_13>storables(protocol).backwardsBlockStorage();
BackwardsBlockStorage storage = user.get(BackwardsBlockStorage.class);
Integer blockId = storage.get(position);
if (blockId == null) {
return tag;
@@ -34,7 +34,6 @@ import 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.viabackwards.protocol.v1_13to1_12_2.storage.BackwardsBlockStorage;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.storage.NoteBlockStorage;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.storage.ProtocolStorables1_13;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.BlockChangeRecord;
@@ -141,8 +140,7 @@ public class BlockItemPacketRewriter1_13 extends BackwardsItemRewriter<Clientbou
blockId = blockId - 483 + 219;
if (blockId == 25) { // Note block
ProtocolStorables1_13 storables = wrapper.user().storables(protocol);
final NoteBlockStorage noteBlockStorage = storables.noteBlockStorage();
final NoteBlockStorage noteBlockStorage = wrapper.user().get(NoteBlockStorage.class);
final BlockPosition position = wrapper.get(Types.BLOCK_POSITION1_8, 0);
final Pair<Integer, Integer> update = noteBlockStorage.getNoteBlockUpdate(position);
@@ -187,8 +185,7 @@ public class BlockItemPacketRewriter1_13 extends BackwardsItemRewriter<Clientbou
int chunkMinZ = wrapper.passthrough(Types.INT) << 4;
int chunkMaxX = chunkMinX + 15;
int chunkMaxZ = chunkMinZ + 15;
ProtocolStorables1_13 storables = wrapper.user().storables(protocol);
BackwardsBlockStorage blockStorage = storables.backwardsBlockStorage();
BackwardsBlockStorage blockStorage = wrapper.user().get(BackwardsBlockStorage.class);
blockStorage.getBlocks().entrySet().removeIf(entry -> {
BlockPosition position = entry.getKey();
return position.x() >= chunkMinX && position.z() >= chunkMinZ
@@ -205,15 +202,14 @@ public class BlockItemPacketRewriter1_13 extends BackwardsItemRewriter<Clientbou
handler(wrapper -> {
int blockState = wrapper.read(Types.VAR_INT);
BlockPosition position = wrapper.get(Types.BLOCK_POSITION1_8, 0);
ProtocolStorables1_13 storables = wrapper.user().storables(protocol);
// Note block special treatment
if (blockState >= 249 && blockState <= 748) { // Note block states id range
storables.noteBlockStorage().storeNoteBlockUpdate(position, blockState);
wrapper.user().get(NoteBlockStorage.class).storeNoteBlockUpdate(position, blockState);
}
// Store blocks
BackwardsBlockStorage storage = storables.backwardsBlockStorage();
BackwardsBlockStorage storage = wrapper.user().get(BackwardsBlockStorage.class);
storage.checkAndStore(position, blockState);
wrapper.write(Types.VAR_INT, protocol.getMappingData().getNewBlockStateId(blockState));
@@ -232,8 +228,7 @@ public class BlockItemPacketRewriter1_13 extends BackwardsItemRewriter<Clientbou
map(Types.INT); // 1 - Chunk Z
map(Types.BLOCK_CHANGE_ARRAY);
handler(wrapper -> {
ProtocolStorables1_13 storables = wrapper.user().storables(protocol);
BackwardsBlockStorage storage = storables.backwardsBlockStorage();
BackwardsBlockStorage storage = wrapper.user().get(BackwardsBlockStorage.class);
for (BlockChangeRecord record : wrapper.get(Types.BLOCK_CHANGE_ARRAY, 0)) {
int chunkX = wrapper.get(Types.INT, 0);
@@ -258,8 +253,7 @@ public class BlockItemPacketRewriter1_13 extends BackwardsItemRewriter<Clientbou
});
protocol.registerClientbound(ClientboundPackets1_13.LEVEL_CHUNK, wrapper -> {
ProtocolStorables1_13 storables = wrapper.user().storables(protocol);
ClientWorld clientWorld = storables.clientWorld();
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_13To1_12_2.class);
ChunkType1_9_3 type_old = ChunkType1_9_3.forEnvironment(clientWorld.getEnvironment());
ChunkType1_13 type = ChunkType1_13.forEnvironment(clientWorld.getEnvironment());
@@ -267,7 +261,7 @@ public class BlockItemPacketRewriter1_13 extends BackwardsItemRewriter<Clientbou
// Handle Block Entities before block rewrite
BackwardsBlockEntityProvider provider = Via.getManager().getProviders().get(BackwardsBlockEntityProvider.class);
BackwardsBlockStorage storage = storables.backwardsBlockStorage();
BackwardsBlockStorage storage = wrapper.user().get(BackwardsBlockStorage.class);
for (CompoundTag tag : chunk.getBlockEntities()) {
StringTag idTag = tag.getStringTag("id");
if (idTag == null) continue;
@@ -297,8 +291,6 @@ public class BlockItemPacketRewriter1_13 extends BackwardsItemRewriter<Clientbou
}
// Rewrite new blocks to old blocks
int baseX = chunk.getX() << 4;
int baseZ = chunk.getZ() << 4;
for (int i = 0; i < chunk.getSections().length; i++) {
ChunkSection section = chunk.getSections()[i];
if (section == null) {
@@ -306,21 +298,29 @@ public class BlockItemPacketRewriter1_13 extends BackwardsItemRewriter<Clientbou
}
DataPalette palette = section.palette(PaletteType.BLOCKS);
int baseY = i << 4;
// Flower pots require a special treatment, they are no longer block entities :(
palette.forEachMatchingCoordinate(FlowerPotHandler::isFlowah, idx -> {
int block = palette.idAt(idx);
BlockPosition pos = new BlockPosition(
ChunkSection.xFromIndex(idx) + baseX,
(short) (ChunkSection.yFromIndex(idx) + baseY),
ChunkSection.zFromIndex(idx) + baseZ
);
storage.checkAndStore(pos, block);
for (int y = 0; y < 16; y++) {
for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++) {
int block = palette.idAt(x, y, z);
CompoundTag nbt = provider.transform(wrapper.user(), pos, "minecraft:flower_pot");
chunk.getBlockEntities().add(nbt);
});
// Check if the block is a flower
if (FlowerPotHandler.isFlowah(block)) {
BlockPosition pos = new BlockPosition(
(x + (chunk.getX() << 4)),
(short) (y + (i << 4)),
(z + (chunk.getZ() << 4))
);
// Store block
storage.checkAndStore(pos, block);
CompoundTag nbt = provider.transform(wrapper.user(), pos, "minecraft:flower_pot");
chunk.getBlockEntities().add(nbt);
}
}
}
}
for (int j = 0; j < palette.size(); j++) {
int mappedBlockStateId = protocol.getMappingData().getNewBlockStateId(palette.idByIndex(j));
@@ -463,12 +463,8 @@ public class BlockItemPacketRewriter1_13 extends BackwardsItemRewriter<Clientbou
if (item.identifier() == 358) { // map
Tag mapTag = tag.remove("map");
if (!gotRawIdFromTag && mapTag instanceof NumberTag numberTag) {
item.setData((short) (numberTag.asInt() & 0x7FFF));
// Keep original ID if conversion is lossy
if (numberTag.asInt() > Short.MAX_VALUE) {
tag.put("map", numberTag);
}
if (!gotRawIdFromTag && mapTag instanceof NumberTag) {
item.setData(((NumberTag) mapTag).asShort());
}
}
@@ -671,9 +667,7 @@ public class BlockItemPacketRewriter1_13 extends BackwardsItemRewriter<Clientbou
}
if (item.identifier() == 358) { // map
if (tag == null) item.setTag(tag = new CompoundTag());
if (!tag.contains("map")) {
tag.putInt("map", item.data());
}
tag.putInt("map", item.data());
}
// NBT Changes
@@ -24,8 +24,9 @@ import com.viaversion.viabackwards.protocol.v1_13to1_12_2.Protocol1_13To1_12_2;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.data.EntityIdMappings1_12_2;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.data.PaintingNames1_13;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.data.ParticleIdMappings1_12_2;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.storage.BackwardsBlockStorage;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.storage.NoteBlockStorage;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.storage.PlayerPositionStorage1_13;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.storage.ProtocolStorables1_13;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.Particle;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
@@ -63,8 +64,7 @@ public class EntityPacketRewriter1_13 extends LegacyEntityRewriter<ClientboundPa
handler(wrapper -> {
if (!ViaBackwards.getConfig().isFix1_13FacePlayer()) return;
ProtocolStorables1_13 storables = wrapper.user().storables(protocol);
PlayerPositionStorage1_13 playerStorage = storables.playerPositionStorage();
PlayerPositionStorage1_13 playerStorage = wrapper.user().get(PlayerPositionStorage1_13.class);
byte bitField = wrapper.get(Types.BYTE, 0);
playerStorage.setX(toSet(bitField, 0, playerStorage.x(), wrapper.get(Types.DOUBLE, 0)));
playerStorage.setY(toSet(bitField, 1, playerStorage.y(), wrapper.get(Types.DOUBLE, 1)));
@@ -177,10 +177,8 @@ public class EntityPacketRewriter1_13 extends LegacyEntityRewriter<ClientboundPa
map(Types.VAR_INT);
map(Types.UUID);
handler(getTrackerHandler(EntityTypes1_13.EntityType.PAINTING));
handler(wrapper -> {
int entityId = wrapper.get(Types.VAR_INT, 0);
tracker(wrapper.user()).addEntity(entityId, EntityTypes1_13.EntityType.PAINTING);
int motive = wrapper.read(Types.VAR_INT);
String title = PaintingNames1_13.getStringId(motive);
wrapper.write(Types.STRING, title);
@@ -196,14 +194,13 @@ public class EntityPacketRewriter1_13 extends LegacyEntityRewriter<ClientboundPa
map(Types.INT); // 0 - Dimension ID
handler(wrapper -> {
ProtocolStorables1_13 storables = wrapper.user().storables(protocol);
ClientWorld clientWorld = storables.clientWorld();
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_13To1_12_2.class);
int dimensionId = wrapper.get(Types.INT, 0);
if (clientWorld.setEnvironment(dimensionId)) {
tracker(wrapper.user()).clearEntities();
storables.backwardsBlockStorage().clear();
storables.noteBlockStorage().clear();
wrapper.user().get(BackwardsBlockStorage.class).clear();
wrapper.user().get(NoteBlockStorage.class).clear();
}
});
}
@@ -224,8 +221,7 @@ public class EntityPacketRewriter1_13 extends LegacyEntityRewriter<ClientboundPa
final double y = wrapper.read(Types.DOUBLE);
final double z = wrapper.read(Types.DOUBLE);
ProtocolStorables1_13 storables = wrapper.user().storables(protocol);
PlayerPositionStorage1_13 positionStorage = storables.playerPositionStorage();
PlayerPositionStorage1_13 positionStorage = wrapper.user().get(PlayerPositionStorage1_13.class);
// Send teleport packet to client
PacketWrapper positionAndLook = wrapper.create(ClientboundPackets1_12_1.PLAYER_POSITION);
@@ -247,9 +243,10 @@ public class EntityPacketRewriter1_13 extends LegacyEntityRewriter<ClientboundPa
if (!ViaBackwards.getConfig().isFix1_13FacePlayer()) {
return;
}
ProtocolStorables1_13 storables = wrapper.user().storables(protocol);
storables.playerPositionStorage().setPosFromPacket(wrapper);
final double x = wrapper.passthrough(Types.DOUBLE);
final double y = wrapper.passthrough(Types.DOUBLE);
final double z = wrapper.passthrough(Types.DOUBLE);
wrapper.user().get(PlayerPositionStorage1_13.class).setPosition(x, y, z);
};
protocol.registerServerbound(ServerboundPackets1_12_1.MOVE_PLAYER_POS, movementRemapper); // Player Position
protocol.registerServerbound(ServerboundPackets1_12_1.MOVE_PLAYER_POS_ROT, movementRemapper); // Player Position And Look (serverbound)
@@ -355,14 +352,6 @@ public class EntityPacketRewriter1_13 extends LegacyEntityRewriter<ClientboundPa
event.cancel();
});
filter().dataType(EntityDataTypes1_12.OPTIONAL_BLOCK_STATE).handler(((event, data) -> {
final int blockState = data.value();
if (blockState != 0) {
final int combined = Protocol1_13To1_12_2.MAPPINGS.getNewBlockStateId(blockState);
data.setValue(((combined >> 4) & 0xFFF) | ((combined & 0xF) << 12));
}
}));
}
@Override
@@ -21,7 +21,6 @@ import com.google.common.base.Joiner;
import com.viaversion.viabackwards.ViaBackwards;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.Protocol1_13To1_12_2;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.data.ParticleIdMappings1_12_2;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.storage.ProtocolStorables1_13;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.storage.TabCompleteStorage;
import com.viaversion.viabackwards.utils.ChatUtil;
import com.viaversion.viaversion.api.Via;
@@ -143,8 +142,7 @@ public class PlayerPacketRewriter1_13 extends RewriterBase<Protocol1_13To1_12_2>
@Override
public void register() {
handler(packetWrapper -> {
ProtocolStorables1_13 storables = packetWrapper.user().storables(protocol);
TabCompleteStorage storage = storables.tabCompleteStorage();
TabCompleteStorage storage = packetWrapper.user().get(TabCompleteStorage.class);
int action = packetWrapper.passthrough(Types.VAR_INT);
int nPlayers = packetWrapper.passthrough(Types.VAR_INT);
for (int i = 0; i < nPlayers; i++) {
@@ -238,8 +236,7 @@ public class PlayerPacketRewriter1_13 extends RewriterBase<Protocol1_13To1_12_2>
protocol.registerClientbound(ClientboundPackets1_13.COMMANDS, null, wrapper -> {
wrapper.cancel();
ProtocolStorables1_13 storables = wrapper.user().storables(protocol);
TabCompleteStorage storage = storables.tabCompleteStorage();
TabCompleteStorage storage = wrapper.user().get(TabCompleteStorage.class);
if (!storage.commands().isEmpty()) {
storage.commands().clear();
@@ -277,8 +274,7 @@ public class PlayerPacketRewriter1_13 extends RewriterBase<Protocol1_13To1_12_2>
});
protocol.registerClientbound(ClientboundPackets1_13.COMMAND_SUGGESTIONS, wrapper -> {
ProtocolStorables1_13 storables = wrapper.user().storables(protocol);
TabCompleteStorage storage = storables.tabCompleteStorage();
TabCompleteStorage storage = wrapper.user().get(TabCompleteStorage.class);
if (storage.lastRequest() == null) {
wrapper.cancel();
return;
@@ -303,8 +299,7 @@ public class PlayerPacketRewriter1_13 extends RewriterBase<Protocol1_13To1_12_2>
});
protocol.registerServerbound(ServerboundPackets1_12_1.COMMAND_SUGGESTION, wrapper -> {
ProtocolStorables1_13 storables = wrapper.user().storables(protocol);
TabCompleteStorage storage = storables.tabCompleteStorage();
TabCompleteStorage storage = wrapper.user().get(TabCompleteStorage.class);
List<String> suggestions = new ArrayList<>();
String command = wrapper.read(Types.STRING);
@@ -18,6 +18,7 @@
package com.viaversion.viabackwards.protocol.v1_13to1_12_2.storage;
import com.viaversion.viaversion.api.connection.StorableObject;
import com.viaversion.viaversion.api.minecraft.BlockPosition;
import com.viaversion.viaversion.libs.fastutil.ints.IntOpenHashSet;
import com.viaversion.viaversion.libs.fastutil.ints.IntSet;
@@ -25,7 +26,7 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.checkerframework.checker.nullness.qual.Nullable;
public class BackwardsBlockStorage {
public class BackwardsBlockStorage implements StorableObject {
// This BlockStorage is very exclusive (;
private static final IntSet WHITELIST = new IntOpenHashSet(779);
@@ -17,12 +17,13 @@
*/
package com.viaversion.viabackwards.protocol.v1_13to1_12_2.storage;
import com.viaversion.viaversion.api.connection.StorableObject;
import com.viaversion.viaversion.api.minecraft.BlockPosition;
import com.viaversion.viaversion.libs.fastutil.objects.Object2IntMap;
import com.viaversion.viaversion.libs.fastutil.objects.Object2IntOpenHashMap;
import com.viaversion.viaversion.util.Pair;
public class NoteBlockStorage {
public class NoteBlockStorage implements StorableObject {
private static final int MAX_NOTE_ID = 24;
@@ -1,49 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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_13to1_12_2.storage;
import com.viaversion.viaversion.connection.ProtocolStorablesBase;
import org.checkerframework.checker.nullness.qual.Nullable;
public final class ProtocolStorables1_13 extends ProtocolStorablesBase {
private final BackwardsBlockStorage backwardsBlockStorage = new BackwardsBlockStorage();
private final TabCompleteStorage tabCompleteStorage = new TabCompleteStorage();
private final NoteBlockStorage noteBlockStorage = new NoteBlockStorage();
private PlayerPositionStorage1_13 playerPositionStorage;
public BackwardsBlockStorage backwardsBlockStorage() {
return backwardsBlockStorage;
}
public TabCompleteStorage tabCompleteStorage() {
return tabCompleteStorage;
}
public NoteBlockStorage noteBlockStorage() {
return noteBlockStorage;
}
public @Nullable PlayerPositionStorage1_13 playerPositionStorage() {
return playerPositionStorage;
}
public void setPlayerPositionStorage(final PlayerPositionStorage1_13 playerPositionStorage) {
this.playerPositionStorage = playerPositionStorage;
}
}
@@ -17,13 +17,14 @@
*/
package com.viaversion.viabackwards.protocol.v1_13to1_12_2.storage;
import com.viaversion.viaversion.api.connection.StorableObject;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
public class TabCompleteStorage {
public class TabCompleteStorage implements StorableObject {
private final Map<UUID, String> usernames = new HashMap<>();
private final Set<String> commands = new HashSet<>();
private int lastId;
@@ -41,8 +41,8 @@ public class Protocol1_14_1To1_14 extends BackwardsProtocol<ClientboundPackets1_
@Override
public void init(UserConnection user) {
addEntityTracker(user, new EntityTrackerBase(user, EntityTypes1_15.PLAYER));
user.storables(this).setClientWorld(new ClientWorld());
user.addEntityTracker(this.getClass(), new EntityTrackerBase(user, EntityTypes1_15.PLAYER));
user.addClientWorld(this.getClass(), new ClientWorld());
}
@Override
@@ -27,7 +27,7 @@ import com.viaversion.viabackwards.protocol.v1_14to1_13_2.rewriter.EntityPacketR
import com.viaversion.viabackwards.protocol.v1_14to1_13_2.rewriter.PlayerPacketRewriter1_14;
import com.viaversion.viabackwards.protocol.v1_14to1_13_2.rewriter.SoundPacketRewriter1_14;
import com.viaversion.viabackwards.protocol.v1_14to1_13_2.storage.ChunkLightStorage;
import com.viaversion.viabackwards.protocol.v1_14to1_13_2.storage.ProtocolStorables1_14;
import com.viaversion.viabackwards.protocol.v1_14to1_13_2.storage.DifficultyStorage;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.RegistryType;
@@ -121,8 +121,7 @@ public class Protocol1_14To1_13_2 extends BackwardsProtocol<ClientboundPackets1_
}
//TODO Soft memory leak: Don't store light if chunk is already loaded
ProtocolStorables1_14 storables = wrapper.user().storables(this);
storables.chunkLightStorage().setStoredLight(skyLight, blockLight, x, z);
wrapper.user().get(ChunkLightStorage.class).setStoredLight(skyLight, blockLight, x, z);
wrapper.cancel();
});
}
@@ -133,14 +132,14 @@ public class Protocol1_14To1_13_2 extends BackwardsProtocol<ClientboundPackets1_
@Override
public void init(UserConnection user) {
addEntityTracker(user, new EntityTrackerBase(user, EntityTypes1_14.PLAYER));
final ProtocolStorables1_14 storables = user.storables(this);
storables.setClientWorld(new ClientWorld());
}
user.addEntityTracker(this.getClass(), new EntityTrackerBase(user, EntityTypes1_14.PLAYER));
user.addClientWorld(this.getClass(), new ClientWorld());
@Override
public ProtocolStorables1_14 createStorables() {
return new ProtocolStorables1_14();
if (!user.has(ChunkLightStorage.class)) {
user.put(new ChunkLightStorage());
}
user.put(new DifficultyStorage());
}
@Override
@@ -27,7 +27,6 @@ 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.viabackwards.protocol.v1_14to1_13_2.storage.ProtocolStorables1_14;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
@@ -37,7 +36,6 @@ import com.viaversion.viaversion.api.minecraft.chunks.ChunkSection;
import com.viaversion.viaversion.api.minecraft.chunks.ChunkSectionLight;
import com.viaversion.viaversion.api.minecraft.chunks.ChunkSectionLightImpl;
import com.viaversion.viaversion.api.minecraft.chunks.DataPalette;
import com.viaversion.viaversion.api.minecraft.chunks.NibbleArray;
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;
@@ -131,7 +129,7 @@ public class BlockItemPacketRewriter1_14 extends BackwardsItemRewriter<Clientbou
}
if (stringType == null) {
// TODO stonecutter, if reasonably possible
protocol.getLogger().warning("Can't open inventory for player! Type: " + type);
wrapper.cancel();
return;
}
@@ -222,7 +220,7 @@ public class BlockItemPacketRewriter1_14 extends BackwardsItemRewriter<Clientbou
handler(wrapper -> {
int entityId = wrapper.get(Types.VAR_INT, 0);
EntityType entityType = wrapper.user().getEntityTracker(protocol).entityType(entityId);
EntityType entityType = wrapper.user().getEntityTracker(Protocol1_14To1_13_2.class).entityType(entityId);
if (entityType == null) return;
if (entityType.isOrHasParent(EntityTypes1_14.ABSTRACT_HORSE)) {
@@ -348,12 +346,11 @@ public class BlockItemPacketRewriter1_14 extends BackwardsItemRewriter<Clientbou
});
protocol.registerClientbound(ClientboundPackets1_14.LEVEL_CHUNK, wrapper -> {
ProtocolStorables1_14 storables = wrapper.user().storables(protocol);
ClientWorld clientWorld = storables.clientWorld();
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_14To1_13_2.class);
Chunk chunk = wrapper.read(ChunkType1_14.TYPE);
wrapper.write(ChunkType1_13.forEnvironment(clientWorld.getEnvironment()), chunk);
ChunkLightStorage.ChunkLight chunkLight = storables.chunkLightStorage().getStoredLight(chunk.getX(), chunk.getZ());
ChunkLightStorage.ChunkLight chunkLight = wrapper.user().get(ChunkLightStorage.class).getStoredLight(chunk.getX(), chunk.getZ());
for (int i = 0; i < chunk.getSections().length; i++) {
ChunkSection section = chunk.getSections()[i];
if (section == null) continue;
@@ -376,11 +373,16 @@ public class BlockItemPacketRewriter1_14 extends BackwardsItemRewriter<Clientbou
DataPalette palette = section.palette(PaletteType.BLOCKS);
if (Via.getConfig().isNonFullBlockLightFix() && section.getNonAirBlocksCount() != 0 && sectionLight.hasBlockLight()) {
NibbleArray blockLight = sectionLight.getBlockLightNibbleArray();
palette.forEachMatchingCoordinate(
id -> Protocol1_13_2To1_14.MAPPINGS.getNonFullBlocks().contains(id),
idx -> blockLight.set(ChunkSection.xFromIndex(idx), ChunkSection.yFromIndex(idx), ChunkSection.zFromIndex(idx), 0)
);
for (int x = 0; x < 16; x++) {
for (int y = 0; y < 16; y++) {
for (int z = 0; z < 16; z++) {
int id = palette.idAt(x, y, z);
if (Protocol1_13_2To1_14.MAPPINGS.getNonFullBlocks().contains(id)) {
sectionLight.getBlockLightNibbleArray().set(x, y, z, 0);
}
}
}
}
}
for (int j = 0; j < palette.size(); j++) {
@@ -393,8 +395,7 @@ public class BlockItemPacketRewriter1_14 extends BackwardsItemRewriter<Clientbou
protocol.registerClientbound(ClientboundPackets1_14.FORGET_LEVEL_CHUNK, wrapper -> {
int x = wrapper.passthrough(Types.INT);
int z = wrapper.passthrough(Types.INT);
ProtocolStorables1_14 storables = wrapper.user().storables(protocol);
storables.chunkLightStorage().unloadChunk(x, z);
wrapper.user().get(ChunkLightStorage.class).unloadChunk(x, z);
});
protocol.replaceClientbound(ClientboundPackets1_14.LEVEL_EVENT, new PacketHandlers() {
@@ -21,10 +21,11 @@ import com.viaversion.viabackwards.api.entities.storage.EntityPositionHandler;
import com.viaversion.viabackwards.api.entities.storage.EntityReplacement;
import com.viaversion.viabackwards.api.rewriters.LegacyEntityRewriter;
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.viabackwards.protocol.v1_14to1_13_2.storage.DifficultyStorage;
import com.viaversion.viabackwards.protocol.v1_14to1_13_2.storage.EntityPositionStorage1_14;
import com.viaversion.viabackwards.protocol.v1_14to1_13_2.storage.ProtocolStorables1_14;
import com.viaversion.viaversion.api.data.entity.EntityTracker;
import com.viaversion.viaversion.api.data.entity.TrackedEntity;
import com.viaversion.viaversion.api.data.entity.StoredEntityData;
import com.viaversion.viaversion.api.minecraft.BlockPosition;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.Particle;
@@ -63,12 +64,6 @@ public class EntityPacketRewriter1_14 extends LegacyEntityRewriter<ClientboundPa
if (status != 3) return;
EntityTracker tracker = tracker(wrapper.user());
if (entityId == tracker.clientEntityId()) {
// Clients up to 1.13.2 run the local death handling on their own death event, clearing
// their own inventory; the death screen still shows from the health update
wrapper.cancel();
return;
}
EntityType entityType = tracker.entityType(entityId);
if (entityType != EntityTypes1_14.PLAYER) return;
@@ -313,10 +308,9 @@ public class EntityPacketRewriter1_14 extends LegacyEntityRewriter<ClientboundPa
map(Types.INT); // 2 - Dimension
handler(getDimensionHandler(1));
handler(playerTrackerHandler());
handler(getPlayerTrackerHandler());
handler(wrapper -> {
ProtocolStorables1_14 storables = wrapper.user().storables(protocol);
short difficulty = storables.difficultyStorage().getDifficulty();
short difficulty = wrapper.user().get(DifficultyStorage.class).getDifficulty();
wrapper.write(Types.UNSIGNED_BYTE, difficulty);
wrapper.passthrough(Types.UNSIGNED_BYTE); // Max Players
@@ -325,7 +319,7 @@ public class EntityPacketRewriter1_14 extends LegacyEntityRewriter<ClientboundPa
final int entityId = wrapper.get(Types.INT, 0);
final TrackedEntity storedEntity = tracker(wrapper.user()).entity(entityId);
final StoredEntityData storedEntity = tracker(wrapper.user()).entityData(entityId);
storedEntity.put(new EntityPositionStorage1_14());
});
}
@@ -337,18 +331,17 @@ public class EntityPacketRewriter1_14 extends LegacyEntityRewriter<ClientboundPa
map(Types.INT); // 0 - Dimension ID
handler(wrapper -> {
ProtocolStorables1_14 storables = wrapper.user().storables(protocol);
ClientWorld clientWorld = storables.clientWorld();
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_14To1_13_2.class);
int dimensionId = wrapper.get(Types.INT, 0);
if (clientWorld.setEnvironment(dimensionId)) {
EntityTracker tracker = tracker(wrapper.user());
tracker.clearEntities();
storables.chunkLightStorage().clear();
tracker.entity(tracker.clientEntityId()).put(new EntityPositionStorage1_14());
wrapper.user().get(ChunkLightStorage.class).clear();
tracker.entityData(tracker.clientEntityId()).put(new EntityPositionStorage1_14());
}
short difficulty = storables.difficultyStorage().getDifficulty();
short difficulty = wrapper.user().get(DifficultyStorage.class).getDifficulty();
wrapper.write(Types.UNSIGNED_BYTE, difficulty);
});
}
@@ -366,8 +359,7 @@ public class EntityPacketRewriter1_14 extends LegacyEntityRewriter<ClientboundPa
private void trackAndCacheEntityPosition(PacketWrapper wrapper, EntityType type) {
// Tracks the entity + cache the position for the entity
final int entityId = wrapper.get(Types.VAR_INT, 0);
tracker(wrapper.user()).addEntity(entityId, type);
tracker(wrapper.user()).addEntity(wrapper.get(Types.VAR_INT, 0), type);
if (type == EntityTypes1_14.PAINTING) {
final BlockPosition position = wrapper.get(Types.BLOCK_POSITION1_8, 0);
@@ -484,21 +476,9 @@ public class EntityPacketRewriter1_14 extends LegacyEntityRewriter<ClientboundPa
filter().type(EntityTypes1_14.CAT).handler((event, data) -> {
if (event.index() == 15) {
Integer catVariant = data.value();
int ocelotVariant = catVariant != null ? switch (catVariant) {
// new ocelot mappings
case 0, 1, 2, 3 -> catVariant;
// Map to tuxedo
case 10 -> 1; // all_black
// Map to red
case 5, 6 -> 2; // calico, persian
// Map to siamese
case 4, 7, 8, 9 -> 3; // british_shorthair, ragdoll, white, jellie
default -> 0; // Untamed
} : 0;
data.setValue(ocelotVariant);
data.setValue(1);
} else if (event.index() == 13) {
data.setValue((byte) ((byte) data.getValue() & 0x4));
}
});
@@ -539,7 +519,7 @@ public class EntityPacketRewriter1_14 extends LegacyEntityRewriter<ClientboundPa
@Override
public void onMappingDataLoaded() {
super.onMappingDataLoaded();
mapEntityTypeWithData(EntityTypes1_14.CAT, EntityTypes1_14.OCELOT);
mapEntityTypeWithData(EntityTypes1_14.CAT, EntityTypes1_14.OCELOT).jsonName();
mapEntityTypeWithData(EntityTypes1_14.TRADER_LLAMA, EntityTypes1_14.LLAMA).jsonName();
mapEntityTypeWithData(EntityTypes1_14.FOX, EntityTypes1_14.WOLF).jsonName();
mapEntityTypeWithData(EntityTypes1_14.PANDA, EntityTypes1_14.POLAR_BEAR).jsonName();
@@ -18,7 +18,7 @@
package com.viaversion.viabackwards.protocol.v1_14to1_13_2.rewriter;
import com.viaversion.viabackwards.protocol.v1_14to1_13_2.Protocol1_14To1_13_2;
import com.viaversion.viabackwards.protocol.v1_14to1_13_2.storage.ProtocolStorables1_14;
import com.viaversion.viabackwards.protocol.v1_14to1_13_2.storage.DifficultyStorage;
import com.viaversion.viaversion.api.minecraft.BlockPosition;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.rewriter.RewriterBase;
@@ -41,8 +41,7 @@ public class PlayerPacketRewriter1_14 extends RewriterBase<Protocol1_14To1_13_2>
read(Types.BOOLEAN); // Locked
handler(wrapper -> {
byte difficulty = wrapper.get(Types.UNSIGNED_BYTE, 0).byteValue();
ProtocolStorables1_14 storables = wrapper.user().storables(protocol);
storables.difficultyStorage().setDifficulty(difficulty);
wrapper.user().get(DifficultyStorage.class).setDifficulty(difficulty);
});
}
});
@@ -19,7 +19,7 @@ package com.viaversion.viabackwards.protocol.v1_14to1_13_2.rewriter;
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;
import com.viaversion.viaversion.api.data.entity.TrackedEntity;
import com.viaversion.viaversion.api.data.entity.StoredEntityData;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.rewriter.RewriterBase;
import com.viaversion.viaversion.api.type.Types;
@@ -45,7 +45,7 @@ public class SoundPacketRewriter1_14 extends RewriterBase<Protocol1_14To1_13_2>
int category = wrapper.read(Types.VAR_INT);
int entityId = wrapper.read(Types.VAR_INT);
TrackedEntity storedEntity = wrapper.user().getEntityTracker(protocol).entity(entityId);
StoredEntityData storedEntity = wrapper.user().getEntityTracker(protocol.getClass()).entityData(entityId);
EntityPositionStorage1_14 entityStorage;
if (storedEntity == null || (entityStorage = storedEntity.get(EntityPositionStorage1_14.class)) == null) {
protocol.getLogger().warning("Untracked entity with id " + entityId);
@@ -17,11 +17,12 @@
*/
package com.viaversion.viabackwards.protocol.v1_14to1_13_2.storage;
import com.viaversion.viaversion.api.connection.StorableObject;
import com.viaversion.viaversion.libs.fastutil.longs.Long2ObjectMap;
import com.viaversion.viaversion.libs.fastutil.longs.Long2ObjectOpenHashMap;
import java.util.Arrays;
public class ChunkLightStorage {
public class ChunkLightStorage implements StorableObject {
public static final byte[] FULL_LIGHT = new byte[2048];
public static final byte[] EMPTY_LIGHT = new byte[2048];
@@ -17,7 +17,9 @@
*/
package com.viaversion.viabackwards.protocol.v1_14to1_13_2.storage;
public class DifficultyStorage {
import com.viaversion.viaversion.api.connection.StorableObject;
public class DifficultyStorage implements StorableObject {
private byte difficulty;
public byte getDifficulty() {
@@ -1,34 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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_14to1_13_2.storage;
import com.viaversion.viaversion.connection.ProtocolStorablesBase;
public final class ProtocolStorables1_14 extends ProtocolStorablesBase {
private final ChunkLightStorage chunkLightStorage = new ChunkLightStorage();
private final DifficultyStorage difficultyStorage = new DifficultyStorage();
public ChunkLightStorage chunkLightStorage() {
return chunkLightStorage;
}
public DifficultyStorage difficultyStorage() {
return difficultyStorage;
}
}
@@ -88,8 +88,8 @@ public class Protocol1_15To1_14_4 extends BackwardsProtocol<ClientboundPackets1_
@Override
public void init(UserConnection user) {
user.storables(this).setEntityTracker(new EntityTrackerBase(user, EntityTypes1_15.PLAYER));
user.storables(this).setClientWorld(new ClientWorld());
user.addEntityTracker(getClass(), new EntityTrackerBase(user, EntityTypes1_15.PLAYER));
user.addClientWorld(getClass(), new ClientWorld());
user.put(new ImmediateRespawnStorage());
}
@@ -113,7 +113,7 @@ public class EntityPacketRewriter1_15 extends EntityRewriter<ClientboundPackets1
map(Types.VAR_INT); // 5 - View Distance
map(Types.BOOLEAN); // 6 - Reduce Debug Info
handler(playerTrackerHandler());
handler(getPlayerTrackerHandler());
handler(wrapper -> {
boolean immediateRespawn = !wrapper.read(Types.BOOLEAN); // Inverted
@@ -136,13 +136,9 @@ public class EntityPacketRewriter1_15 extends EntityRewriter<ClientboundPackets1
map(Types.DOUBLE); // 4 - Z
map(Types.BYTE); // 5 - Yaw
map(Types.BYTE); // 6 - Pitch
handler(wrapper -> {
final int entityId = wrapper.get(Types.VAR_INT, 0);
tracker(wrapper.user()).addEntity(entityId, EntityTypes1_15.PLAYER);
handler(wrapper -> wrapper.write(Types1_14.ENTITY_DATA_LIST, new ArrayList<>())); // Entity data is no longer sent in 1.15, so we have to send an empty one
// Entity data is no longer sent in 1.15, so we have to send an empty one
wrapper.write(Types1_14.ENTITY_DATA_LIST, new ArrayList<>());
});
handler(getTrackerHandler(EntityTypes1_15.PLAYER));
}
});
@@ -24,8 +24,6 @@ import com.viaversion.viabackwards.protocol.v1_16_2to1_16_1.rewriter.BlockItemPa
import com.viaversion.viabackwards.protocol.v1_16_2to1_16_1.rewriter.CommandRewriter1_16_2;
import com.viaversion.viabackwards.protocol.v1_16_2to1_16_1.rewriter.EntityPacketRewriter1_16_2;
import com.viaversion.viabackwards.protocol.v1_16_2to1_16_1.storage.BiomeStorage;
import com.viaversion.viabackwards.protocol.v1_16_2to1_16_1.storage.ProtocolStorables1_16_2;
import com.viaversion.viaversion.connection.ProtocolStorablesBase;
import com.viaversion.viabackwards.utils.BackwardsProtocolLogger;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.RegistryType;
@@ -111,15 +109,8 @@ public class Protocol1_16_2To1_16_1 extends BackwardsProtocol<ClientboundPackets
@Override
public void init(UserConnection user) {
addEntityTracker(user, new EntityTrackerBase(user, EntityTypes1_16_2.PLAYER));
final ProtocolStorables1_16_2 storables = user.storables(this);
// BiomeStorage is also used in 1.16->1.15.2
user.put(storables.biomeStorage());
}
@Override
public ProtocolStorablesBase createStorables() {
return new ProtocolStorables1_16_2();
user.put(new BiomeStorage());
user.addEntityTracker(this.getClass(), new EntityTrackerBase(user, EntityTypes1_16_2.PLAYER));
}
@Override
@@ -26,7 +26,6 @@ import com.viaversion.viabackwards.ViaBackwards;
import com.viaversion.viabackwards.api.rewriters.EntityRewriter;
import com.viaversion.viabackwards.protocol.v1_16_2to1_16_1.Protocol1_16_2To1_16_1;
import com.viaversion.viabackwards.protocol.v1_16_2to1_16_1.storage.BiomeStorage;
import com.viaversion.viabackwards.protocol.v1_16_2to1_16_1.storage.ProtocolStorables1_16_2;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_16_2;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
@@ -74,8 +73,7 @@ public class EntityPacketRewriter1_16_2 extends EntityRewriter<ClientboundPacket
if (wrapper.user().getProtocolInfo().protocolVersion().olderThanOrEqualTo(ProtocolVersion.v1_15_2)) {
// Store biomes for <1.16 client handling
ListTag<CompoundTag> biomes = TagUtil.getRegistryEntries(registry, "worldgen/biome");
ProtocolStorables1_16_2 storables = wrapper.user().storables(protocol);
BiomeStorage biomeStorage = storables.biomeStorage();
BiomeStorage biomeStorage = wrapper.user().get(BiomeStorage.class);
biomeStorage.clear();
for (CompoundTag biome : biomes) {
StringTag name = biome.getStringTag("name");
@@ -104,7 +102,7 @@ public class EntityPacketRewriter1_16_2 extends EntityRewriter<ClientboundPacket
wrapper.write(Types.UNSIGNED_BYTE, (short) Math.min(maxPlayers, 255));
});
// ...
handler(playerTrackerHandler());
handler(getPlayerTrackerHandler());
}
});
@@ -1,29 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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_16_2to1_16_1.storage;
import com.viaversion.viaversion.connection.ProtocolStorablesBase;
public final class ProtocolStorables1_16_2 extends ProtocolStorablesBase {
private final BiomeStorage biomeStorage = new BiomeStorage();
public BiomeStorage biomeStorage() {
return biomeStorage;
}
}
@@ -19,11 +19,9 @@ package com.viaversion.viabackwards.protocol.v1_16_4to1_16_3;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.protocol.v1_16_4to1_16_3.storage.PlayerHandStorage;
import com.viaversion.viabackwards.protocol.v1_16_4to1_16_3.storage.ProtocolStorables1_16_4;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.connection.ProtocolStorablesBase;
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;
@@ -45,8 +43,7 @@ public class Protocol1_16_4To1_16_3 extends BackwardsProtocol<ClientboundPackets
if (slot == 1) {
wrapper.write(Types.VAR_INT, 40); // offhand
} else {
ProtocolStorables1_16_4 storables = wrapper.user().storables(Protocol1_16_4To1_16_3.this);
wrapper.write(Types.VAR_INT, storables.playerHandStorage().getCurrentHand());
wrapper.write(Types.VAR_INT, wrapper.user().get(PlayerHandStorage.class).getCurrentHand());
}
});
}
@@ -54,17 +51,12 @@ public class Protocol1_16_4To1_16_3 extends BackwardsProtocol<ClientboundPackets
registerServerbound(ServerboundPackets1_16_2.SET_CARRIED_ITEM, wrapper -> {
short slot = wrapper.passthrough(Types.SHORT);
ProtocolStorables1_16_4 storables = wrapper.user().storables(this);
storables.playerHandStorage().setCurrentHand(slot);
wrapper.user().get(PlayerHandStorage.class).setCurrentHand(slot);
});
}
@Override
public void init(UserConnection user) {
}
@Override
public ProtocolStorablesBase createStorables() {
return new ProtocolStorables1_16_4();
user.put(new PlayerHandStorage());
}
}
@@ -17,7 +17,9 @@
*/
package com.viaversion.viabackwards.protocol.v1_16_4to1_16_3.storage;
public class PlayerHandStorage {
import com.viaversion.viaversion.api.connection.StorableObject;
public class PlayerHandStorage implements StorableObject {
private int currentHand;
@@ -1,29 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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_16_4to1_16_3.storage;
import com.viaversion.viaversion.connection.ProtocolStorablesBase;
public final class ProtocolStorables1_16_4 extends ProtocolStorablesBase {
private final PlayerHandStorage playerHandStorage = new PlayerHandStorage();
public PlayerHandStorage playerHandStorage() {
return playerHandStorage;
}
}
@@ -23,7 +23,9 @@ import com.viaversion.viabackwards.protocol.v1_16to1_15_2.rewriter.BlockItemPack
import com.viaversion.viabackwards.protocol.v1_16to1_15_2.rewriter.CommandRewriter1_16;
import com.viaversion.viabackwards.protocol.v1_16to1_15_2.rewriter.EntityPacketRewriter1_16;
import com.viaversion.viabackwards.protocol.v1_16to1_15_2.rewriter.TranslatableRewriter1_16;
import com.viaversion.viabackwards.protocol.v1_16to1_15_2.storage.ProtocolStorables1_16;
import com.viaversion.viabackwards.protocol.v1_16to1_15_2.storage.PlayerAttributesStorage;
import com.viaversion.viabackwards.protocol.v1_16to1_15_2.storage.PlayerSneakStorage;
import com.viaversion.viabackwards.protocol.v1_16to1_15_2.storage.WorldNameTracker;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.RegistryType;
@@ -115,11 +117,9 @@ public class Protocol1_16To1_15_2 extends BackwardsProtocol<ClientboundPackets1_
wrapper.passthrough(Types.VAR_INT); // player id
int action = wrapper.passthrough(Types.VAR_INT);
if (action == 0) {
ProtocolStorables1_16 storables = wrapper.user().storables(this);
storables.playerSneakStorage().setSneaking(true);
wrapper.user().get(PlayerSneakStorage.class).setSneaking(true);
} else if (action == 1) {
ProtocolStorables1_16 storables = wrapper.user().storables(this);
storables.playerSneakStorage().setSneaking(false);
wrapper.user().get(PlayerSneakStorage.class).setSneaking(false);
}
});
@@ -138,8 +138,7 @@ public class Protocol1_16To1_15_2 extends BackwardsProtocol<ClientboundPackets1_
}
// New boolean: Whether the client is sneaking
ProtocolStorables1_16 storables = wrapper.user().storables(this);
wrapper.write(Types.BOOLEAN, storables.playerSneakStorage().isSneaking());
wrapper.write(Types.BOOLEAN, wrapper.user().get(PlayerSneakStorage.class).isSneaking());
});
registerServerbound(ServerboundPackets1_14.PLAYER_ABILITIES, wrapper -> {
@@ -156,13 +155,12 @@ public class Protocol1_16To1_15_2 extends BackwardsProtocol<ClientboundPackets1_
@Override
public void init(UserConnection user) {
addEntityTracker(user, new EntityTrackerBase(user, EntityTypes1_16.PLAYER));
user.storables(this).setClientWorld(new ClientWorld());
}
user.addEntityTracker(this.getClass(), new EntityTrackerBase(user, EntityTypes1_16.PLAYER));
user.addClientWorld(this.getClass(), new ClientWorld());
@Override
public ProtocolStorables1_16 createStorables() {
return new ProtocolStorables1_16();
user.put(new PlayerSneakStorage());
user.put(new WorldNameTracker());
user.put(new PlayerAttributesStorage());
}
@Override
@@ -20,10 +20,10 @@ package com.viaversion.viabackwards.protocol.v1_16to1_15_2.rewriter;
import com.viaversion.viabackwards.api.rewriters.EntityRewriter;
import com.viaversion.viabackwards.protocol.v1_16to1_15_2.Protocol1_16To1_15_2;
import com.viaversion.viabackwards.protocol.v1_16to1_15_2.storage.PlayerAttributesStorage;
import com.viaversion.viabackwards.protocol.v1_16to1_15_2.storage.ProtocolStorables1_16;
import com.viaversion.viabackwards.protocol.v1_16to1_15_2.storage.WolfDataMaskStorage;
import com.viaversion.viabackwards.protocol.v1_16to1_15_2.storage.WorldNameTracker;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.data.entity.StoredEntityData;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.Particle;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
@@ -100,9 +100,8 @@ public class EntityPacketRewriter1_16 extends EntityRewriter<ClientboundPackets1
public void register() {
map(dimensionTransformer); // Dimension Type
handler(wrapper -> {
ProtocolStorables1_16 storables = wrapper.user().storables(protocol);
// Grab the tracker for world names
WorldNameTracker worldNameTracker = storables.worldNameTracker();
WorldNameTracker worldNameTracker = wrapper.user().get(WorldNameTracker.class);
String nextWorldName = wrapper.read(Types.STRING); // World Name
wrapper.passthrough(Types.LONG); // Seed
@@ -110,7 +109,7 @@ public class EntityPacketRewriter1_16 extends EntityRewriter<ClientboundPackets1
wrapper.read(Types.BYTE); // Previous gamemode
// Grab client world
ClientWorld clientWorld = storables.clientWorld();
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_16To1_15_2.class);
int dimension = wrapper.get(Types.INT, 0);
// Send a dummy respawn with a different dimension if the world name was different and the same dimension was used
@@ -136,7 +135,7 @@ public class EntityPacketRewriter1_16 extends EntityRewriter<ClientboundPackets1
wrapper.set(Types.STRING, 0, "flat");
}
final PlayerAttributesStorage attributes = storables.playerAttributesStorage();
final PlayerAttributesStorage attributes = wrapper.user().get(PlayerAttributesStorage.class);
final boolean keepPlayerAttributes = wrapper.read(Types.BOOLEAN);
if (keepPlayerAttributes) {
// Ensure packet order
@@ -163,13 +162,13 @@ public class EntityPacketRewriter1_16 extends EntityRewriter<ClientboundPackets1
read(Types.NAMED_COMPOUND_TAG); // whatever this is
map(dimensionTransformer); // Dimension Type
handler(wrapper -> {
ProtocolStorables1_16 storables = wrapper.user().storables(protocol);
storables.worldNameTracker().setWorldName(wrapper.read(Types.STRING)); // Save the world name
WorldNameTracker worldNameTracker = wrapper.user().get(WorldNameTracker.class);
worldNameTracker.setWorldName(wrapper.read(Types.STRING)); // Save the world name
});
map(Types.LONG); // Seed
map(Types.UNSIGNED_BYTE); // Max players
handler(wrapper -> {
ClientWorld clientWorld = wrapper.user().storables(protocol).clientWorld();
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_16To1_15_2.class);
clientWorld.setEnvironment(wrapper.get(Types.INT, 1));
wrapper.write(Types.STRING, "default"); // Level type
@@ -194,8 +193,7 @@ public class EntityPacketRewriter1_16 extends EntityRewriter<ClientboundPackets1
registerSetEntityData(ClientboundPackets1_16.SET_ENTITY_DATA, Types1_16.ENTITY_DATA_LIST, Types1_14.ENTITY_DATA_LIST);
protocol.registerClientbound(ClientboundPackets1_16.UPDATE_ATTRIBUTES, wrapper -> {
ProtocolStorables1_16 storables = wrapper.user().storables(protocol);
final PlayerAttributesStorage attributes = storables.playerAttributesStorage();
final PlayerAttributesStorage attributes = wrapper.user().get(PlayerAttributesStorage.class);
final int entityId = wrapper.passthrough(Types.VAR_INT);
@@ -292,14 +290,18 @@ public class EntityPacketRewriter1_16 extends EntityRewriter<ClientboundPackets1
filter().type(EntityTypes1_16.WOLF).index(16).handler((event, data) -> {
byte mask = data.value();
event.trackedEntity().put(new WolfDataMaskStorage(mask));
StoredEntityData entityData = tracker(event.user()).entityData(event.entityId());
entityData.put(new WolfDataMaskStorage(mask));
});
filter().type(EntityTypes1_16.WOLF).index(20).handler((event, data) -> {
StoredEntityData entityData = tracker(event.user()).entityDataIfPresent(event.entityId());
byte previousMask = 0;
WolfDataMaskStorage wolfData = event.trackedEntity().get(WolfDataMaskStorage.class);
if (wolfData != null) {
previousMask = wolfData.tameableMask();
if (entityData != null) {
WolfDataMaskStorage wolfData = entityData.get(WolfDataMaskStorage.class);
if (wolfData != null) {
previousMask = wolfData.tameableMask();
}
}
int angerTime = data.value();
@@ -18,6 +18,7 @@
package com.viaversion.viabackwards.protocol.v1_16to1_15_2.storage;
import com.viaversion.viabackwards.protocol.v1_16to1_15_2.Protocol1_16To1_15_2;
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;
@@ -26,7 +27,7 @@ import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public final class PlayerAttributesStorage {
public final class PlayerAttributesStorage implements StorableObject {
private final Map<String, Attribute> attributes = new HashMap<>();
@@ -17,7 +17,9 @@
*/
package com.viaversion.viabackwards.protocol.v1_16to1_15_2.storage;
public class PlayerSneakStorage {
import com.viaversion.viaversion.api.connection.StorableObject;
public class PlayerSneakStorage implements StorableObject {
private boolean sneaking;
public boolean isSneaking() {
@@ -1,39 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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_16to1_15_2.storage;
import com.viaversion.viaversion.connection.ProtocolStorablesBase;
public final class ProtocolStorables1_16 extends ProtocolStorablesBase {
private final PlayerSneakStorage playerSneakStorage = new PlayerSneakStorage();
private final WorldNameTracker worldNameTracker = new WorldNameTracker();
private final PlayerAttributesStorage playerAttributesStorage = new PlayerAttributesStorage();
public PlayerSneakStorage playerSneakStorage() {
return playerSneakStorage;
}
public WorldNameTracker worldNameTracker() {
return worldNameTracker;
}
public PlayerAttributesStorage playerAttributesStorage() {
return playerAttributesStorage;
}
}
@@ -17,9 +17,7 @@
*/
package com.viaversion.viabackwards.protocol.v1_16to1_15_2.storage;
import com.viaversion.viaversion.api.connection.StorableObject;
public final class WolfDataMaskStorage implements StorableObject {
public final class WolfDataMaskStorage {
private byte tameableMask;
@@ -17,7 +17,9 @@
*/
package com.viaversion.viabackwards.protocol.v1_16to1_15_2.storage;
public class WorldNameTracker {
import com.viaversion.viaversion.api.connection.StorableObject;
public class WorldNameTracker implements StorableObject {
private String worldName;
public String getWorldName() {
@@ -21,7 +21,7 @@ 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_17_1to1_17.storage.ProtocolStorables1_17_1;
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;
@@ -56,17 +56,17 @@ public final class Protocol1_17_1To1_17 extends BackwardsProtocol<ClientboundPac
registerClientbound(ClientboundPackets1_17_1.CONTAINER_CLOSE, wrapper -> {
short containerId = wrapper.passthrough(Types.UNSIGNED_BYTE);
wrapper.user().<ProtocolStorables1_17_1>storables(this).inventoryStateIds().removeStateId(containerId);
wrapper.user().get(InventoryStateIds.class).removeStateId(containerId);
});
registerClientbound(ClientboundPackets1_17_1.CONTAINER_SET_SLOT, wrapper -> {
byte containerId = wrapper.passthrough(Types.BYTE);
int stateId = wrapper.read(Types.VAR_INT);
wrapper.user().<ProtocolStorables1_17_1>storables(this).inventoryStateIds().setStateId(containerId, stateId);
wrapper.user().get(InventoryStateIds.class).setStateId(containerId, stateId);
});
registerClientbound(ClientboundPackets1_17_1.CONTAINER_SET_CONTENT, wrapper -> {
short containerId = wrapper.passthrough(Types.UNSIGNED_BYTE);
int stateId = wrapper.read(Types.VAR_INT);
wrapper.user().<ProtocolStorables1_17_1>storables(this).inventoryStateIds().setStateId(containerId, stateId);
wrapper.user().get(InventoryStateIds.class).setStateId(containerId, stateId);
// Length is encoded as a var int in 1.17.1
wrapper.write(Types.ITEM1_13_2_SHORT_ARRAY, wrapper.read(Types.ITEM1_13_2_ARRAY));
@@ -74,7 +74,7 @@ public final class Protocol1_17_1To1_17 extends BackwardsProtocol<ClientboundPac
// Carried item - forward as CONTAINER_SET_SLOT for <1.17 clients
Item carried = wrapper.read(Types.ITEM1_13_2);
PlayerLastCursorItem lastCursorItem = wrapper.user().<ProtocolStorables1_17_1>storables(this).playerLastCursorItem();
PlayerLastCursorItem lastCursorItem = wrapper.user().get(PlayerLastCursorItem.class);
if (lastCursorItem != null) {
// For click drag ghost item fix -- since the state ID is always wrong,
// the server always resends the entire window contents after a drag action,
@@ -97,11 +97,11 @@ public final class Protocol1_17_1To1_17 extends BackwardsProtocol<ClientboundPac
registerServerbound(ServerboundPackets1_17.CONTAINER_CLOSE, wrapper -> {
byte containerId = wrapper.passthrough(Types.BYTE);
wrapper.user().<ProtocolStorables1_17_1>storables(this).inventoryStateIds().removeStateId(containerId);
wrapper.user().get(InventoryStateIds.class).removeStateId(containerId);
});
registerServerbound(ServerboundPackets1_17.CONTAINER_CLICK, wrapper -> {
byte containerId = wrapper.passthrough(Types.BYTE);
int stateId = wrapper.user().<ProtocolStorables1_17_1>storables(this).inventoryStateIds().removeStateId(containerId);
int stateId = wrapper.user().get(InventoryStateIds.class).removeStateId(containerId);
wrapper.write(Types.VAR_INT, stateId == Integer.MAX_VALUE ? 0 : stateId);
});
@@ -158,7 +158,7 @@ public final class Protocol1_17_1To1_17 extends BackwardsProtocol<ClientboundPac
}
@Override
public ProtocolStorables1_17_1 createStorables() {
return new ProtocolStorables1_17_1();
public void init(UserConnection connection) {
connection.put(new InventoryStateIds());
}
}
@@ -1,35 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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_17_1to1_17.storage;
import com.viaversion.viabackwards.protocol.v1_17to1_16_4.storage.PlayerLastCursorItem;
import com.viaversion.viaversion.connection.ProtocolStorablesBase;
public final class ProtocolStorables1_17_1 extends ProtocolStorablesBase {
private final InventoryStateIds inventoryStateIds = new InventoryStateIds();
private final PlayerLastCursorItem playerLastCursorItem = new PlayerLastCursorItem();
public InventoryStateIds inventoryStateIds() {
return inventoryStateIds;
}
public PlayerLastCursorItem playerLastCursorItem() {
return playerLastCursorItem;
}
}
@@ -24,8 +24,6 @@ import com.viaversion.viabackwards.api.rewriters.text.JsonNBTComponentRewriter;
import com.viaversion.viabackwards.protocol.v1_17to1_16_4.rewriter.BlockItemPacketRewriter1_17;
import com.viaversion.viabackwards.protocol.v1_17to1_16_4.rewriter.EntityPacketRewriter1_17;
import com.viaversion.viabackwards.protocol.v1_17to1_16_4.storage.PlayerLastCursorItem;
import com.viaversion.viabackwards.protocol.v1_17to1_16_4.storage.ProtocolStorables1_17;
import com.viaversion.viaversion.connection.ProtocolStorablesBase;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.RegistryType;
import com.viaversion.viaversion.api.minecraft.TagData;
@@ -207,11 +205,7 @@ public final class Protocol1_17To1_16_4 extends BackwardsProtocol<ClientboundPac
@Override
public void init(UserConnection user) {
addEntityTracker(user, new EntityTrackerBase(user, EntityTypes1_17.PLAYER));
}
@Override
public ProtocolStorablesBase createStorables() {
return new ProtocolStorables1_17();
user.put(new PlayerLastCursorItem());
}
@Override
@@ -26,12 +26,8 @@ import com.viaversion.viabackwards.api.rewriters.BackwardsItemRewriter;
import com.viaversion.viabackwards.api.rewriters.MapColorRewriter;
import com.viaversion.viabackwards.protocol.v1_17to1_16_4.Protocol1_17To1_16_4;
import com.viaversion.viabackwards.protocol.v1_17to1_16_4.data.MapColorMappings1_16_4;
import com.viaversion.viabackwards.protocol.v1_17_1to1_17.Protocol1_17_1To1_17;
import com.viaversion.viabackwards.protocol.v1_17_1to1_17.storage.InventoryStateIds;
import com.viaversion.viabackwards.protocol.v1_17_1to1_17.storage.ProtocolStorables1_17_1;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viabackwards.protocol.v1_17to1_16_4.storage.PlayerLastCursorItem;
import com.viaversion.viabackwards.protocol.v1_17to1_16_4.storage.ProtocolStorables1_17;
import com.viaversion.viaversion.api.data.entity.EntityTracker;
import com.viaversion.viaversion.api.minecraft.BlockChangeRecord;
import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
@@ -103,15 +99,13 @@ public final class BlockItemPacketRewriter1_17 extends BackwardsItemRewriter<Cli
// that we can't easily predict. Force a state ID mismatch so the server
// sends a full inventory resync instead of individual slot corrections.
if (mode != 0) {
ProtocolStorables1_17_1 storables1_17_1 = wrapper.user().storables(Via.getManager().getProtocolManager().getProtocol(Protocol1_17_1To1_17.class));
InventoryStateIds stateIds = storables1_17_1.inventoryStateIds();
InventoryStateIds stateIds = wrapper.user().get(InventoryStateIds.class);
if (stateIds != null) {
stateIds.setStateId(wrapper.get(Types.BYTE, 0), -1);
}
}
ProtocolStorables1_17 storables = wrapper.user().storables(protocol);
PlayerLastCursorItem state = storables.playerLastCursorItem();
PlayerLastCursorItem state = wrapper.user().get(PlayerLastCursorItem.class);
if (mode == 0 && button == 0 && clicked != null) {
// Left click PICKUP
// Carried item will (usually) be the entire clicked stack
@@ -160,8 +154,7 @@ public final class BlockItemPacketRewriter1_17 extends BackwardsItemRewriter<Cli
// carried item, and the server will helpfully send this packet allowing us
// to update the internal state. This is necessary for fixing multiple sequential
// click drag actions without intermittent pickup actions.
ProtocolStorables1_17 storables = wrapper.user().storables(protocol);
storables.playerLastCursorItem().setLastCursorItem(carried);
wrapper.user().get(PlayerLastCursorItem.class).setLastCursorItem(carried);
}
wrapper.write(Types.ITEM1_13_2, handleItemToClient(wrapper.user(), carried));
@@ -235,7 +228,7 @@ public final class BlockItemPacketRewriter1_17 extends BackwardsItemRewriter<Cli
map(Types.VAR_INT); // Z
map(Types.BOOLEAN); // Trust edges
handler(wrapper -> {
EntityTracker tracker = wrapper.user().getEntityTracker(protocol);
EntityTracker tracker = wrapper.user().getEntityTracker(Protocol1_17To1_16_4.class);
int startFromSection = Math.max(0, -(tracker.currentMinY() >> 4));
long[] skyLightMask = wrapper.read(Types.LONG_ARRAY_PRIMITIVE);
@@ -351,7 +344,7 @@ public final class BlockItemPacketRewriter1_17 extends BackwardsItemRewriter<Cli
});
protocol.registerClientbound(ClientboundPackets1_17.LEVEL_CHUNK, wrapper -> {
EntityTracker tracker = wrapper.user().getEntityTracker(protocol);
EntityTracker tracker = wrapper.user().getEntityTracker(Protocol1_17To1_16_4.class);
int currentWorldSectionHeight = tracker.currentWorldSectionHeight();
Chunk chunk = wrapper.read(new ChunkType1_17(currentWorldSectionHeight));
@@ -101,7 +101,7 @@ public final class EntityPacketRewriter1_17 extends EntityRewriter<ClientboundPa
wrapper.set(Types.BYTE, 1, (byte) 0);
}
});
handler(playerTrackerHandler());
handler(getPlayerTrackerHandler());
handler(worldDataTrackerHandler(1));
handler(wrapper -> {
CompoundTag registry = wrapper.get(Types.NAMED_COMPOUND_TAG, 0);
@@ -17,9 +17,10 @@
*/
package com.viaversion.viabackwards.protocol.v1_17to1_16_4.storage;
import com.viaversion.viaversion.api.connection.StorableObject;
import com.viaversion.viaversion.api.minecraft.item.Item;
public class PlayerLastCursorItem {
public class PlayerLastCursorItem implements StorableObject {
private Item lastCursorItem;
public Item getLastCursorItem() {
@@ -1,29 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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_17to1_16_4.storage;
import com.viaversion.viaversion.connection.ProtocolStorablesBase;
public final class ProtocolStorables1_17 extends ProtocolStorablesBase {
private final PlayerLastCursorItem playerLastCursorItem = new PlayerLastCursorItem();
public PlayerLastCursorItem playerLastCursorItem() {
return playerLastCursorItem;
}
}
@@ -54,7 +54,6 @@ import com.viaversion.viaversion.protocols.v1_19to1_19_1.packet.ServerboundPacke
import com.viaversion.viaversion.rewriter.text.ComponentRewriterBase;
import com.viaversion.viaversion.util.CipherUtil;
import com.viaversion.viaversion.util.ComponentUtil;
import com.viaversion.viaversion.util.Limit;
import com.viaversion.viaversion.util.Pair;
import com.viaversion.viaversion.util.TagUtil;
import java.security.SignatureException;
@@ -104,9 +103,8 @@ public final class Protocol1_19_1To1_19 extends BackwardsProtocol<ClientboundPac
// Replace with 1.19 chat types
// Ensures that the client has a chat type for system message, with and without overlay
registry.put("minecraft:chat_type", Protocol1_18_2To1_19.MAPPINGS.chatRegistry());
entityRewriter.trackWorld(wrapper.user(), wrapper.get(Types.STRING, 1));
});
handler(entityRewriter.worldTrackerHandlerByKey());
}
});
@@ -231,7 +229,7 @@ public final class Protocol1_19_1To1_19 extends BackwardsProtocol<ClientboundPac
final SignableCommandArgumentsProvider argumentsProvider = Via.getManager().getProviders().get(SignableCommandArgumentsProvider.class);
if (chatSession != null && argumentsProvider != null) {
final int signatures = Limit.max(wrapper.read(Types.VAR_INT), 8);
final int signatures = wrapper.read(Types.VAR_INT);
for (int i = 0; i < signatures; i++) {
wrapper.read(Types.STRING); // Argument name
wrapper.read(Types.BYTE_ARRAY_PRIMITIVE); // Signature
@@ -41,9 +41,7 @@ import com.viaversion.viaversion.api.minecraft.signature.storage.ChatSession1_19
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.packet.State;
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.api.type.types.ArrayType;
import com.viaversion.viaversion.api.type.types.BitSetType;
import com.viaversion.viaversion.api.type.types.ByteArrayType;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_18;
@@ -63,7 +61,6 @@ 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.Limit;
import com.viaversion.viaversion.util.Pair;
import java.security.SignatureException;
import java.util.BitSet;
@@ -73,7 +70,6 @@ import org.checkerframework.checker.nullness.qual.Nullable;
public final class Protocol1_19_3To1_19_1 extends BackwardsProtocol<ClientboundPackets1_19_3, ClientboundPackets1_19_1, ServerboundPackets1_19_3, ServerboundPackets1_19_1> {
public static final BackwardsMappingData MAPPINGS = new BackwardsMappingData("1.19.3", "1.19", Protocol1_19_1To1_19_3.class);
private static final Type<PlayerMessageSignature[]> LAST_SEEN_MESSAGES_TYPE = new ArrayType<>(Types.PLAYER_MESSAGE_SIGNATURE, 5);
private final EntityPacketRewriter1_19_3 entityRewriter = new EntityPacketRewriter1_19_3(this);
private final BlockItemPacketRewriter1_19_3 itemRewriter = new BlockItemPacketRewriter1_19_3(this);
private final ParticleRewriter<ClientboundPackets1_19_3> particleRewriter = new ParticleRewriter<>(this);
@@ -211,7 +207,7 @@ public final class Protocol1_19_3To1_19_1 extends BackwardsProtocol<ClientboundP
map(Types.LONG); // Salt
read(Types.BYTE_ARRAY_PRIMITIVE); // Signature
read(Types.BOOLEAN); // Signed preview
read(LAST_SEEN_MESSAGES_TYPE); // Last seen messages
read(Types.PLAYER_MESSAGE_SIGNATURE_ARRAY); // Last seen messages
read(Types.OPTIONAL_PLAYER_MESSAGE_SIGNATURE); // Last received message
handler(wrapper -> {
final ChatSession1_19_3 chatSession = wrapper.user().get(ChatSession1_19_3.class);
@@ -254,7 +250,7 @@ public final class Protocol1_19_3To1_19_1 extends BackwardsProtocol<ClientboundP
final long timestamp = wrapper.get(Types.LONG, 0);
final long salt = wrapper.get(Types.LONG, 1);
final int signatures = Limit.max(wrapper.read(Types.VAR_INT), 8);
final int signatures = wrapper.read(Types.VAR_INT);
for (int i = 0; i < signatures; i++) {
wrapper.read(Types.STRING); // Name
wrapper.read(Types.BYTE_ARRAY_PRIMITIVE); // Signature
@@ -286,7 +282,7 @@ public final class Protocol1_19_3To1_19_1 extends BackwardsProtocol<ClientboundP
wrapper.write(Types.VAR_INT, offset);
wrapper.write(new BitSetType(20), acknowledged);
});
read(LAST_SEEN_MESSAGES_TYPE); // Last seen messages
read(Types.PLAYER_MESSAGE_SIGNATURE_ARRAY); // Last seen messages
read(Types.OPTIONAL_PLAYER_MESSAGE_SIGNATURE); // Last received message
}
});
@@ -21,7 +21,6 @@ import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.data.BackwardsMappingData;
import com.viaversion.viabackwards.api.rewriters.text.JsonNBTComponentRewriter;
import com.viaversion.viabackwards.protocol.v1_19_4to1_19_3.rewriter.BlockItemPacketRewriter1_19_4;
import com.viaversion.viabackwards.protocol.v1_19_4to1_19_3.rewriter.ComponentRewriter1_19_4;
import com.viaversion.viabackwards.protocol.v1_19_4to1_19_3.rewriter.EntityPacketRewriter1_19_4;
import com.viaversion.viabackwards.protocol.v1_19_4to1_19_3.storage.EntityTracker1_19_4;
import com.viaversion.viaversion.api.connection.UserConnection;
@@ -38,6 +37,8 @@ import com.viaversion.viaversion.rewriter.BlockRewriter;
import com.viaversion.viaversion.rewriter.CommandRewriter;
import com.viaversion.viaversion.rewriter.ParticleRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
import com.viaversion.viaversion.rewriter.text.ComponentRewriterBase;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
public final class Protocol1_19_4To1_19_3 extends BackwardsProtocol<ClientboundPackets1_19_4, ClientboundPackets1_19_3, ServerboundPackets1_19_4, ServerboundPackets1_19_3> {
@@ -46,7 +47,7 @@ public final class Protocol1_19_4To1_19_3 extends BackwardsProtocol<ClientboundP
private final EntityPacketRewriter1_19_4 entityRewriter = new EntityPacketRewriter1_19_4(this);
private final BlockItemPacketRewriter1_19_4 itemRewriter = new BlockItemPacketRewriter1_19_4(this);
private final ParticleRewriter<ClientboundPackets1_19_4> particleRewriter = new ParticleRewriter<>(this);
private final JsonNBTComponentRewriter<ClientboundPackets1_19_4> translatableRewriter = new ComponentRewriter1_19_4(this);
private final JsonNBTComponentRewriter<ClientboundPackets1_19_4> translatableRewriter = new JsonNBTComponentRewriter<>(this, ComponentRewriterBase.ReadType.JSON);
private final TagRewriter<ClientboundPackets1_19_4> tagRewriter = new TagRewriter<>(this);
private final BlockRewriter<ClientboundPackets1_19_4> blockRewriter = BlockRewriter.for1_18(this, ChunkType1_18::new);
@@ -83,7 +84,7 @@ public final class Protocol1_19_4To1_19_3 extends BackwardsProtocol<ClientboundP
wrapper.write(Types.OPTIONAL_COMPONENT, element);
final byte[] iconBytes = wrapper.read(Types.OPTIONAL_BYTE_ARRAY_PRIMITIVE);
final String iconBase64 = iconBytes != null ? "data:image/png;base64," + Base64.getEncoder().encodeToString(iconBytes) : null;
final String iconBase64 = iconBytes != null ? "data:image/png;base64," + new String(Base64.getEncoder().encode(iconBytes), StandardCharsets.UTF_8) : null;
wrapper.write(Types.OPTIONAL_STRING, iconBase64);
});
@@ -1,42 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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_19_4to1_19_3.rewriter;
import com.viaversion.viabackwards.api.rewriters.text.JsonNBTComponentRewriter;
import com.viaversion.viabackwards.protocol.v1_19_4to1_19_3.Protocol1_19_4To1_19_3;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.libs.gson.JsonObject;
import com.viaversion.viaversion.protocols.v1_19_3to1_19_4.packet.ClientboundPackets1_19_4;
public final class ComponentRewriter1_19_4 extends JsonNBTComponentRewriter<ClientboundPackets1_19_4> {
public ComponentRewriter1_19_4(final Protocol1_19_4To1_19_3 protocol) {
super(protocol, ReadType.JSON);
}
@Override
protected void handleTranslate(final JsonObject root, final String translate) {
super.handleTranslate(root, translate);
if ((translate.startsWith("vb.item.") || translate.startsWith("vb.entity.")) && root.has("fallback")) {
// Add fallback as actual translate value
final JsonElement fallback = root.remove("fallback");
root.add("translate", fallback);
}
}
}
@@ -27,8 +27,7 @@ import com.viaversion.viabackwards.api.rewriters.EntityRewriter;
import com.viaversion.viabackwards.protocol.v1_19_4to1_19_3.Protocol1_19_4To1_19_3;
import com.viaversion.viabackwards.protocol.v1_19_4to1_19_3.storage.EntityTracker1_19_4;
import com.viaversion.viabackwards.protocol.v1_19_4to1_19_3.storage.LinkedEntityStorage;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.entity.TrackedEntity;
import com.viaversion.viaversion.api.data.entity.StoredEntityData;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_19_3;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_19_4;
@@ -40,24 +39,13 @@ import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.version.Types1_19_3;
import com.viaversion.viaversion.api.type.types.version.Types1_19_4;
import com.viaversion.viaversion.libs.fastutil.ints.IntArrayList;
import com.viaversion.viaversion.libs.fastutil.ints.IntList;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.libs.gson.JsonPrimitive;
import com.viaversion.viaversion.libs.mcstructs.text.TextComponent;
import com.viaversion.viaversion.libs.mcstructs.text.utils.TextUtils;
import com.viaversion.viaversion.protocols.v1_19_1to1_19_3.packet.ClientboundPackets1_19_3;
import com.viaversion.viaversion.protocols.v1_19_3to1_19_4.packet.ClientboundPackets1_19_4;
import com.viaversion.viaversion.util.SerializerVersion;
import com.viaversion.viaversion.util.TagUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.checkerframework.checker.nullness.qual.Nullable;
public final class EntityPacketRewriter1_19_4 extends EntityRewriter<ClientboundPackets1_19_4, Protocol1_19_4To1_19_3> {
private static final double TEXT_DISPLAY_LINE_HEIGHT = 0.25;
private static final double TEXT_DISPLAY_Y_OFFSET = -0.25; // Move emulated armor stands down to match text display height offsets
public EntityPacketRewriter1_19_4(final Protocol1_19_4To1_19_3 protocol) {
super(protocol, Types1_19_3.ENTITY_DATA_TYPES.optionalComponentType, Types1_19_3.ENTITY_DATA_TYPES.booleanType);
@@ -93,43 +81,27 @@ public final class EntityPacketRewriter1_19_4 extends EntityRewriter<Clientbound
final double y = wrapper.get(Types.DOUBLE, 1);
if (entityType == EntityTypes1_19_4.TEXT_DISPLAY.getId()) {
wrapper.set(Types.DOUBLE, 1, y - TEXT_DISPLAY_LINE_HEIGHT);
wrapper.set(Types.DOUBLE, 1, y + TEXT_DISPLAY_Y_OFFSET);
}
// First track (and remap) the entity, then store its position. Positions of all entities are
// needed to anchor and move the emulated text display lines when riding other entities
// Check against the UNMAPPED entity type
final TrackedEntity entity = trackAndRewrite(wrapper, entityType, entityId);
if (entity.entityType() == EntityTypes1_19_4.FALLING_BLOCK) {
final int blockState = wrapper.get(Types.VAR_INT, 2);
wrapper.set(Types.VAR_INT, 2, protocol.getMappingData().getNewBlockStateId(blockState));
// First track (and remap) entity, then put storage for block display entity
getSpawnTrackerWithDataHandler1_19().handle(wrapper);
if (entityType != EntityTypes1_19_4.BLOCK_DISPLAY.getId()) {
return;
}
final LinkedEntityStorage storage = new LinkedEntityStorage();
final double x = wrapper.get(Types.DOUBLE, 0);
final double z = wrapper.get(Types.DOUBLE, 2);
storage.setPosition(x, y, z);
entity.put(storage);
final StoredEntityData data = tracker(wrapper.user()).entityData(entityId);
if (data != null) {
final LinkedEntityStorage storage = new LinkedEntityStorage();
final double x = wrapper.get(Types.DOUBLE, 0);
final double z = wrapper.get(Types.DOUBLE, 2);
storage.setPosition(x, y, z);
data.put(storage);
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_19_4.ADD_PLAYER, wrapper -> {
final int entityId = wrapper.passthrough(Types.VAR_INT);
wrapper.passthrough(Types.UUID);
final double x = wrapper.passthrough(Types.DOUBLE);
final double y = wrapper.passthrough(Types.DOUBLE);
final double z = wrapper.passthrough(Types.DOUBLE);
// Also track players and their positions as possible vehicles of text displays
// (excluding the client player)
final EntityTracker1_19_4 tracker = tracker(wrapper.user());
final TrackedEntity entity = tracker.addEntity(entityId, EntityTypes1_19_4.PLAYER);
final LinkedEntityStorage storage = new LinkedEntityStorage();
storage.setPosition(x, y, z);
entity.put(storage);
});
protocol.registerClientbound(ClientboundPackets1_19_4.LOGIN, new PacketHandlers() {
@Override
public void register() {
@@ -179,8 +151,8 @@ public final class EntityPacketRewriter1_19_4 extends EntityRewriter<Clientbound
public void register() {
map(Types.VAR_INT, Types.INT); // Entity id
read(Types.VAR_INT); // Damage type
read(Types.OPTIONAL_VAR_INT); // Cause entity
read(Types.OPTIONAL_VAR_INT); // Direct cause entity
read(Types.VAR_INT); // Cause entity
read(Types.VAR_INT); // Direct cause entity
handler(wrapper -> {
// Source position
if (wrapper.read(Types.BOOLEAN)) {
@@ -193,14 +165,10 @@ public final class EntityPacketRewriter1_19_4 extends EntityRewriter<Clientbound
}
});
protocol.registerClientbound(ClientboundPackets1_19_4.HURT_ANIMATION, ClientboundPackets1_19_3.ANIMATE, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // Entity id
read(Types.FLOAT); // Yaw
create(Types.UNSIGNED_BYTE, (short) 1); // Hit
}
});
// The damage event above already maps to entity status 2, a superset of animate 1 on all
// 1.8-1.19.3 clients; forwarding both re-flashes the hurt when latency splits the pair.
// Cancelling restores pre-1.19.4 wire parity but drops plugin-sent standalone hurt animations.
protocol.cancelClientbound(ClientboundPackets1_19_4.HURT_ANIMATION);
protocol.registerClientbound(ClientboundPackets1_19_4.RESPAWN, new PacketHandlers() {
@Override
@@ -221,9 +189,8 @@ public final class EntityPacketRewriter1_19_4 extends EntityRewriter<Clientbound
wrapper.write(Types.VAR_INT, duration == -1 ? 999999 : duration);
});
// Track the position of entities to later spawn and move the linked entities.
// Block display passengers move with their vehicle, but the text display line entities have to be
// moved manually - both when the display itself moves and when a vehicle moves
// Track the position of block display entities to later spawn the linked entities, we will put them
// as passengers but the spawn position needs to be in the players view distance
protocol.registerClientbound(ClientboundPackets1_19_4.TELEPORT_ENTITY, wrapper -> {
final int entityId = wrapper.passthrough(Types.VAR_INT);
@@ -232,147 +199,31 @@ public final class EntityPacketRewriter1_19_4 extends EntityRewriter<Clientbound
final double z = wrapper.passthrough(Types.DOUBLE);
final EntityTracker1_19_4 tracker = tracker(wrapper.user());
final TrackedEntity entity = tracker.entity(entityId);
if (entity == null) {
return;
if (tracker.entityType(entityId) == EntityTypes1_19_4.TEXT_DISPLAY) {
wrapper.set(Types.DOUBLE, 1, y + TEXT_DISPLAY_Y_OFFSET);
}
final boolean textDisplay = entity.entityType() == EntityTypes1_19_4.TEXT_DISPLAY;
if (textDisplay) {
// Move emulated armor stands down to match text display height offsets
wrapper.set(Types.DOUBLE, 1, y - TEXT_DISPLAY_LINE_HEIGHT);
}
final LinkedEntityStorage storage = entity.get(LinkedEntityStorage.class);
if (storage == null) {
return;
}
final double deltaX = x - storage.x();
final double deltaY = y - storage.y();
final double deltaZ = z - storage.z();
storage.setPosition(x, y, z);
if (textDisplay) {
teleportTextDisplayLines(wrapper.user(), storage);
}
final int[] passengers = storage.passengers();
if (passengers != null) {
// Move emulated text display passengers along, keeping their offset to the vehicle
for (final int passenger : passengers) {
final LinkedEntityStorage passengerStorage = riddenTextDisplayStorage(tracker, passenger, entityId);
if (passengerStorage != null) {
passengerStorage.addRelativePosition(deltaX, deltaY, deltaZ);
sendTeleport(wrapper.user(), passenger, passengerStorage.x(), passengerStorage.y() - TEXT_DISPLAY_LINE_HEIGHT, passengerStorage.z());
teleportTextDisplayLines(wrapper.user(), passengerStorage);
}
}
final LinkedEntityStorage storage = tracker.linkedEntityStorage(entityId);
if (storage != null) {
storage.setPosition(x, y, z);
}
});
final PacketHandler entityPositionHandler = wrapper -> {
final int entityId = wrapper.passthrough(Types.VAR_INT);
final double x = wrapper.passthrough(Types.SHORT) / EntityPositionHandler.RELATIVE_MOVE_FACTOR;
final double y = wrapper.passthrough(Types.SHORT) / EntityPositionHandler.RELATIVE_MOVE_FACTOR;
final double z = wrapper.passthrough(Types.SHORT) / EntityPositionHandler.RELATIVE_MOVE_FACTOR;
final EntityTracker1_19_4 tracker = tracker(wrapper.user());
final TrackedEntity entity = tracker.entity(entityId);
if (entity == null) {
return;
}
final LinkedEntityStorage storage = entity.get(LinkedEntityStorage.class);
if (storage == null) {
return;
}
final short compressedX = wrapper.passthrough(Types.SHORT);
final short compressedY = wrapper.passthrough(Types.SHORT);
final short compressedZ = wrapper.passthrough(Types.SHORT);
final double deltaX = compressedX / EntityPositionHandler.RELATIVE_MOVE_FACTOR;
final double deltaY = compressedY / EntityPositionHandler.RELATIVE_MOVE_FACTOR;
final double deltaZ = compressedZ / EntityPositionHandler.RELATIVE_MOVE_FACTOR;
storage.addRelativePosition(deltaX, deltaY, deltaZ);
if (entity.entityType() == EntityTypes1_19_4.TEXT_DISPLAY) {
moveTextDisplayLines(wrapper.user(), storage, compressedX, compressedY, compressedZ);
}
// Move passengers along with vehicle
final int[] passengers = storage.passengers();
if (passengers != null) {
for (final int passenger : passengers) {
final LinkedEntityStorage passengerStorage = riddenTextDisplayStorage(tracker, passenger, entityId);
if (passengerStorage == null) {
continue;
}
passengerStorage.addRelativePosition(deltaX, deltaY, deltaZ);
sendRelativeMove(wrapper.user(), passenger, compressedX, compressedY, compressedZ);
moveTextDisplayLines(wrapper.user(), passengerStorage, compressedX, compressedY, compressedZ);
}
final LinkedEntityStorage storage = tracker.linkedEntityStorage(entityId);
if (storage != null) {
storage.addRelativePosition(x, y, z);
}
};
protocol.registerClientbound(ClientboundPackets1_19_4.MOVE_ENTITY_POS, entityPositionHandler);
protocol.registerClientbound(ClientboundPackets1_19_4.MOVE_ENTITY_POS_ROT, entityPositionHandler);
protocol.registerClientbound(ClientboundPackets1_19_4.SET_PASSENGERS, wrapper -> {
final int vehicleId = wrapper.passthrough(Types.VAR_INT);
final int[] passengers = wrapper.read(Types.VAR_INT_ARRAY_PRIMITIVE);
final EntityTracker1_19_4 tracker = tracker(wrapper.user());
final LinkedEntityStorage vehicleStorage = tracker.linkedEntityStorage(vehicleId);
if (vehicleStorage == null) {
wrapper.write(Types.VAR_INT_ARRAY_PRIMITIVE, passengers);
return;
}
// Unlink all previous passengers. Those still riding are attached again below
if (vehicleStorage.passengers() != null) {
for (final int previousPassenger : vehicleStorage.passengers()) {
final LinkedEntityStorage passengerStorage = tracker.linkedEntityStorage(previousPassenger);
if (passengerStorage != null && passengerStorage.isVehicle(vehicleId)) {
passengerStorage.setVehicleId(null);
}
}
}
boolean hasTextDisplay = false;
final IntList filteredPassengers = new IntArrayList(passengers.length);
for (final int passenger : passengers) {
if (tracker.entityType(passenger) != EntityTypes1_19_4.TEXT_DISPLAY) {
filteredPassengers.add(passenger);
continue;
}
hasTextDisplay = true;
final LinkedEntityStorage passengerStorage = tracker.linkedEntityStorage(passenger);
if (passengerStorage == null) {
filteredPassengers.add(passenger);
continue;
}
passengerStorage.setVehicleId(vehicleId);
if (passengerStorage.entities() == null) {
// Single-line text display
filteredPassengers.add(passenger);
continue;
}
// Keep the position if it is already close to the vehicle, else we'd have to calculate entity heights for passenger offsets
final double distanceX = passengerStorage.x() - vehicleStorage.x();
final double distanceY = passengerStorage.y() - vehicleStorage.y();
final double distanceZ = passengerStorage.z() - vehicleStorage.z();
if ((distanceX * distanceX) + (distanceY * distanceY) + (distanceZ * distanceZ) > 4 * 4) {
passengerStorage.setPosition(vehicleStorage.x(), vehicleStorage.y(), vehicleStorage.z());
sendTeleport(wrapper.user(), passenger, passengerStorage.x(), passengerStorage.y() - TEXT_DISPLAY_LINE_HEIGHT, passengerStorage.z());
teleportTextDisplayLines(wrapper.user(), passengerStorage);
}
}
// Only needed to move text display passengers along, so skip storing other passenger lists
vehicleStorage.setPassengers(hasTextDisplay ? passengers : null);
wrapper.write(Types.VAR_INT_ARRAY_PRIMITIVE, filteredPassengers.size() == passengers.length ? passengers : filteredPassengers.toIntArray());
});
}
@Override
@@ -404,71 +255,17 @@ public final class EntityPacketRewriter1_19_4 extends EntityRewriter<Clientbound
event.setIndex(2);
data.setDataType(Types1_19_3.ENTITY_DATA_TYPES.optionalComponentType);
event.createExtraData(new EntityData(3, Types1_19_3.ENTITY_DATA_TYPES.booleanType, true)); // Show custom name
// The armor stand name is rendered as a single line an doesn't support new lines,
// so extra lines have to be moved to their own armor stands, stacked upwards.
final EntityTracker1_19_4 tracker = tracker(event.user());
final JsonElement component = data.value();
if (!containsNewLine(component)) { // Avoid parsing the full component where possible
clearTextDisplayLines(event.user(), tracker, event.entityId());
return;
}
final TextComponent[] lines = TextUtils.split(SerializerVersion.V1_19_4.toComponent(component), "\n", false);
if (lines.length <= 1) {
clearTextDisplayLines(event.user(), tracker, event.entityId());
return;
}
data.setValue(SerializerVersion.V1_19_4.toJson(lines[lines.length - 1])); // Bottom line stays on the actual entity
final LinkedEntityStorage storage = tracker.linkedEntityStorage(event.entityId());
if (storage == null) {
return;
}
final int extraLines = lines.length - 1;
int[] entities = storage.entities();
if (entities == null || entities.length != extraLines) {
final boolean mountedOnClient = entities == null && storage.vehicleId() != null;
tracker.clearLinkedEntities(storage);
final LinkedEntityStorage vehicleStorage = mountedOnClient ? tracker.linkedEntityStorage(storage.vehicleId()) : null;
if (vehicleStorage != null) {
// The display position wasn't tracked while it was mounted client-side; anchor it to the vehicle
storage.setPosition(vehicleStorage.x(), vehicleStorage.y(), vehicleStorage.z());
}
entities = new int[extraLines];
for (int i = 0; i < extraLines; i++) {
final double y = storage.y() + (TEXT_DISPLAY_LINE_HEIGHT * i);
entities[i] = tracker.spawnEntity(EntityTypes1_19_3.ARMOR_STAND, storage.x(), y, storage.z(), 0);
}
storage.setEntities(entities);
if (vehicleStorage != null) {
// The now multi-line display was mounted client-side; dismount and position it manually from now on
sendVehiclePassengers(event.user(), tracker, storage.vehicleId());
sendTeleport(event.user(), event.entityId(), storage.x(), storage.y() - TEXT_DISPLAY_LINE_HEIGHT, storage.z());
}
}
// Send in inverse order
for (int i = 0; i < extraLines; i++) {
sendLineData(event.user(), entities[i], SerializerVersion.V1_19_4.toJson(lines[extraLines - 1 - i]));
}
}));
filter().type(EntityTypes1_19_4.BLOCK_DISPLAY).index(22).handler((event, data) -> {
final int value = data.value();
final EntityTracker1_19_4 tracker = tracker(event.user());
final LinkedEntityStorage storage = event.trackedEntity().get(LinkedEntityStorage.class);
tracker.clearLinkedEntities(event.entityId());
final LinkedEntityStorage storage = tracker.linkedEntityStorage(event.entityId());
if (storage == null) {
return;
}
tracker.clearLinkedEntities(storage);
final int linkedEntity = tracker.spawnEntity(EntityTypes1_19_3.FALLING_BLOCK, storage.x(), storage.y(), storage.z(), value);
storage.setEntities(linkedEntity);
@@ -504,134 +301,6 @@ public final class EntityPacketRewriter1_19_4 extends EntityRewriter<Clientbound
filter().type(EntityTypes1_19_4.ABSTRACT_HORSE).addIndex(18); // Owner UUID
}
private void clearTextDisplayLines(final UserConnection connection, final EntityTracker1_19_4 tracker, final int entityId) {
final LinkedEntityStorage storage = tracker.linkedEntityStorage(entityId);
if (storage == null || storage.entities() == null) {
return;
}
tracker.clearLinkedEntities(storage);
sendVehiclePassengers(connection, tracker, storage.vehicleId()); // Mount the now single-line display again
}
private LinkedEntityStorage riddenTextDisplayStorage(final EntityTracker1_19_4 tracker, final int entityId, final int vehicleId) {
final TrackedEntity entity = tracker.entity(entityId);
if (entity == null || entity.entityType() != EntityTypes1_19_4.TEXT_DISPLAY) {
return null;
}
final LinkedEntityStorage storage = entity.get(LinkedEntityStorage.class);
return storage != null && storage.entities() != null && storage.isVehicle(vehicleId) ? storage : null;
}
private boolean isMultiLineTextDisplay(final EntityTracker1_19_4 tracker, final int entityId) {
if (tracker.entityType(entityId) != EntityTypes1_19_4.TEXT_DISPLAY) {
return false;
}
final LinkedEntityStorage storage = tracker.linkedEntityStorage(entityId);
return storage != null && storage.entities() != null;
}
private int[] withoutMultiLineTextDisplays(final EntityTracker1_19_4 tracker, final int[] passengers) {
final IntList filtered = new IntArrayList(passengers.length);
for (final int passenger : passengers) {
if (!isMultiLineTextDisplay(tracker, passenger)) {
filtered.add(passenger);
}
}
return filtered.size() == passengers.length ? passengers : filtered.toIntArray();
}
private void sendVehiclePassengers(final UserConnection connection, final EntityTracker1_19_4 tracker, @Nullable final Integer vehicleId) {
if (vehicleId == null) {
return;
}
final LinkedEntityStorage vehicleStorage = tracker.linkedEntityStorage(vehicleId);
if (vehicleStorage == null || vehicleStorage.passengers() == null) {
return;
}
final PacketWrapper wrapper = PacketWrapper.create(ClientboundPackets1_19_3.SET_PASSENGERS, connection);
wrapper.write(Types.VAR_INT, vehicleId);
wrapper.write(Types.VAR_INT_ARRAY_PRIMITIVE, withoutMultiLineTextDisplays(tracker, vehicleStorage.passengers()));
wrapper.send(Protocol1_19_4To1_19_3.class);
}
private void teleportTextDisplayLines(final UserConnection connection, final LinkedEntityStorage storage) {
final int[] entities = storage.entities();
if (entities == null) {
return;
}
for (int i = 0; i < entities.length; i++) {
sendTeleport(connection, entities[i], storage.x(), storage.y() + (TEXT_DISPLAY_LINE_HEIGHT * i), storage.z());
}
}
private void moveTextDisplayLines(final UserConnection connection, final LinkedEntityStorage storage, final short deltaX, final short deltaY, final short deltaZ) {
final int[] entities = storage.entities();
if (entities == null) {
return;
}
for (final int entity : entities) {
sendRelativeMove(connection, entity, deltaX, deltaY, deltaZ);
}
}
private void sendTeleport(final UserConnection connection, final int entityId, final double x, final double y, final double z) {
final PacketWrapper teleport = PacketWrapper.create(ClientboundPackets1_19_3.TELEPORT_ENTITY, connection);
teleport.write(Types.VAR_INT, entityId);
teleport.write(Types.DOUBLE, x);
teleport.write(Types.DOUBLE, y);
teleport.write(Types.DOUBLE, z);
teleport.write(Types.BYTE, (byte) 0); // Yaw
teleport.write(Types.BYTE, (byte) 0); // Pitch
teleport.write(Types.BOOLEAN, false); // On ground
teleport.send(Protocol1_19_4To1_19_3.class);
}
private void sendRelativeMove(final UserConnection connection, final int entityId, final short deltaX, final short deltaY, final short deltaZ) {
final PacketWrapper move = PacketWrapper.create(ClientboundPackets1_19_3.MOVE_ENTITY_POS, connection);
move.write(Types.VAR_INT, entityId);
move.write(Types.SHORT, deltaX);
move.write(Types.SHORT, deltaY);
move.write(Types.SHORT, deltaZ);
move.write(Types.BOOLEAN, false); // On ground
move.send(Protocol1_19_4To1_19_3.class);
}
private static boolean containsNewLine(final JsonElement element) {
if (element.isJsonPrimitive()) {
final JsonPrimitive primitive = element.getAsJsonPrimitive();
return primitive.isString() && primitive.getAsString().indexOf('\n') != -1;
} else if (element.isJsonArray()) {
for (final JsonElement entry : element.getAsJsonArray()) {
if (containsNewLine(entry)) {
return true;
}
}
} else if (element.isJsonObject()) {
for (final Map.Entry<String, JsonElement> entry : element.getAsJsonObject().entrySet()) {
if (containsNewLine(entry.getValue())) {
return true;
}
}
}
return false;
}
private void sendLineData(final UserConnection connection, final int entityId, final JsonElement text) {
final List<EntityData> data = new ArrayList<>();
data.add(new EntityData(0, Types1_19_3.ENTITY_DATA_TYPES.byteType, (byte) 0x20)); // Invisible
data.add(new EntityData(2, Types1_19_3.ENTITY_DATA_TYPES.optionalComponentType, text)); // Custom name
data.add(new EntityData(3, Types1_19_3.ENTITY_DATA_TYPES.booleanType, true)); // Show custom name
data.add(new EntityData(5, Types1_19_3.ENTITY_DATA_TYPES.booleanType, true)); // No gravity
data.add(new EntityData(15, Types1_19_3.ENTITY_DATA_TYPES.byteType, (byte) (0x01 | 0x10))); // Small marker
final PacketWrapper wrapper = PacketWrapper.create(ClientboundPackets1_19_3.SET_ENTITY_DATA, connection);
wrapper.write(Types.VAR_INT, entityId);
wrapper.write(Types1_19_3.ENTITY_DATA_LIST, data);
wrapper.send(Protocol1_19_4To1_19_3.class);
}
@Override
public void onMappingDataLoaded() {
super.onMappingDataLoaded();
@@ -30,7 +30,6 @@ import com.viaversion.viaversion.libs.fastutil.ints.IntSet;
import com.viaversion.viaversion.protocols.v1_19_1to1_19_3.packet.ClientboundPackets1_19_3;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import org.checkerframework.checker.nullness.qual.Nullable;
public final class EntityTracker1_19_4 extends EntityTrackerBase {
@@ -59,35 +58,44 @@ public final class EntityTracker1_19_4 extends EntityTrackerBase {
addEntity.write(Types.SHORT, (short) 0); // Velocity Z
addEntity.send(Protocol1_19_4To1_19_3.class);
generatedEntities.add(entityId);
return entityId;
}
@Override
public @Nullable TrackedEntity removeEntity(final int id) {
final TrackedEntity entity = super.removeEntity(id);
if (entity != null) {
clearLinkedEntities(entity.get(LinkedEntityStorage.class));
public void clearEntities() {
for (final int id : entities.keySet()) {
clearLinkedEntities(id);
}
return entity;
super.clearEntities();
}
public void clearLinkedEntities(final LinkedEntityStorage storage) {
@Override
public void removeEntity(final int id) {
clearLinkedEntities(id);
super.removeEntity(id);
}
public void clearLinkedEntities(final int id) {
final LinkedEntityStorage storage = linkedEntityStorage(id);
if (storage != null && storage.entities() != null) {
for (final int entity : storage.entities()) {
generatedEntities.remove(entity);
}
storage.remove(user());
generatedEntities.remove(id);
}
}
public @Nullable LinkedEntityStorage linkedEntityStorage(final int id) {
public LinkedEntityStorage linkedEntityStorage(final int id) {
final TrackedEntity entity = entity(id);
return entity != null ? entity.get(LinkedEntityStorage.class) : null;
if (entity != null && entity.hasData()) {
return entity.data().get(LinkedEntityStorage.class);
}
return null;
}
private int nextEntityId() {
final int entityId = ThreadLocalRandom.current().nextInt(-1_000_000, -1);
if (!generatedEntities.add(entityId)) {
final int entityId = -ThreadLocalRandom.current().nextInt(10_000);
if (generatedEntities.contains(entityId)) {
return nextEntityId();
}
return entityId;
@@ -24,15 +24,12 @@ 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.protocols.v1_19_1to1_19_3.packet.ClientboundPackets1_19_3;
import org.checkerframework.checker.nullness.qual.Nullable;
public class LinkedEntityStorage extends EntityPositionStorage implements StorableObject {
private int[] entities;
private int[] passengers;
private Integer vehicleId;
public int @Nullable [] entities() {
public int[] entities() {
return entities;
}
@@ -40,31 +37,10 @@ public class LinkedEntityStorage extends EntityPositionStorage implements Storab
this.entities = entities;
}
public int @Nullable [] passengers() {
return passengers;
}
public void setPassengers(final int... passengers) {
this.passengers = passengers;
}
public @Nullable Integer vehicleId() {
return vehicleId;
}
public boolean isVehicle(final int vehicleId) {
return this.vehicleId != null && this.vehicleId == vehicleId;
}
public void setVehicleId(@Nullable final Integer vehicleId) {
this.vehicleId = vehicleId;
}
public void remove(final UserConnection connection) {
final PacketWrapper wrapper = PacketWrapper.create(ClientboundPackets1_19_3.REMOVE_ENTITIES, connection);
wrapper.write(Types.VAR_INT_ARRAY_PRIMITIVE, entities);
wrapper.send(Protocol1_19_4To1_19_3.class);
entities = null;
}
}
@@ -24,14 +24,21 @@ import com.viaversion.viabackwards.protocol.v1_19to1_18_2.Protocol1_19To1_18_2;
import com.viaversion.viabackwards.protocol.v1_19to1_18_2.storage.LastDeathPosition;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.ParticleMappings;
import com.viaversion.viaversion.api.data.entity.EntityTracker;
import com.viaversion.viaversion.api.minecraft.GlobalBlockPosition;
import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
import com.viaversion.viaversion.api.minecraft.chunks.ChunkSection;
import com.viaversion.viaversion.api.minecraft.chunks.DataPalette;
import com.viaversion.viaversion.api.minecraft.chunks.PaletteType;
import com.viaversion.viaversion.api.minecraft.item.Item;
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_18;
import com.viaversion.viaversion.protocols.v1_16_4to1_17.packet.ServerboundPackets1_17;
import com.viaversion.viaversion.protocols.v1_18_2to1_19.packet.ClientboundPackets1_19;
import com.viaversion.viaversion.rewriter.RecipeRewriter;
import com.viaversion.viaversion.util.MathUtil;
public final class BlockItemPacketRewriter1_19 extends BackwardsItemRewriter<ClientboundPackets1_19, ServerboundPackets1_17, Protocol1_19To1_18_2> {
@@ -180,7 +187,6 @@ public final class BlockItemPacketRewriter1_19 extends BackwardsItemRewriter<Cli
final int identifier = item.identifier();
item = super.handleItemToClient(connection, item);
enchantmentRewriter.handleToClient(item);
if (identifier != 834) {
return item;
@@ -199,6 +205,8 @@ public final class BlockItemPacketRewriter1_19 extends BackwardsItemRewriter<Cli
lodestonePosTag.putInt("X", position.x());
lodestonePosTag.putInt("Y", position.y());
lodestonePosTag.putInt("Z", position.z());
enchantmentRewriter.handleToClient(item);
return item;
}
@@ -28,7 +28,7 @@ import com.viaversion.viabackwards.protocol.v1_19to1_18_2.storage.EntityTracker1
import com.viaversion.viabackwards.protocol.v1_19to1_18_2.storage.LastDeathPosition;
import com.viaversion.viabackwards.protocol.v1_19to1_18_2.storage.StoredPainting;
import com.viaversion.viaversion.api.data.ParticleMappings;
import com.viaversion.viaversion.api.data.entity.TrackedEntity;
import com.viaversion.viaversion.api.data.entity.StoredEntityData;
import com.viaversion.viaversion.api.minecraft.BlockPosition;
import com.viaversion.viaversion.api.minecraft.GlobalBlockPosition;
import com.viaversion.viaversion.api.minecraft.Particle;
@@ -49,6 +49,12 @@ import com.viaversion.viaversion.util.TagUtil;
public final class EntityPacketRewriter1_19 extends EntityRewriter<ClientboundPackets1_19, Protocol1_19To1_18_2> {
private static final IntSet WIDE_PAINTINGS = IntOpenHashSet.of(
7, 8, 9, 10, 11,
14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25
);
public EntityPacketRewriter1_19(final Protocol1_19To1_18_2 protocol) {
super(protocol);
}
@@ -73,10 +79,8 @@ public final class EntityPacketRewriter1_19 extends EntityRewriter<ClientboundPa
handler(wrapper -> {
final byte headYaw = wrapper.read(Types.BYTE);
int data = wrapper.read(Types.VAR_INT);
final int entityId = wrapper.get(Types.VAR_INT, 0);
final int typeId = wrapper.get(Types.VAR_INT, 1);
final TrackedEntity entity = trackAndRewrite(wrapper, typeId, entityId);
if (entity.entityType().isOrHasParent(EntityTypes1_19.LIVING_ENTITY)) {
final EntityType entityType = trackAndMapEntity(wrapper);
if (entityType.isOrHasParent(EntityTypes1_19.LIVING_ENTITY)) {
wrapper.write(Types.BYTE, headYaw);
// Switch pitch and yaw position
@@ -87,18 +91,20 @@ public final class EntityPacketRewriter1_19 extends EntityRewriter<ClientboundPa
wrapper.setPacketType(ClientboundPackets1_18.ADD_MOB);
return;
} else if (entity.entityType() == EntityTypes1_19.PAINTING) {
} else if (entityType == EntityTypes1_19.PAINTING) {
wrapper.cancel();
// The entity has been tracked, now we wait for the entity data packet
final int entityId = wrapper.get(Types.VAR_INT, 0);
final StoredEntityData entityData = tracker(wrapper.user()).entityData(entityId);
final int x = wrapper.get(Types.DOUBLE, 0).intValue();
final int y = wrapper.get(Types.DOUBLE, 1).intValue();
final int z = wrapper.get(Types.DOUBLE, 2).intValue();
final BlockPosition position = new BlockPosition(x, y, z);
entity.put(new StoredPainting(entityId, wrapper.get(Types.UUID, 0), position, data));
entityData.put(new StoredPainting(entityId, wrapper.get(Types.UUID, 0), position, data));
return;
}
if (entity.entityType() == EntityTypes1_19.FALLING_BLOCK) {
if (entityType == EntityTypes1_19.FALLING_BLOCK) {
data = protocol.getMappingData().getNewBlockStateId(data);
}
wrapper.write(Types.INT, data);
@@ -116,70 +122,19 @@ public final class EntityPacketRewriter1_19 extends EntityRewriter<ClientboundPa
final double y = wrapper.read(Types.DOUBLE);
final double z = wrapper.read(Types.DOUBLE);
final TrackedEntity entity = tracker(wrapper.user()).entity(entityId);
final StoredPainting storedPainting = entity != null ? entity.get(StoredPainting.class) : null;
if (storedPainting == null) {
final StoredEntityData entityData = tracker(wrapper.user()).entityDataIfPresent(entityId);
final StoredPainting storedPainting = entityData != null ? entityData.get(StoredPainting.class) : null;
// Presumably there is a more correct way of fixing this? Only north and east looking paintings with a width of >1 seem to be extra special
if (storedPainting != null && (storedPainting.direction() == 2 || storedPainting.direction() == 3)
&& WIDE_PAINTINGS.contains(storedPainting.type())) {
wrapper.write(Types.DOUBLE, storedPainting.direction() == 2 ? x : x + 1);
wrapper.write(Types.DOUBLE, y + 1);
wrapper.write(Types.DOUBLE, storedPainting.direction() == 3 ? z : z + 1);
} else {
wrapper.write(Types.DOUBLE, x + 1);
wrapper.write(Types.DOUBLE, y + 1);
wrapper.write(Types.DOUBLE, z + 1);
return;
}
// In 1.18 and below, the teleport position is the painting entity's position.
// In 1.19+, it is the block position the painting is attached to.
// The game calculates the entity's position as follows.
// See PaintingVariants in 1.19
double width = 0, height = 0;
int type = storedPainting.type();
if (type <= 6) {
width = 16;
height = 16;
} else if (type <= 11) {
width = 32;
height = 16;
} else if (type <= 13) {
width = 16;
height = 32;
} else if (type <= 19 || (type >= 25 && type <= 28)) {
width = 32;
height = 32;
} else if (type == 20) {
width = 64;
height = 32;
} else if (type <= 23) {
width = 64;
height = 64;
} else if (type == 24 || type == 29) {
width = 64;
height = 48;
}
// See HangingEntity#recalculateBoundingBox
double resX = x + 0.5, resY = y + 0.5, resZ = z + 0.5;
final double againstWall = -0.46875;
switch (storedPainting.direction()) {
case 2 -> resZ -= againstWall; // North -z
case 0 -> resZ += againstWall; // South +z
case 1 -> resX -= againstWall; // West -x
case 3 -> resX += againstWall; // East +x
}
// Counter-clockwise
final double horizontalOffset = width % 32 == 0 ? 0.5 : 0.0;
final double verticalOffset = height % 32 == 0 ? 0.5 : 0.0;
resY += verticalOffset;
switch (storedPainting.direction()) {
case 3 -> resZ -= horizontalOffset; // East -> North -z
case 1 -> resZ += horizontalOffset; // West -> South +z
case 2 -> resX -= horizontalOffset; // North -> West -x
case 0 -> resX += horizontalOffset; // South -> East +x
}
wrapper.write(Types.DOUBLE, resX);
wrapper.write(Types.DOUBLE, resY);
wrapper.write(Types.DOUBLE, resZ);
});
protocol.registerClientbound(ClientboundPackets1_19.UPDATE_MOB_EFFECT, new PacketHandlers() {
@@ -406,19 +361,11 @@ public final class EntityPacketRewriter1_19 extends EntityRewriter<ClientboundPa
filter().type(EntityTypes1_19.PAINTING).index(8).handler((event, data) -> {
event.cancel();
final TrackedEntity entity = tracker(event.user()).entity(event.entityId());
final StoredPainting storedPainting = entity != null ? entity.get(StoredPainting.class) : null;
final StoredEntityData entityData = tracker(event.user()).entityDataIfPresent(event.entityId());
final StoredPainting storedPainting = entityData != null ? entityData.get(StoredPainting.class) : null;
if (storedPainting != null) {
int type = data.value();
final int type = data.value();
storedPainting.setType(type);
type = switch (type) {
case 29 -> 25; // kong painting changed ID
case 25 -> 19; // earth -> wither
case 26 -> 16; // wind -> stage
case 27 -> 18; // water -> skull_and_roses
case 28 -> 14; // fire -> match
default -> type;
};
final PacketWrapper packet = PacketWrapper.create(ClientboundPackets1_18.ADD_PAINTING, event.user());
packet.write(Types.VAR_INT, storedPainting.entityId());
@@ -18,12 +18,10 @@
package com.viaversion.viabackwards.protocol.v1_19to1_18_2.storage;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.entity.TrackedEntity;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_19;
import com.viaversion.viaversion.data.entity.EntityTrackerBase;
import com.viaversion.viaversion.libs.fastutil.ints.IntArrayList;
import com.viaversion.viaversion.libs.fastutil.ints.IntList;
import org.checkerframework.checker.nullness.qual.Nullable;
public final class EntityTracker1_19 extends EntityTrackerBase {
@@ -35,10 +33,10 @@ public final class EntityTracker1_19 extends EntityTrackerBase {
}
@Override
public @Nullable TrackedEntity removeEntity(final int id) {
public void removeEntity(final int id) {
super.removeEntity(id);
this.affectedByBlindness.rem(id);
this.affectedByDarkness.rem(id);
return super.removeEntity(id);
}
public IntList getAffectedByBlindness() {
@@ -79,30 +79,26 @@ public final class EntityPacketRewriter1_20_2 extends EntityRewriter<Clientbound
final byte pitch = wrapper.read(Types.BYTE);
wrapper.passthrough(Types.BYTE); // Yaw
wrapper.write(Types.BYTE, pitch);
final byte headYaw = wrapper.read(Types.BYTE); // Head yaw
wrapper.read(Types.BYTE); // Head yaw
wrapper.read(Types.VAR_INT); // Data
final short velocityX = wrapper.read(Types.SHORT);
final short velocityY = wrapper.read(Types.SHORT);
final short velocityZ = wrapper.read(Types.SHORT);
if (velocityX == 0 && velocityY == 0 && velocityZ == 0) {
return;
}
// Follow up with velocity packet
wrapper.send(Protocol1_20_2To1_20.class);
wrapper.cancel();
final PacketWrapper headRotation = wrapper.create(ClientboundPackets1_19_4.ROTATE_HEAD);
headRotation.write(Types.VAR_INT, entityId);
headRotation.write(Types.BYTE, headYaw);
headRotation.send(Protocol1_20_2To1_20.class);
// Follow up with velocity packet
if (velocityX != 0 || velocityY != 0 || velocityZ != 0) {
final PacketWrapper velocityPacket = wrapper.create(ClientboundPackets1_19_4.SET_ENTITY_MOTION);
velocityPacket.write(Types.VAR_INT, entityId);
velocityPacket.write(Types.SHORT, velocityX);
velocityPacket.write(Types.SHORT, velocityY);
velocityPacket.write(Types.SHORT, velocityZ);
velocityPacket.send(Protocol1_20_2To1_20.class);
}
final PacketWrapper velocityPacket = wrapper.create(ClientboundPackets1_19_4.SET_ENTITY_MOTION);
velocityPacket.write(Types.VAR_INT, entityId);
velocityPacket.write(Types.SHORT, velocityX);
velocityPacket.write(Types.SHORT, velocityY);
velocityPacket.write(Types.SHORT, velocityZ);
velocityPacket.send(Protocol1_20_2To1_20.class);
});
}
});
Loaded 100 of 198 files, more files were not shown because too many files have changed in this diff. Show more