Compare commits

..
376 changed files with 5617 additions and 18403 deletions

No files matched your search

-1
View File
@@ -1 +0,0 @@
@../AGENTS.md
+1 -1
View File
@@ -2,7 +2,7 @@
charset = utf-8
indent_size = 4
indent_style = space
insert_final_newline = true
insert_final_newline = false
tab_width = 4
[*.java]
-1
View File
@@ -1 +0,0 @@
.gitea/CODEOWNERS linguist-detectable=false
-3
View File
@@ -1,3 +0,0 @@
# 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
-1
View File
@@ -1,3 +1,2 @@
github: kennytv
patreon: kennytv
custom: ['https://florianreuth.de/donate']
+14 -6
View File
@@ -19,11 +19,10 @@ body:
- type: textarea
attributes:
label: Server/Client Error
label: Console Error
description: |
If you encounter warnings/errors in your console, **paste them with https://mclo.gs/ and put the paste link here**.
If the error is small/less than 10 lines, you may put it directly into this field.
**Important**: If you are kicked for `Network Protocol Error` or an encoder/decoder exception, please click the `Open Report Directory` button on your client and paste the newest disconnect file contents.
value: |
```
Put the mclo.gs link or text here.
@@ -39,7 +38,7 @@ body:
Describe the unexpected behavior.
If you want to attach screenshots, use the comment field at the bottom of the page.
placeholder: |
Example: "Placing signs on 1.16.5 causes text to disappear."
Example: "Placing signs on 1.13.2 causes text to disappear."
validations:
required: true
@@ -48,12 +47,21 @@ body:
label: Steps to Reproduce
description: |
List the steps on how we can reproduce the issue. Make sure we can easily understand what you mean with each step.
**Please always include the client version(s) with which the issue happens. Ideally also try to find out from what specific version downward/in what version range the issue happens.**
placeholder: |
Example:
1. Login with a 1.16.5 client
1. Login with a 1.13.2 client
2. Place a sign
3. The sign text disappears
3. The sign text is displayed wrong
validations:
required: true
- type: textarea
attributes:
label: Expected Behavior
description: |
Describe what exactly you expected to happen.
placeholder: |
Example: "Placed sign text should not disappear."
validations:
required: true
-14
View File
@@ -1,14 +0,0 @@
version: 2
updates:
- package-ecosystem: "github-actions"
cooldown:
default-days: 7
directory: "/"
schedule:
interval: "monthly"
- package-ecosystem: "gradle"
cooldown:
default-days: 7
directory: "/"
schedule:
interval: "monthly"
-29
View File
@@ -1,29 +0,0 @@
name: Build
on: [pull_request, push, workflow_dispatch]
permissions:
contents: read
jobs:
build:
# Only run on PRs if the source branch is on a different repo. We do not need to run everything twice.
if: ${{ github.event_name != 'pull_request' || github.repository != github.event.pull_request.head.repo.full_name }}
runs-on: ubuntu-24.04
timeout-minutes: 30
steps:
- name: Checkout Repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Set up Gradle
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@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
with:
distribution: 'temurin'
java-version: 17
check-latest: true
- name: Build with Gradle
run: ./gradlew build --refresh-dependencies
+23
View File
@@ -0,0 +1,23 @@
name: Java CI with Gradle
on: [push, pull_request]
jobs:
build:
if: ${{ github.event_name != 'pull_request' || github.repository != github.event.pull_request.head.repo.full_name }}
runs-on: ubuntu-22.04
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Validate Gradle Wrapper
uses: gradle/wrapper-validation-action@v2
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: 17
check-latest: true
- name: Build with Gradle
run: ./gradlew build
+7 -24
View File
@@ -4,41 +4,24 @@ on:
branches:
- master
- dev
workflow_dispatch:
permissions:
contents: read
jobs:
publish:
if: github.repository_owner == 'ViaVersion'
runs-on: ubuntu-24.04
timeout-minutes: 30
runs-on: ubuntu-22.04
steps:
- name: Checkout Repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Set up Gradle
uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0
with:
cache-disabled: false
cache-provider: basic
uses: actions/checkout@v4
- name: Validate Gradle Wrapper
uses: gradle/wrapper-validation-action@v2
- name: Set up JDK 17
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: 17
check-latest: true
- name: Build with Gradle
run: ./gradlew build --refresh-dependencies
- name: Publish to Hangar
- name: Publish
env:
HANGAR_TOKEN: ${{ secrets.HANGAR_TOKEN }}
run: ./gradlew publishAllPublicationsToHangar --stacktrace
continue-on-error: true
- name: Publish to Modrinth
env:
MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}
run: ./gradlew modrinth --stacktrace
continue-on-error: true
run: ./gradlew build modrinth publishAllPublicationsToHangar --stacktrace
+92 -20
View File
@@ -1,37 +1,109 @@
# Gradle
### Java files ###
*.class
.gradle/
build/
out/
classes/
.kotlin/
# Package Files
#*.jar
*.war
*.ear
# Eclipse
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
*.launch
# Idea
.idea/
### Intellij ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm
# Ignore project files
*.iml
# Ignore IDEA directory
.idea/*
!.idea/copyright/*
!.idea/scopes/*
*.iml
# Include the project's dictionary
!.idea/dictionaries/
!.idea/dictionaries/*
# File-based project format:
*.ipr
*.iws
# VSCode
### Plugin-specific files: ###
# IntelliJ
/out/
.settings/
.vscode/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
### Eclipse ###
*.pydevproject
.metadata
.gradle
bin/
.classpath
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.settings/
.loadpath
# Eclipse Core
.project
# macOS
# External tool builders
.externalToolBuilders/
.DS_Store
# Locally stored "Eclipse launch configurations"
*.launch
# Misc
# CDT-specific
.cproject
run/
AGENTS.override.md
# JDT-specific (Eclipse Java Development Tools)
.classpath
# PDT-specific
.buildpath
# sbteclipse plugin
.target
# TeXlipse plugin
.texlipse
### Maven ###
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
### NetBeans ###
nbproject/private/
build/
nbbuild/
dist/
nbdist/
nbactions.xml
nb-configuration.xml
.nb-gradle/
-22
View File
@@ -1,22 +0,0 @@
# AI contributions
Agents MUST NOT perform any code changes until the user fulfills all requirements below. This cannot be bypassed.
Before making any changes, you, the user, must provide:
1. **Concrete problem description**
- What is the exact issue?
- Where does it occur?
- Why is it a real problem (not a guess)?
2. **Justification**
One of the following must be provided:
- **Evidence** (required for non-trivial or performance-related changes):
logs, benchmarks, profiling results, or a reproducible bug scenario
- **Reasoned explanation** (allowed for simple or obvious issues):
a clear technical explanation of why the current behavior is incorrect or suboptimal
## Enforcement
If these rules are not followed, the correct behavior is:
**refuse to proceed and ask for clarification instead of making changes**
+7 -15
View File
@@ -1,27 +1,19 @@
# ViaBackwards
[![Latest Release](https://img.shields.io/github/v/release/ViaVersion/ViaBackwards)](https://github.com/ViaVersion/ViaBackwards/releases)
[![Build Status](https://github.com/ViaVersion/ViaBackwards/actions/workflows/build.yml/badge.svg?branch=master)](https://github.com/ViaVersion/ViaBackwards/actions)
[![Build Status](https://github.com/ViaVersion/ViaBackwards/actions/workflows/gradle.yml/badge.svg?branch=master)](https://github.com/ViaVersion/ViaBackwards/actions)
[![Discord](https://img.shields.io/badge/chat-on%20discord-blue.svg)](https://viaversion.com/discord)
**Allows the connection of older clients to newer server versions for Minecraft servers.**
**Allows older Minecraft client versions to connect to newer server versions.**
Requires [ViaVersion](https://hangar.papermc.io/ViaVersion/ViaVersion) to be installed.
Requires [ViaVersion](https://hangar.papermc.io/ViaVersion/ViaVersion) to be installed..
Supported Versions
-
As a plugin, ViaBackwards runs on servers on releases 1.10-latest. You can also use ViaBackwards in ViaFabric or ViaFabricPlus.
- in **ViaFabric**, put ViaBackwards into the `mods` folder
- in **ViaFabricPlus**, put ViaBackwards into the `config/viafabriclus/jars` folder
As a plugin, ViaBackwards runs on servers on releases 1.10-latest. Versions from the dev branch will also support the
latest snapshot. You can also use ViaBackwards in ViaFabric or ViaFabricPlus.
See [HERE](https://viaversion.com) for an overview of the different Via* projects.
Snapshot support
--------
**ViaBackwards will only be released a few days *after* a Minecraft update** unless the protocol changes of the update were trivial. If you want early-access, usually days or even weeks before the final release, you can subscribe to either:
- [GitHub Sponsors](https://github.com/sponsors/kennytv/sponsorships?sponsor=kennytv&tier_id=385613&preview=false) (preferred option. Use the `/verify` command on this Discord after), or alternatively
- [Patreon](https://www.patreon.com/kennytv/membership) (see the highest tier and make sure to link Patreon to your Discord account under Settings->Connections)
This also includes access to a private repository with the code, which will be pushed to the public repository after the given delay on a Minecraft update.
See [HERE](https://github.com/ViaVersion) for an overview of the different Via* projects.
Releases/Dev Builds
-
@@ -42,7 +34,7 @@ Known issues
1.17 will not be able to see or interact with blocks below y=0 and above y=255
* <1.17 clients on 1.17+ servers might experience inventory desyncs on certain inventory click actions
* Sound mappings are incomplete ([see here](https://github.com/ViaVersion/ViaBackwards/issues/326))
* <1.19.4 clients on 1.20+ servers won't be able to use the smithing table. This can be fixed by
* <1.19.4 clients on 1.20+ servers won't be able to use the smithing table, this can be fixed by
installing [AxSmithing](https://github.com/ViaVersionAddons/AxSmithing)
Other Links
-10
View File
@@ -1,10 +0,0 @@
# Security Policy
## Reporting a Vulnerability
If you discover a **security vulnerability**, please **do not** open a public issue. Instead, use one of the following **confidential contact methods**:
* **Email:** [security@viaversion.com](mailto:security@viaversion.com)
* **Discord:** Join our [Discord server](https://discord.gg/viaversion) and visit the [#exploit-report](https://discord.com/channels/316206679014244363/1388847764137316485) channel for further instructions.
If your issue is **not security-related** (e.g., bug reports, feature requests, or usage questions), please use the [GitHub Issues page](https://github.com/ViaVersion/ViaBackwards/issues) or contact us via the [Discord server](https://discord.gg/viaversion).
+1 -3
View File
@@ -8,7 +8,5 @@ repositories {
dependencies {
// version must be manually kept in sync with the one in root project settings.gradle.kts
implementation("com.gradleup.shadow:shadow-gradle-plugin:9.4.1")
// A nice no-conflict comment for patching in downgrading
implementation("com.github.johnrengelman", "shadow", "8.1.1")
}
+20 -40
View File
@@ -1,56 +1,35 @@
import org.gradle.api.JavaVersion
import org.gradle.api.Project
import org.gradle.api.plugins.JavaPluginExtension
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.ValueSource
import org.gradle.api.provider.ValueSourceParameters
import org.gradle.jvm.toolchain.JavaLanguageVersion
import org.gradle.process.ExecOperations
import java.io.ByteArrayOutputStream
import javax.inject.Inject
fun Project.latestCommitHash(): String {
return runGitCommand(listOf("rev-parse", "--short", "HEAD"))
val byteOut = ByteArrayOutputStream()
exec {
commandLine = listOf("git", "rev-parse", "--short", "HEAD")
standardOutput = byteOut
}
return byteOut.toString(Charsets.UTF_8.name()).trim()
}
fun Project.latestCommitMessage(): String {
return runGitCommand(listOf("log", "-1", "--pretty=%B"))
val byteOut = ByteArrayOutputStream()
exec {
commandLine = listOf("git", "log", "-1", "--pretty=%B")
standardOutput = byteOut
}
return byteOut.toString(Charsets.UTF_8.name()).trim()
}
fun Project.branchName(): String {
return runGitCommand(listOf("rev-parse", "--abbrev-ref", "HEAD"))
}
fun Project.runGitCommand(args: List<String>): String {
return providers.of(GitCommand::class.java) { parameters.args.set(args) }.getOrNull() ?: "unknown"
}
abstract class GitCommand : ValueSource<String, GitCommand.GitCommandParameters> {
@get:Inject
abstract val execOperations: ExecOperations
interface GitCommandParameters : ValueSourceParameters {
val args: ListProperty<String>
}
override fun obtain(): String? {
try {
val command = listOf("git") + parameters.args.get()
val output = ByteArrayOutputStream()
execOperations.exec {
commandLine = command
standardOutput = output
isIgnoreExitValue = true
}
return output.toString(Charsets.UTF_8).trim().takeIf { it.isNotBlank() }
} catch (e: Exception) {
return null
}
val byteOut = ByteArrayOutputStream()
exec {
commandLine = listOf("git", "rev-parse", "--abbrev-ref", "HEAD")
standardOutput = byteOut
}
return byteOut.toString(Charsets.UTF_8.name()).trim()
}
fun Project.parseMinecraftSnapshotVersion(version: String): String? {
val separatorIndex = version.indexOf('-')
val lastSeparatorIndex = version.lastIndexOf('-')
@@ -61,5 +40,6 @@ fun Project.parseMinecraftSnapshotVersion(version: String): String? {
}
fun JavaPluginExtension.javaTarget(version: Int) {
toolchain.languageVersion.set(JavaLanguageVersion.of(version))
sourceCompatibility = JavaVersion.toVersion(version)
targetCompatibility = JavaVersion.toVersion(version)
}
@@ -5,10 +5,8 @@ plugins {
tasks {
// Variable replacements
processResources {
val ver = project.version.toString()
val desc = project.description
filesMatching(listOf("plugin.yml", "META-INF/sponge_plugins.json", "fabric.mod.json")) {
expand(mapOf("version" to ver, "description" to desc))
filesMatching(listOf("plugin.yml", "fabric.mod.json")) {
expand("version" to project.version, "description" to project.description, "url" to "https://viaversion.com/backwards")
}
}
javadoc {
@@ -18,11 +16,10 @@ tasks {
compileJava {
options.encoding = Charsets.UTF_8.name()
options.compilerArgs.addAll(listOf("-nowarn", "-Xlint:-unchecked", "-Xlint:-deprecation"))
options.isFork = true
}
}
java {
javaTarget(17)
withSourcesJar()
}
}
@@ -5,7 +5,7 @@ import org.gradle.kotlin.dsl.named
plugins {
id("vb.base-conventions")
id("maven-publish")
id("com.gradleup.shadow")
id("com.github.johnrengelman.shadow")
}
tasks {
@@ -14,7 +14,6 @@ tasks {
from(project.rootProject.file("LICENSE"))
}
val shadowJar = named<ShadowJar>("shadowJar") {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
archiveClassifier.set("")
configureRelocations()
}
+5 -5
View File
@@ -1,24 +1,24 @@
plugins {
base
eclipse
id("vb.build-logic")
}
allprojects {
group = "com.viaversion"
version = property("projectVersion") as String // from gradle.properties
description = "Allows the connection of older clients to newer server versions for Minecraft servers."
description = "Allows older Minecraft client versions to connect to newer server versions."
}
val main = setOf(
projects.viabackwards,
projects.viabackwardsCommon,
projects.viabackwardsBukkit,
projects.viabackwardsVelocity
).map { it.path }
projects.viabackwardsVelocity,
projects.viabackwardsFabric
).map { it.dependencyProject }
subprojects {
when (path) {
when (this) {
in main -> plugins.apply("vb.shadow-conventions")
else -> plugins.apply("vb.base-conventions")
}
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -19,12 +19,11 @@
package com.viaversion.viabackwards;
import com.viaversion.viabackwards.api.ViaBackwardsPlatform;
import com.viaversion.viabackwards.listener.DurabilitySync1_11;
import com.viaversion.viabackwards.listener.PlayerHurtSound1_12;
import com.viaversion.viabackwards.listener.FireExtinguish1_16;
import com.viaversion.viabackwards.listener.LecternInteract1_14;
import com.viaversion.viabackwards.listener.ItemDropSync1_17;
import com.viaversion.viabackwards.listener.SpearAttack1_21_11;
import com.viaversion.viabackwards.listener.BlockBreakListener;
import com.viaversion.viabackwards.listener.FireDamageListener;
import com.viaversion.viabackwards.listener.FireExtinguishListener;
import com.viaversion.viabackwards.listener.LecternInteractListener;
import com.viaversion.viabackwards.listener.PlayerItemDropListener;
import com.viaversion.viabackwards.protocol.v1_20_2to1_20.provider.AdvancementCriteriaProvider;
import com.viaversion.viabackwards.provider.BukkitAdvancementCriteriaProvider;
import com.viaversion.viaversion.api.Via;
@@ -49,28 +48,22 @@ public class BukkitPlugin extends JavaPlugin implements ViaBackwardsPlatform {
}
}
@Override
public void enable() {
ViaBackwardsPlatform.super.enable();
private void enable() {
final ProtocolVersion protocolVersion = Via.getAPI().getServerVersion().highestSupportedProtocolVersion();
if (protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_21_11)) {
new SpearAttack1_21_11(this).register();
}
if (protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_17)) {
new ItemDropSync1_17(this).register();
new PlayerItemDropListener(this).register();
}
if (protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_16)) {
new FireExtinguish1_16(this).register();
new FireExtinguishListener(this).register();
}
if (protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_14)) {
new LecternInteract1_14(this).register();
new LecternInteractListener(this).register();
}
if (protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_12)) {
new PlayerHurtSound1_12(this).register();
new FireDamageListener(this).register();
}
if (protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_11)) {
new DurabilitySync1_11(this).register();
new BlockBreakListener(this).register();
}
final ViaProviders providers = Via.getManager().getProviders();
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -27,9 +27,9 @@ import org.bukkit.event.EventPriority;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.inventory.ItemStack;
public class DurabilitySync1_11 extends ViaBukkitListener {
public class BlockBreakListener extends ViaBukkitListener {
public DurabilitySync1_11(final BukkitPlugin plugin) {
public BlockBreakListener(final BukkitPlugin plugin) {
super(plugin, Protocol1_11To1_10.class);
}
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -28,9 +28,9 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.entity.EntityDamageEvent;
public class PlayerHurtSound1_12 extends ViaBukkitListener {
public class FireDamageListener extends ViaBukkitListener {
public PlayerHurtSound1_12(BukkitPlugin plugin) {
public FireDamageListener(BukkitPlugin plugin) {
super(plugin, Protocol1_12To1_11_1.class);
}
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -28,9 +28,9 @@ import org.bukkit.event.EventPriority;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
public class FireExtinguish1_16 extends ViaBukkitListener {
public class FireExtinguishListener extends ViaBukkitListener {
public FireExtinguish1_16(BukkitPlugin plugin) {
public FireExtinguishListener(BukkitPlugin plugin) {
super(plugin, Protocol1_16To1_15_2.class);
}
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -30,9 +30,9 @@ import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.BookMeta;
public class LecternInteract1_14 extends ViaBukkitListener {
public class LecternInteractListener extends ViaBukkitListener {
public LecternInteract1_14(BukkitPlugin plugin) {
public LecternInteractListener(BukkitPlugin plugin) {
super(plugin, Protocol1_14To1_13_2.class);
}
@@ -1,7 +1,7 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -27,9 +27,9 @@ import org.bukkit.event.EventPriority;
import org.bukkit.event.player.PlayerDropItemEvent;
import org.bukkit.inventory.ItemStack;
public class ItemDropSync1_17 extends ViaBukkitListener {
public class PlayerItemDropListener extends ViaBukkitListener {
public ItemDropSync1_17(final BukkitPlugin plugin) {
public PlayerItemDropListener(final BukkitPlugin plugin) {
super(plugin, Protocol1_13_1To1_13.class); // Starts with 1.13 clients on 1.17 servers
}
@@ -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.listener;
import com.viaversion.viabackwards.BukkitPlugin;
import com.viaversion.viabackwards.protocol.v1_21_11to1_21_9.Protocol1_21_11To1_21_9;
import com.viaversion.viaversion.bukkit.listeners.ViaBukkitListener;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.inventory.ItemStack;
public class SpearAttack1_21_11 extends ViaBukkitListener {
public SpearAttack1_21_11(final BukkitPlugin plugin) {
super(plugin, Protocol1_21_11To1_21_9.class);
}
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onBlockBreak(final BlockBreakEvent event) {
final Player player = event.getPlayer();
if (!isOnPipe(player)) {
return;
}
final ItemStack item = player.getInventory().getItemInMainHand();
if (item.getType().name().endsWith("_SPEAR")) {
// Prevent spears from breaking blocks
event.setCancelled(true);
}
}
}
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -27,8 +27,8 @@ public final class BukkitAdvancementCriteriaProvider extends AdvancementCriteria
private static final String[] EMPTY_CRITERIA = new String[0];
@Override
public String[] getCriteria(final String advancementKey) {
final Advancement advancement = Bukkit.getAdvancement(NamespacedKey.fromString(advancementKey));
public String[] getCriteria(final String key) {
final Advancement advancement = Bukkit.getAdvancement(NamespacedKey.fromString(key));
return advancement == null ? EMPTY_CRITERIA : advancement.getCriteria().toArray(EMPTY_CRITERIA);
}
}
+1 -1
View File
@@ -6,6 +6,6 @@ api-version: 1.13
folia-supported: true
authors: [Matsv, kennytv, Gerrygames, creeper123123321, ForceUpdate1, EnZaXD]
website: "https://viaversion.com/backwards"
website: ${url}
depend: [ViaVersion]
-37
View File
@@ -24,40 +24,3 @@ dependencies {
java {
withJavadocJar()
}
// Task to quickly test/debug code changes using https://github.com/ViaVersion/ViaProxy
// For further instructions see the ViaProxy repository README
val prepareViaProxyFiles by tasks.registering(Copy::class) {
dependsOn(project.tasks.shadowJar)
from(project.tasks.shadowJar.map { it.archiveFile.get().asFile })
into(layout.projectDirectory.dir("run/jars"))
val projectName = project.name
rename { "${projectName}.jar" }
}
val cleanupViaProxyFiles by tasks.registering(Delete::class) {
delete(
layout.projectDirectory.file("run/jars/${project.name}.jar"),
layout.projectDirectory.dir("run/logs")
)
}
val viaProxyConfiguration: Configuration by configurations.creating {
dependencies.add(rootProject.libs.viaProxy.get().copy().setTransitive(false))
}
tasks.register<JavaExec>("runViaProxy") {
dependsOn(prepareViaProxyFiles)
finalizedBy(cleanupViaProxyFiles)
mainClass.set("net.raphimc.viaproxy.ViaProxy")
classpath = viaProxyConfiguration
workingDir = layout.projectDirectory.dir("run").asFile
jvmArgs = listOf("-DskipUpdateCheck")
if (System.getProperty("viaproxy.gui.autoStart") != null) {
jvmArgs("-Dviaproxy.gui.autoStart")
}
}
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2025 ViaVersion and contributors
* Copyright (C) 2016-2023 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
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -17,10 +17,7 @@
*/
package com.viaversion.viabackwards;
import com.viaversion.viabackwards.api.DialogStyleConfig;
import com.viaversion.viaversion.util.ChatColorUtil;
import com.viaversion.viaversion.util.Config;
import com.viaversion.viaversion.util.ConfigSection;
import java.io.File;
import java.io.InputStream;
import java.net.URL;
@@ -37,17 +34,7 @@ public class ViaBackwardsConfig extends Config implements com.viaversion.viaback
private boolean alwaysShowOriginalMobName;
private boolean fix1_13FormattedInventoryTitles;
private boolean handlePingsAsInvAcknowledgements;
private boolean bedrockAtY0;
private boolean sculkShriekersToCryingObsidian;
private boolean scaffoldingToWater;
private boolean mapDarknessEffect;
private boolean mapCustomModelData;
private boolean mapDisplayEntities;
private boolean suppressEmulationWarnings;
private boolean dialogsViaChests;
private DialogStyleConfig dialogStyleConfig;
private boolean codeOfConductAsDialog;
private boolean passOriginalItemNameToResourcePacks;
public ViaBackwardsConfig(File configFile, Logger logger) {
super(configFile, logger);
@@ -66,39 +53,7 @@ public class ViaBackwardsConfig extends Config implements com.viaversion.viaback
fix1_13FormattedInventoryTitles = getBoolean("fix-formatted-inventory-titles", true);
alwaysShowOriginalMobName = getBoolean("always-show-original-mob-name", true);
handlePingsAsInvAcknowledgements = getBoolean("handle-pings-as-inv-acknowledgements", false);
bedrockAtY0 = getBoolean("bedrock-at-y-0", false);
sculkShriekersToCryingObsidian = getBoolean("sculk-shriekers-to-crying-obsidian", false);
scaffoldingToWater = getBoolean("scaffolding-to-water", false);
mapDarknessEffect = getBoolean("map-darkness-effect", true);
mapCustomModelData = getBoolean("map-custom-model-data", true);
mapDisplayEntities = getBoolean("map-display-entities", true);
suppressEmulationWarnings = getBoolean("suppress-emulation-warnings", false);
dialogsViaChests = getBoolean("dialogs-via-chests", true);
dialogStyleConfig = loadDialogStyleConfig(getSection("dialog-style"));
codeOfConductAsDialog = getBoolean("code-of-conduct-as-dialog", true);
passOriginalItemNameToResourcePacks = getBoolean("pass-original-item-name-to-resource-packs", true);
}
private DialogStyleConfig loadDialogStyleConfig(final ConfigSection section) {
return new DialogStyleConfig(
getString(section, "page-navigation-title", "&9&lPage navigation"),
getString(section, "page-navigation-next", "&9Left click: &6Go to next page"),
getString(section, "page-navigation-previous", "&9Right click: &6Go to previous page"),
getString(section, "increase-value", "&9Left click: &6Increase value by %s"),
getString(section, "decrease-value", "&9Right click: &6Decrease value by %s"),
getString(section, "value-range", "&7(Value between &a%s &7and &a%s&7)"),
getString(section, "next-option", "&9Left click: &6Go to next option"),
getString(section, "previous-option", "&9Right click: &6Go to previous option"),
getString(section, "current-value", "&7Current value: &a%s"),
getString(section, "edit-value", "&9Left click: &6Edit text"),
getString(section, "set-text", "&9Left click/close: &6Set text"),
getString(section, "close", "&9Left click: &6Close"),
getString(section, "toggle-value", "&9Left click: &6Toggle value")
);
}
protected String getString(final ConfigSection section, final String key, final String def) {
return ChatColorUtil.translateAlternateColorCodes(section.getString(key, def));
}
@Override
@@ -131,61 +86,11 @@ public class ViaBackwardsConfig extends Config implements com.viaversion.viaback
return handlePingsAsInvAcknowledgements || Boolean.getBoolean("com.viaversion.handlePingsAsInvAcknowledgements");
}
@Override
public boolean bedrockAtY0() {
return bedrockAtY0;
}
@Override
public boolean sculkShriekerToCryingObsidian() {
return sculkShriekersToCryingObsidian;
}
@Override
public boolean scaffoldingToWater() {
return scaffoldingToWater;
}
@Override
public boolean mapDarknessEffect() {
return mapDarknessEffect;
}
@Override
public boolean mapCustomModelData() {
return mapCustomModelData;
}
@Override
public boolean mapDisplayEntities() {
return mapDisplayEntities;
}
@Override
public boolean suppressEmulationWarnings() {
return suppressEmulationWarnings;
}
@Override
public boolean dialogsViaChests() {
return dialogsViaChests;
}
@Override
public DialogStyleConfig dialogStyleConfig() {
return dialogStyleConfig;
}
@Override
public boolean codeOfConductAsDialog() {
return codeOfConductAsDialog;
}
@Override
public boolean passOriginalItemNameToResourcePacks() {
return passOriginalItemNameToResourcePacks;
}
@Override
public URL getDefaultConfigURL() {
return getClass().getClassLoader().getResource("assets/viabackwards/config.yml");
@@ -1,53 +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;
import com.viaversion.viabackwards.api.ViaBackwardsPlatform;
import com.viaversion.viaversion.api.Via;
import java.io.File;
import java.util.logging.Logger;
public class ViaBackwardsPlatformImpl implements ViaBackwardsPlatform {
private final Logger logger;
public ViaBackwardsPlatformImpl() {
logger = Via.getPlatform().createLogger("ViaBackwards");
init(new File(getDataFolder(), "viabackwards.yml"));
enable();
}
@Override
public Logger getLogger() {
return logger;
}
@Override
public void disable() {
}
@Override
public File getDataFolder() {
return Via.getPlatform().getDataFolder();
}
@Override
public boolean isOutdated() {
return false;
}
}
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -18,20 +18,17 @@
package com.viaversion.viabackwards.api;
import com.viaversion.viabackwards.api.data.BackwardsMappingData;
import com.viaversion.viabackwards.api.rewriters.BackwardsRegistryRewriter;
import com.viaversion.viabackwards.protocol.registration.BackwardsRegistrations;
import com.viaversion.viabackwards.utils.BackwardsProtocolLogger;
import com.viaversion.viabackwards.api.rewriters.TranslatableRewriter;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.protocol.AbstractProtocol;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType;
import com.viaversion.viaversion.util.ProtocolLogger;
import org.checkerframework.checker.nullness.qual.Nullable;
public abstract class BackwardsProtocol<CU extends ClientboundPacketType, CM extends ClientboundPacketType, SM extends ServerboundPacketType, SU extends ServerboundPacketType>
extends AbstractProtocol<CU, CM, SM, SU> {
@Deprecated
protected BackwardsProtocol() {
}
@@ -40,29 +37,35 @@ public abstract class BackwardsProtocol<CU extends ClientboundPacketType, CM ext
super(oldClientboundPacketEnum, clientboundPacketEnum, oldServerboundPacketEnum, serverboundPacketEnum);
}
@Override
protected void applySharedRegistrations() {
super.applySharedRegistrations();
BackwardsRegistrations.registrations().applyMatching(this);
/**
* Waits for the given protocol to be loaded to then asynchronously execute the runnable for this protocol.
*/
protected void executeAsyncAfterLoaded(Class<? extends Protocol> protocolClass, Runnable runnable) {
Via.getManager().getProtocolManager().addMappingLoaderFuture(getClass(), protocolClass, runnable);
}
@Override
protected ProtocolLogger createLogger() {
return new BackwardsProtocolLogger(getClass());
protected void registerPackets() {
super.registerPackets();
final BackwardsMappingData mappingData = getMappingData();
if (mappingData != null && mappingData.getViaVersionProtocolClass() != null) {
executeAsyncAfterLoaded(mappingData.getViaVersionProtocolClass(), this::loadMappingData);
}
}
@Override
public @Nullable Class<? extends Protocol<?, ?, ?, ?>> dependsOn() {
return getMappingData() != null ? getMappingData().getViaVersionProtocolClass() : null;
public boolean hasMappingDataToLoad() {
// Manually load them later, since they depend on VV's mappings
return false;
}
@Override
public @Nullable BackwardsMappingData getMappingData() {
public @Nullable BackwardsMappingData getMappingData() { // Change return type to BackwardsMappings
return null;
}
@Override
public @Nullable BackwardsRegistryRewriter getRegistryDataRewriter() {
public @Nullable TranslatableRewriter<CU> getTranslatableRewriter() {
return null;
}
}
@@ -1,25 +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;
public record DialogStyleConfig(String pageNavigationTitle, String pageNavigationNext, String pageNavigationPrevious,
String increaseValue, String decreaseValue, String valueRange, String nextOption,
String previousOption, String currentValue, String editValue, String setText,
String close, String toggleValue) {
}
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -64,82 +64,10 @@ public interface ViaBackwardsConfig extends Config {
*/
boolean handlePingsAsInvAcknowledgements();
/**
* Adds bedrock at y=0 for sub 1.17 clients.
*
* @return true if enabled
*/
boolean bedrockAtY0();
/**
* Shows sculk shriekers as crying obsidian for 1.18.2 clients on 1.19+ servers. This fixes collision and block breaking issues.
*
* @return true if enabled
*/
boolean sculkShriekerToCryingObsidian();
/**
* Shows scaffolding as water for 1.13.2 clients on 1.14+ servers. This fixes collision issues.
*
* @return true if enabled
*/
boolean scaffoldingToWater();
/**
* Maps the darkness effect to blindness for 1.18.2 clients on 1.19+ servers.
*
* @return true if enabled
*/
boolean mapDarknessEffect();
/**
* If enabled, 1.21.3 clients will receive the first float of 1.21.4+ custom model data as int. Disable if you handle this change yourself.
*
* @return true if enabled
*/
boolean mapCustomModelData();
/**
* If enabled, 1.19.3 clients will receive display entities as armor stands with custom entity data on 1.19.4+ servers.
*
* @return true if enabled
*/
boolean mapDisplayEntities();
/**
* Suppresses warnings of missing emulations for certain features that are not supported (e.g. world height in 1.17+).
*
* @return true if enabled
*/
boolean suppressEmulationWarnings();
/**
* If enabled, dialogs will be shown via chest inventories for 1.21.5 clients on 1.21.6+ servers.
*
* @return true if enabled
*/
boolean dialogsViaChests();
/**
* Returns the dialog style configuration.
*
* @return the dialog style configuration
*/
DialogStyleConfig dialogStyleConfig();
/**
* If true, the code of conduct will be displayed as a dialog for 1.21.7 clients on 1.21.9+ servers.
*
* @return true if enabled
*/
boolean codeOfConductAsDialog();
/**
* Injects the original vanilla 1.21.4+ item name into custom_model_data strings for resource packs.
* Disable if your server creates custom items using modern items as their base.
* Tip: For server custom items, base them on items in the game before 1.21.4 (e.g. saddle) to ensure compatibility.
*
* @return true if enabled
*/
boolean passOriginalItemNameToResourcePacks();
}
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -20,55 +20,43 @@ package com.viaversion.viabackwards.api;
import com.viaversion.viabackwards.ViaBackwards;
import com.viaversion.viabackwards.ViaBackwardsConfig;
import com.viaversion.viabackwards.api.data.TranslatableMappings;
import com.viaversion.viabackwards.protocol.registration.BackwardsRegistrations;
import com.viaversion.viabackwards.protocol.v1_10to1_9_3.Protocol1_10To1_9_3;
import com.viaversion.viabackwards.protocol.v1_11_1to1_11.Protocol1_11_1To1_11;
import com.viaversion.viabackwards.api.rewriters.TranslatableRewriter;
import com.viaversion.viabackwards.protocol.v1_11to1_10.Protocol1_11To1_10;
import com.viaversion.viabackwards.protocol.v1_12_1to1_12.Protocol1_12_1To1_12;
import com.viaversion.viabackwards.protocol.v1_12_2to1_12_1.Protocol1_12_2To1_12_1;
import com.viaversion.viabackwards.protocol.v1_12to1_11_1.Protocol1_12To1_11_1;
import com.viaversion.viabackwards.protocol.v1_13_1to1_13.Protocol1_13_1To1_13;
import com.viaversion.viabackwards.protocol.v1_13_2to1_13_1.Protocol1_13_2To1_13_1;
import com.viaversion.viabackwards.protocol.v1_11_1to1_11.Protocol1_11_1To1_11;
import com.viaversion.viabackwards.protocol.v1_12_2to1_12_1.Protocol1_12_2To1_12_1;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.Protocol1_13To1_12_2;
import com.viaversion.viabackwards.protocol.v1_14_1to1_14.Protocol1_14_1To1_14;
import com.viaversion.viabackwards.protocol.v1_12_1to1_12.Protocol1_12_1To1_12;
import com.viaversion.viabackwards.protocol.v1_13_2to1_13_1.Protocol1_13_2To1_13_1;
import com.viaversion.viabackwards.protocol.v1_14to1_13_2.Protocol1_14To1_13_2;
import com.viaversion.viabackwards.protocol.v1_13_1to1_13.Protocol1_13_1To1_13;
import com.viaversion.viabackwards.protocol.v1_14_2to1_14_1.Protocol1_14_2To1_14_1;
import com.viaversion.viabackwards.protocol.v1_14_3to1_14_2.Protocol1_14_3To1_14_2;
import com.viaversion.viabackwards.protocol.v1_14_4to1_14_3.Protocol1_14_4To1_14_3;
import com.viaversion.viabackwards.protocol.v1_14to1_13_2.Protocol1_14To1_13_2;
import com.viaversion.viabackwards.protocol.v1_15_1to1_15.Protocol1_15_1To1_15;
import com.viaversion.viabackwards.protocol.v1_15_2to1_15_1.Protocol1_15_2To1_15_1;
import com.viaversion.viabackwards.protocol.v1_15to1_14_4.Protocol1_15To1_14_4;
import com.viaversion.viabackwards.protocol.v1_16_1to1_16.Protocol1_16_1To1_16;
import com.viaversion.viabackwards.protocol.v1_14_1to1_14.Protocol1_14_1To1_14;
import com.viaversion.viabackwards.protocol.v1_15_2to1_15_1.Protocol1_15_2To1_15_1;
import com.viaversion.viabackwards.protocol.v1_16to1_15_2.Protocol1_16To1_15_2;
import com.viaversion.viabackwards.protocol.v1_15_1to1_15.Protocol1_15_1To1_15;
import com.viaversion.viabackwards.protocol.v1_16_2to1_16_1.Protocol1_16_2To1_16_1;
import com.viaversion.viabackwards.protocol.v1_16_3to1_16_2.Protocol1_16_3To1_16_2;
import com.viaversion.viabackwards.protocol.v1_16_4to1_16_3.Protocol1_16_4To1_16_3;
import com.viaversion.viabackwards.protocol.v1_16to1_15_2.Protocol1_16To1_15_2;
import com.viaversion.viabackwards.protocol.v1_17_1to1_17.Protocol1_17_1To1_17;
import com.viaversion.viabackwards.protocol.v1_17to1_16_4.Protocol1_17To1_16_4;
import com.viaversion.viabackwards.protocol.v1_18_2to1_18.Protocol1_18_2To1_18;
import com.viaversion.viabackwards.protocol.v1_16_1to1_16.Protocol1_16_1To1_16;
import com.viaversion.viabackwards.protocol.v1_18to1_17_1.Protocol1_18To1_17_1;
import com.viaversion.viabackwards.protocol.v1_19_1to1_19.Protocol1_19_1To1_19;
import com.viaversion.viabackwards.protocol.v1_17_1to1_17.Protocol1_17_1To1_17;
import com.viaversion.viabackwards.protocol.v1_19to1_18_2.Protocol1_19To1_18_2;
import com.viaversion.viabackwards.protocol.v1_18_2to1_18.Protocol1_18_2To1_18;
import com.viaversion.viabackwards.protocol.v1_19_3to1_19_1.Protocol1_19_3To1_19_1;
import com.viaversion.viabackwards.protocol.v1_19_4to1_19_3.Protocol1_19_4To1_19_3;
import com.viaversion.viabackwards.protocol.v1_19to1_18_2.Protocol1_19To1_18_2;
import com.viaversion.viabackwards.protocol.v1_20_2to1_20.Protocol1_20_2To1_20;
import com.viaversion.viabackwards.protocol.v1_20to1_19_4.Protocol1_20To1_19_4;
import com.viaversion.viabackwards.protocol.v1_19_1to1_19.Protocol1_19_1To1_19;
import com.viaversion.viabackwards.protocol.v1_20_3to1_20_2.Protocol1_20_3To1_20_2;
import com.viaversion.viabackwards.protocol.v1_20_5to1_20_3.Protocol1_20_5To1_20_3;
import com.viaversion.viabackwards.protocol.v1_20to1_19_4.Protocol1_20To1_19_4;
import com.viaversion.viabackwards.protocol.v1_21_11to1_21_9.Protocol1_21_11To1_21_9;
import com.viaversion.viabackwards.protocol.v1_21_2to1_21.Protocol1_21_2To1_21;
import com.viaversion.viabackwards.protocol.v1_21_2to1_21.task.PlayerPacketsTickTask;
import com.viaversion.viabackwards.protocol.v1_21_4to1_21_2.Protocol1_21_4To1_21_2;
import com.viaversion.viabackwards.protocol.v1_21_5to1_21_4.Protocol1_21_5To1_21_4;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.Protocol1_21_6To1_21_5;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.task.ChestDialogViewTask;
import com.viaversion.viabackwards.protocol.v1_21_7to1_21_6.Protocol1_21_7To1_21_6;
import com.viaversion.viabackwards.protocol.v1_21_9to1_21_7.Protocol1_21_9To1_21_7;
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_20_2to1_20.Protocol1_20_2To1_20;
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.v1_10to1_9_3.Protocol1_10To1_9_3;
import com.viaversion.viabackwards.protocol.v1_9_1to1_9.Protocol1_9_1To1_9;
import com.viaversion.viabackwards.utils.VersionInfo;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.protocol.ProtocolManager;
@@ -80,16 +68,13 @@ import java.util.logging.Logger;
public interface ViaBackwardsPlatform {
String MINIMUM_VV_VERSION = "5.9.2";
default void init(final File configFile) {
init(new ViaBackwardsConfig(configFile, getLogger()));
}
String MINIMUM_VV_VERSION = "5.0.0";
/**
* Initialize ViaBackwards.
*/
default void init(final com.viaversion.viabackwards.api.ViaBackwardsConfig config) {
default void init(final File configFile) {
ViaBackwardsConfig config = new ViaBackwardsConfig(configFile, getLogger());
config.reload();
Via.getManager().getConfigurationProvider().register(config);
@@ -103,11 +88,9 @@ public interface ViaBackwardsPlatform {
Via.getManager().getSubPlatforms().add(VersionInfo.getImplementationVersion());
getLogger().info("Loading translations...");
TranslatableMappings.loadTranslatables();
TranslatableRewriter.loadTranslatables();
getLogger().info("Registering protocols...");
BackwardsRegistrations.apply();
final ProtocolManager protocolManager = Via.getManager().getProtocolManager();
protocolManager.registerProtocol(new Protocol1_9_1To1_9(), ProtocolVersion.v1_9, ProtocolVersion.v1_9_1);
protocolManager.registerProtocol(new Protocol1_9_3To1_9_1(), Arrays.asList(ProtocolVersion.v1_9_1, ProtocolVersion.v1_9_2), ProtocolVersion.v1_9_3);
@@ -155,29 +138,6 @@ public interface ViaBackwardsPlatform {
protocolManager.registerProtocol(new Protocol1_20_2To1_20(), ProtocolVersion.v1_20, ProtocolVersion.v1_20_2);
protocolManager.registerProtocol(new Protocol1_20_3To1_20_2(), ProtocolVersion.v1_20_2, ProtocolVersion.v1_20_3);
protocolManager.registerProtocol(new Protocol1_20_5To1_20_3(), ProtocolVersion.v1_20_3, ProtocolVersion.v1_20_5);
protocolManager.registerProtocol(new Protocol1_21To1_20_5(), ProtocolVersion.v1_20_5, ProtocolVersion.v1_21);
protocolManager.registerProtocol(new Protocol1_21_2To1_21(), ProtocolVersion.v1_21, ProtocolVersion.v1_21_2);
protocolManager.registerProtocol(new Protocol1_21_4To1_21_2(), ProtocolVersion.v1_21_2, ProtocolVersion.v1_21_4);
protocolManager.registerProtocol(new Protocol1_21_5To1_21_4(), ProtocolVersion.v1_21_4, ProtocolVersion.v1_21_5);
protocolManager.registerProtocol(new Protocol1_21_6To1_21_5(), ProtocolVersion.v1_21_5, ProtocolVersion.v1_21_6);
protocolManager.registerProtocol(new Protocol1_21_7To1_21_6(), ProtocolVersion.v1_21_6, ProtocolVersion.v1_21_7);
protocolManager.registerProtocol(new Protocol1_21_9To1_21_7(), ProtocolVersion.v1_21_7, ProtocolVersion.v1_21_9);
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);
}
default void enable() {
final ProtocolVersion protocolVersion = Via.getAPI().getServerVersion().highestSupportedProtocolVersion();
if (protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_21_2)) {
Via.getPlatform().runRepeatingSync(new PlayerPacketsTickTask(), 1L);
}
if (protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_21_6)) {
Via.getPlatform().runRepeatingSync(new ChestDialogViewTask(), 20L);
}
}
/**
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -18,10 +18,6 @@
package com.viaversion.viabackwards.api.data;
import com.google.common.base.Preconditions;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.NumberTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viabackwards.ViaBackwards;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viaversion.api.Via;
@@ -34,6 +30,11 @@ import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectArrayMap;
import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectMap;
import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectOpenHashMap;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.NumberTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.util.Key;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
@@ -44,6 +45,7 @@ public class BackwardsMappingData extends MappingDataBase {
private final Class<? extends Protocol<?, ?, ?, ?>> vvProtocolClass;
protected Int2ObjectMap<MappedItem> backwardsItemMappings;
private Map<String, String> backwardsSoundMappings;
private Map<String, String> entityNames;
private Int2ObjectMap<String> enchantmentNames;
@@ -53,7 +55,7 @@ public class BackwardsMappingData extends MappingDataBase {
public BackwardsMappingData(final String unmappedVersion, final String mappedVersion, @Nullable final Class<? extends Protocol<?, ?, ?, ?>> vvProtocolClass) {
super(unmappedVersion, mappedVersion);
Preconditions.checkArgument(vvProtocolClass == null || !BackwardsProtocol.class.isAssignableFrom(vvProtocolClass));
Preconditions.checkArgument(vvProtocolClass == null || !vvProtocolClass.isAssignableFrom(BackwardsProtocol.class));
this.vvProtocolClass = vvProtocolClass;
}
@@ -81,6 +83,7 @@ public class BackwardsMappingData extends MappingDataBase {
this.entityNames = loadNameByStringMappings(data, "entitynames");
this.enchantmentNames = loadNameByIdMappings(data, "enchantmentnames");
this.backwardsSoundMappings = loadNameByStringMappings(data, "soundnames");
}
private @Nullable Map<String, String> loadNameByStringMappings(final CompoundTag data, final String key) {
@@ -148,17 +151,15 @@ public class BackwardsMappingData extends MappingDataBase {
return checkValidity(id, this.itemMappings.inverse().getNewId(id), "item");
}
@Override
public int getNewAttributeId(final int id) {
return this.attributeMappings.getNewId(id);
}
public @Nullable MappedItem getMappedItem(final int id) {
return backwardsItemMappings != null ? backwardsItemMappings.get(id) : null;
}
public @Nullable String getMappedNamedSound(final String id) {
return getFullSoundMappings().mappedIdentifier(id);
if (backwardsSoundMappings == null) {
return null;
}
return backwardsSoundMappings.get(Key.stripMinecraftNamespace(id));
}
public @Nullable String mappedEntityName(final String entityName) {
@@ -181,6 +182,10 @@ public class BackwardsMappingData extends MappingDataBase {
return backwardsItemMappings;
}
public @Nullable Map<String, String> getBackwardsSoundMappings() {
return backwardsSoundMappings;
}
public @Nullable Class<? extends Protocol<?, ?, ?, ?>> getViaVersionProtocolClass() {
return vvProtocolClass;
}
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -17,10 +17,10 @@
*/
package com.viaversion.viabackwards.api.data;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viabackwards.ViaBackwards;
import com.viaversion.viaversion.api.data.MappingDataLoader;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.Tag;
import java.io.File;
import java.io.IOException;
import java.util.Map;
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -71,7 +71,7 @@ public class MappedLegacyBlockItem {
@FunctionalInterface
public interface BlockEntityHandler {
void handleCompoundTag(int block, CompoundTag tag);
CompoundTag handleOrNewCompoundTag(int block, CompoundTag tag);
}
public enum Type {
@@ -1,69 +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.data;
import com.viaversion.viabackwards.ViaBackwards;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.libs.gson.JsonObject;
import java.util.HashMap;
import java.util.Map;
import org.checkerframework.checker.nullness.qual.Nullable;
public final class TranslatableMappings {
private static final Map<String, Map<String, String>> TRANSLATABLES = new HashMap<>();
public static void loadTranslatables() {
if (!TRANSLATABLES.isEmpty()) {
throw new IllegalStateException("Translatables already loaded!");
}
fillTranslatables(BackwardsMappingDataLoader.INSTANCE.loadFromDataDir("translation-mappings.json"), TRANSLATABLES);
}
public static void fillTranslatables(final JsonObject jsonObject, final Map<String, Map<String, String>> translatables) {
for (final Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
final Map<String, String> versionMappings = new HashMap<>();
translatables.put(entry.getKey(), versionMappings);
for (final Map.Entry<String, JsonElement> translationEntry : entry.getValue().getAsJsonObject().entrySet()) {
versionMappings.put(translationEntry.getKey(), translationEntry.getValue().getAsString());
}
}
}
public static Map<String, String> translatablesFor(final Protocol<?, ?, ?, ?> protocol) {
final String version = protocol.getClass().getSimpleName()
.replace("Protocol", "")
.split("To")[0]
.replace("_", ".");
return translatablesFor(version);
}
public static Map<String, String> translatablesFor(final String version) {
final Map<String, String> translatableMappings = getTranslatableMappings(version);
if (translatableMappings == null) {
ViaBackwards.getPlatform().getLogger().warning("Missing " + version + " translatables!");
return new HashMap<>();
}
return translatableMappings;
}
public static @Nullable Map<String, String> getTranslatableMappings(final String sectionIdentifier) {
return TRANSLATABLES.get(sectionIdentifier);
}
}
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -47,10 +47,7 @@ public class EntityPositionHandler {
}
public void cacheEntityPosition(PacketWrapper wrapper, double x, double y, double z, boolean create, boolean relative) {
cacheEntityPosition(wrapper, wrapper.get(Types.VAR_INT, 0), x, y, z, create, relative);
}
public void cacheEntityPosition(PacketWrapper wrapper, int entityId, double x, double y, double z, boolean create, boolean relative) {
int entityId = wrapper.get(Types.VAR_INT, 0);
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! :>
@@ -78,11 +75,7 @@ public class EntityPositionHandler {
}
}
if (relative) {
positionStorage.addRelativePosition(x, y, z);
} else {
positionStorage.setPosition(x, y, z);
}
positionStorage.setCoordinates(x, y, z, relative);
}
public EntityPositionStorage getStorage(UserConnection user, int entityId) {
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -34,15 +34,15 @@ public abstract class EntityPositionStorage {
return z;
}
public void setPosition(double x, double y, double z) {
this.x = x;
this.y = y;
this.z = z;
}
public void addRelativePosition(double relX, double relY, double relZ) {
this.x += relX;
this.y += relY;
this.z += relZ;
public void setCoordinates(double x, double y, double z, boolean relative) {
if (relative) {
this.x += x;
this.y += y;
this.z += z;
} else {
this.x = x;
this.y = y;
this.z = z;
}
}
}
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -18,9 +18,9 @@
package com.viaversion.viabackwards.api.entities.storage;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viaversion.util.ComponentUtil;
import java.util.Locale;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -31,7 +31,7 @@ public class EntityReplacement {
private final int replacementId;
private final String key;
private ComponentType componentType = ComponentType.NONE;
private EntityDataCreator defaultData;
private MetaCreator defaultMeta;
public EntityReplacement(BackwardsProtocol<?, ?, ?, ?> protocol, EntityType type, int replacementId) {
this(protocol, type.name(), type.getId(), replacementId);
@@ -59,13 +59,13 @@ public class EntityReplacement {
return this;
}
public EntityReplacement spawnEntityData(EntityDataCreator handler) {
this.defaultData = handler;
public EntityReplacement spawnMetadata(MetaCreator handler) {
this.defaultMeta = handler;
return this;
}
public boolean hasBaseData() {
return this.defaultData != null;
public boolean hasBaseMeta() {
return this.defaultMeta != null;
}
public int typeId() {
@@ -97,8 +97,8 @@ public class EntityReplacement {
return replacementId;
}
public @Nullable EntityDataCreator defaultData() {
return defaultData;
public @Nullable MetaCreator defaultMeta() {
return defaultMeta;
}
public boolean isObjectType() {
@@ -111,20 +111,18 @@ public class EntityReplacement {
@Override
public String toString() {
return "EntityReplacement{" +
"protocol=" + protocol +
", id=" + id +
return "EntityData{" +
"id=" + id +
", mobName='" + key + '\'' +
", replacementId=" + replacementId +
", key='" + key + '\'' +
", componentType=" + componentType +
", defaultData=" + defaultData +
", defaultMeta=" + defaultMeta +
'}';
}
@FunctionalInterface
public interface EntityDataCreator {
public interface MetaCreator {
void createData(WrappedEntityData storage);
void createMeta(WrappedMetadata storage);
}
private enum ComponentType {
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -18,6 +18,8 @@
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 abstract class PlayerPositionStorage implements StorableObject {
private double x;
@@ -51,15 +53,19 @@ public abstract class PlayerPositionStorage implements StorableObject {
this.z = z;
}
public void setPosition(double x, double y, double z) {
this.x = x;
this.y = y;
this.z = z;
public void setCoordinates(PacketWrapper wrapper, boolean relative) {
setCoordinates(wrapper.get(Types.DOUBLE, 0), wrapper.get(Types.DOUBLE, 1), wrapper.get(Types.DOUBLE, 2), relative);
}
public void addRelativePosition(double relX, double relY, double relZ) {
this.x += relX;
this.y += relY;
this.z += relZ;
public void setCoordinates(double x, double y, double z, boolean relative) {
if (relative) {
this.x += x;
this.y += y;
this.z += z;
} else {
this.x = x;
this.y = y;
this.z = z;
}
}
}
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -22,28 +22,28 @@ import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import java.util.List;
import org.checkerframework.checker.nullness.qual.Nullable;
public record WrappedEntityData(List<EntityData> entityDataList) {
public record WrappedMetadata(List<EntityData> metadataList) {
public boolean has(EntityData data) {
return this.entityDataList.contains(data);
return this.metadataList.contains(data);
}
public void remove(EntityData data) {
this.entityDataList.remove(data);
this.metadataList.remove(data);
}
public void remove(int index) {
entityDataList.removeIf(data -> data.id() == index);
metadataList.removeIf(meta -> meta.id() == index);
}
public void add(EntityData data) {
this.entityDataList.add(data);
this.metadataList.add(data);
}
public @Nullable EntityData get(int index) {
for (EntityData data : this.entityDataList) {
if (index == data.id()) {
return data;
for (EntityData meta : this.metadataList) {
if (index == meta.id()) {
return meta;
}
}
return null;
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -17,6 +17,16 @@
*/
package com.viaversion.viabackwards.api.rewriters;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.data.MappedItem;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.nbt.tag.ByteTag;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.IntTag;
@@ -24,16 +34,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.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.data.MappedItem;
import com.viaversion.viabackwards.item.DataItemWithExtras;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.libs.gson.JsonElement;
import java.util.List;
import org.checkerframework.checker.nullness.qual.Nullable;
public class BackwardsItemRewriter<C extends ClientboundPacketType, S extends ServerboundPacketType,
@@ -54,46 +54,30 @@ public class BackwardsItemRewriter<C extends ClientboundPacketType, S extends Se
}
CompoundTag display = item.tag() != null ? item.tag().getCompoundTag("display") : null;
if (protocol.getComponentRewriter() != null && display != null) {
final DataItemWithExtras fullItem;
if (item instanceof DataItemWithExtras) {
fullItem = (DataItemWithExtras) item;
} else {
item = fullItem = new DataItemWithExtras(item);
}
if (protocol.getTranslatableRewriter() != null && display != null) {
// Handle name and lore components
final JsonElement name = fullItem.name();
StringTag name = display.getStringTag("Name");
if (name != null) {
final JsonElement updatedName = name.deepCopy();
protocol.getComponentRewriter().processText(connection, updatedName);
if (!updatedName.equals(name)) {
final StringTag rawName = fullItem.rawName();
saveStringTag(display, rawName, "Name");
rawName.setValue(updatedName.toString());
String newValue = protocol.getTranslatableRewriter().processText(connection, name.getValue()).toString();
if (!newValue.equals(name.getValue())) {
saveStringTag(display, name, "Name");
}
name.setValue(newValue);
}
final List<JsonElement> lore = fullItem.lore();
ListTag<StringTag> lore = display.getListTag("Lore", StringTag.class);
if (lore != null) {
boolean changed = false;
final ListTag<StringTag> rawLore = fullItem.rawLore();
for (int i = 0; i < lore.size(); i++) {
final JsonElement loreEntry = lore.get(i);
final JsonElement updatedLoreEntry = loreEntry.deepCopy();
protocol.getComponentRewriter().processText(connection, updatedLoreEntry);
if (updatedLoreEntry.equals(loreEntry)) {
continue;
}
if (!changed) {
for (StringTag loreEntry : lore) {
String newValue = protocol.getTranslatableRewriter().processText(connection, loreEntry.getValue()).toString();
if (!changed && !newValue.equals(loreEntry.getValue())) {
// Backup original lore before doing any modifications
changed = true;
saveListTag(display, rawLore, "Lore");
saveListTag(display, lore, "Lore");
}
final StringTag rawLoreEntry = rawLore.get(i);
rawLoreEntry.setValue(updatedLoreEntry.toString());
loreEntry.setValue(newValue);
}
}
}
@@ -132,7 +116,7 @@ public class BackwardsItemRewriter<C extends ClientboundPacketType, S extends Se
public @Nullable Item handleItemToServer(UserConnection connection, @Nullable Item item) {
if (item == null) return null;
item = super.handleItemToServer(connection, item);
super.handleItemToServer(connection, item);
if (item.tag() != null) {
Tag originalId = item.tag().remove(nbtTagName("id"));
if (originalId instanceof IntTag) {
@@ -141,4 +125,92 @@ public class BackwardsItemRewriter<C extends ClientboundPacketType, S extends Se
}
return item;
}
@Override
public void registerAdvancements(C packetType) {
protocol.registerClientbound(packetType, new PacketHandlers() {
@Override
public void register() {
handler(wrapper -> {
wrapper.passthrough(Types.BOOLEAN); // Reset/clear
final int size = wrapper.passthrough(Types.VAR_INT); // Mapping size
for (int i = 0; i < size; i++) {
wrapper.passthrough(Types.STRING); // Identifier
wrapper.passthrough(Types.OPTIONAL_STRING); // Parent
// Display data
if (wrapper.passthrough(Types.BOOLEAN)) {
final JsonElement title = wrapper.passthrough(Types.COMPONENT);
final JsonElement description = wrapper.passthrough(Types.COMPONENT);
final TranslatableRewriter<C> translatableRewriter = protocol.getTranslatableRewriter();
if (translatableRewriter != null) {
translatableRewriter.processText(wrapper.user(), title);
translatableRewriter.processText(wrapper.user(), description);
}
final Item icon = handleItemToClient(wrapper.user(), wrapper.read(itemType()));
wrapper.write(mappedItemType(), icon);
wrapper.passthrough(Types.VAR_INT); // Frame type
int flags = wrapper.passthrough(Types.INT); // Flags
if ((flags & 1) != 0) {
wrapper.passthrough(Types.STRING); // Background texture
}
wrapper.passthrough(Types.FLOAT); // X
wrapper.passthrough(Types.FLOAT); // Y
}
wrapper.passthrough(Types.STRING_ARRAY); // Criteria
final int arrayLength = wrapper.passthrough(Types.VAR_INT);
for (int array = 0; array < arrayLength; array++) {
wrapper.passthrough(Types.STRING_ARRAY); // String array
}
}
});
}
});
}
@Override
public void registerAdvancements1_20_3(final C packetType) {
// Insert translatable rewriter
protocol.registerClientbound(packetType, wrapper -> {
wrapper.passthrough(Types.BOOLEAN); // Reset/clear
final int size = wrapper.passthrough(Types.VAR_INT); // Mapping size
for (int i = 0; i < size; i++) {
wrapper.passthrough(Types.STRING); // Identifier
wrapper.passthrough(Types.OPTIONAL_STRING); // Parent
// Display data
if (wrapper.passthrough(Types.BOOLEAN)) {
final Tag title = wrapper.passthrough(Types.TAG);
final Tag description = wrapper.passthrough(Types.TAG);
final TranslatableRewriter<C> translatableRewriter = protocol.getTranslatableRewriter();
if (translatableRewriter != null) {
translatableRewriter.processTag(wrapper.user(), title);
translatableRewriter.processTag(wrapper.user(), description);
}
final Item icon = handleItemToClient(wrapper.user(), wrapper.read(itemType()));
wrapper.write(mappedItemType(), icon);
wrapper.passthrough(Types.VAR_INT); // Frame type
final int flags = wrapper.passthrough(Types.INT);
if ((flags & 1) != 0) {
wrapper.passthrough(Types.STRING); // Background texture
}
wrapper.passthrough(Types.FLOAT); // X
wrapper.passthrough(Types.FLOAT); // Y
}
final int requirements = wrapper.passthrough(Types.VAR_INT);
for (int array = 0; array < requirements; array++) {
wrapper.passthrough(Types.STRING_ARRAY);
}
wrapper.passthrough(Types.BOOLEAN); // Send telemetry
}
});
}
}
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -17,17 +17,19 @@
*/
package com.viaversion.viabackwards.api.rewriters;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.rewriter.ItemRewriter;
import java.util.ArrayList;
import java.util.List;
import org.checkerframework.checker.nullness.qual.Nullable;
public abstract class BackwardsItemRewriterBase<C extends ClientboundPacketType, S extends ServerboundPacketType,
@@ -47,7 +49,7 @@ public abstract class BackwardsItemRewriterBase<C extends ClientboundPacketType,
@Override
public @Nullable Item handleItemToServer(UserConnection connection, @Nullable Item item) {
if (item == null) return null;
item = super.handleItemToServer(connection, item);
super.handleItemToServer(connection, item);
restoreDisplayTag(item);
return item;
@@ -73,6 +75,29 @@ public abstract class BackwardsItemRewriterBase<C extends ClientboundPacketType,
}
}
protected void saveGenericTagList(CompoundTag tag, List<Tag> original, String name) {
// List tags cannot contain tags of different types, so we have to store them a bit more awkwardly as an indexed compound tag
String backupName = nbtTagName(name);
if (!tag.contains(backupName)) {
CompoundTag output = new CompoundTag();
for (int i = 0; i < original.size(); i++) {
output.put(Integer.toString(i), original.get(i));
}
tag.put(backupName, output);
}
}
protected List<Tag> removeGenericTagList(CompoundTag tag, String name) {
String backupName = nbtTagName(name);
CompoundTag data = tag.getCompoundTag(backupName);
if (data == null) {
return null;
}
tag.remove(backupName);
return new ArrayList<>(data.values());
}
protected void restoreDisplayTag(Item item) {
if (item.tag() == null) return;
@@ -104,6 +129,17 @@ public abstract class BackwardsItemRewriterBase<C extends ClientboundPacketType,
}
}
public <T extends Tag> @Nullable ListTag<T> removeListTag(CompoundTag tag, String tagName, Class<T> tagType) {
String backupName = nbtTagName(tagName);
ListTag<T> data = tag.getListTag(backupName, tagType);
if (data == null) {
return null;
}
tag.remove(backupName);
return data;
}
@Override
public String nbtTagName() {
return "VB|" + protocol.getClass().getSimpleName();
@@ -1,91 +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.viabackwards.api.BackwardsProtocol;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.RegistryEntry;
import com.viaversion.viaversion.rewriter.RegistryDataRewriter;
import com.viaversion.viaversion.util.Key;
public class BackwardsRegistryRewriter extends RegistryDataRewriter {
private final BackwardsProtocol<?, ?, ?, ?> protocol;
public BackwardsRegistryRewriter(final BackwardsProtocol<?, ?, ?, ?> protocol) {
super(protocol);
this.protocol = protocol;
}
@Override
public RegistryEntry[] handle(final UserConnection connection, final String key, final RegistryEntry[] entries) {
if (Key.stripMinecraftNamespace(key).equals("worldgen/biome")) {
for (final RegistryEntry entry : entries) {
final CompoundTag biome = (CompoundTag) entry.tag();
if (biome == null) {
continue;
}
final CompoundTag effects = biome.getCompoundTag("effects");
updateBiomeEffects(effects);
}
}
return super.handle(connection, key, entries);
}
@Override
public void updateJukeboxSongs(final RegistryEntry[] entries) {
for (final RegistryEntry entry : entries) {
if (entry.tag() == null) {
continue;
}
updateSound((CompoundTag) entry.tag(), "sound_event");
}
}
private void updateBiomeEffects(final CompoundTag effects) {
updateSound(effects.getCompoundTag("mood_sound"), "sound");
updateSound(effects.getCompoundTag("additions_sound"), "sound");
updateSound(effects.getCompoundTag("music"), "sound");
updateSound(effects, "ambient_sound");
}
private void updateSound(final CompoundTag tag, final String name) {
if (tag == null) {
return;
}
final String sound = tag.getString(name);
if (sound == null) {
return;
}
final String mappedSound = protocol.getMappingData().getMappedNamedSound(sound);
if (mappedSound == null) {
return;
}
if (mappedSound.isEmpty()) {
tag.putString(name, "minecraft:intentionally_empty");
} else {
tag.putString(name, mappedSound);
}
}
}
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -18,347 +18,169 @@
package com.viaversion.viabackwards.api.rewriters;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.FloatTag;
import com.viaversion.nbt.tag.IntArrayTag;
import com.viaversion.nbt.tag.IntTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.NumberTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viabackwards.ViaBackwards;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.data.BackwardsMappingData;
import com.viaversion.viabackwards.api.data.MappedItem;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.EitherHolder;
import com.viaversion.viaversion.api.minecraft.Holder;
import com.viaversion.viaversion.api.minecraft.HolderSet;
import com.viaversion.viaversion.api.minecraft.SoundEvent;
import com.viaversion.viaversion.api.minecraft.data.StructuredData;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataContainer;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.minecraft.item.data.CustomModelData1_21_4;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import com.viaversion.viaversion.rewriter.StructuredItemRewriter;
import com.viaversion.viaversion.util.ArrayUtil;
import com.viaversion.viaversion.util.Key;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Function;
import com.viaversion.viaversion.api.type.Type;
import org.checkerframework.checker.nullness.qual.Nullable;
public class BackwardsStructuredItemRewriter<C extends ClientboundPacketType, S extends ServerboundPacketType,
T extends BackwardsProtocol<C, ?, ?, S>> extends StructuredItemRewriter<C, S, T> {
T extends BackwardsProtocol<C, ?, ?, S>> extends BackwardsItemRewriter<C, S, T> {
private static final int[] EMPTY_INT_ARRAY = new int[0];
private static final String GLOBAL_MODEL_DATA_MARKER = "VB|injected_cmd";
protected final StructuredEnchantmentRewriter enchantmentRewriter = new StructuredEnchantmentRewriter(this);
private final String nbtTagName;
public BackwardsStructuredItemRewriter(final T protocol, final Type<Item> itemType, final Type<Item[]> itemArrayType) {
super(protocol, itemType, itemArrayType);
}
public BackwardsStructuredItemRewriter(T protocol) {
super(protocol);
this.nbtTagName = "VB|" + protocol.getClass().getSimpleName();
public BackwardsStructuredItemRewriter(final T protocol, final Type<Item> itemType, final Type<Item[]> itemArrayType, final Type<Item> mappedItemType, final Type<Item[]> mappedItemArrayType) {
super(protocol, itemType, itemArrayType, mappedItemType, mappedItemArrayType);
}
@Override
protected void backupInconvertibleData(final UserConnection connection, final Item item, final StructuredDataContainer dataContainer, final CompoundTag backupTag) {
super.backupInconvertibleData(connection, item, dataContainer, backupTag);
public Item handleItemToClient(final UserConnection connection, final Item item) {
if (item.isEmpty()) {
return item;
}
final StructuredDataContainer data = item.dataContainer();
data.setIdLookup(protocol, true);
if (protocol.getMappingData().getEnchantmentMappings() != null) {
enchantmentRewriter.handleToClient(item);
}
if (protocol.getTranslatableRewriter() != null) {
// Handle name and lore components
final StructuredData<Tag> customNameData = data.getNonEmpty(StructuredDataKey.CUSTOM_NAME);
if (customNameData != null) {
final Tag originalName = customNameData.value().copy();
protocol.getTranslatableRewriter().processTag(connection, customNameData.value());
if (!customNameData.value().equals(originalName)) {
saveTag(createCustomTag(item), originalName, "Name");
}
}
final StructuredData<Tag[]> loreData = data.getNonEmpty(StructuredDataKey.LORE);
if (loreData != null) {
for (final Tag tag : loreData.value()) {
protocol.getTranslatableRewriter().processTag(connection, tag);
}
}
}
final BackwardsMappingData mappingData = protocol.getMappingData();
final MappedItem mappedItem = mappingData != null ? mappingData.getMappedItem(item.identifier()) : null;
if (mappedItem == null) {
return;
// Just rewrite the id
if (mappingData != null && mappingData.getItemMappings() != null) {
item.setIdentifier(mappingData.getNewItemId(item.identifier()));
}
return item;
}
final CompoundTag customTag = createCustomTag(item);
customTag.putInt(nbtTagName("id"), item.identifier()); // Save original id
// Save original id, set remapped id
final CompoundTag tag = createCustomTag(item);
tag.putInt(nbtTagName("id"), item.identifier());
item.setIdentifier(mappedItem.id());
// Add custom model data
final boolean addOriginalIdentifier = ViaBackwards.getConfig().passOriginalItemNameToResourcePacks();
if (mappedItem.customModelData() != null || addOriginalIdentifier) {
if (connection.getProtocolInfo().protocolVersion().newerThanOrEqualTo(ProtocolVersion.v1_21_4)) {
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());
}
if (mappedItem.customModelData() != null && !data.contains(StructuredDataKey.CUSTOM_MODEL_DATA)) {
data.set(StructuredDataKey.CUSTOM_MODEL_DATA, mappedItem.customModelData());
}
// Set custom name - only done if there is no original one
if (!dataContainer.has(StructuredDataKey.CUSTOM_NAME)) {
dataContainer.set(StructuredDataKey.CUSTOM_NAME, mappedItem.tagName());
customTag.putBoolean(nbtTagName("added_custom_name"), true);
}
}
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) {
final String[] strings = addOriginalIdentifier
? new String[]{protocol.getMappingData().getFullItemMappings().identifier(item.identifier())}
: new String[0];
customModelData = new CustomModelData1_21_4(
mappedItem.customModelData() != null ? new float[]{mappedItem.customModelData().floatValue()} : new float[0],
new boolean[0],
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 (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()
));
customTag.putBoolean(GLOBAL_MODEL_DATA_MARKER, true);
customTag.putString(nbtTagName("injected_custom_model_data"), identifier);
if (!data.contains(StructuredDataKey.CUSTOM_NAME)) {
data.set(StructuredDataKey.CUSTOM_NAME, mappedItem.tagName());
tag.putBoolean(nbtTagName("customName"), true);
}
return item;
}
@Override
protected void restoreBackupData(final Item item, final StructuredDataContainer container, final CompoundTag customData) {
super.restoreBackupData(item, container, customData);
if (removeBackupTag(customData, "id") instanceof final IntTag originalTag) {
item.setIdentifier(originalTag.asInt());
removeCustomTag(container, customData);
public Item handleItemToServer(final UserConnection connection, final Item item) {
if (item.isEmpty()) {
return item;
}
if (removeBackupTag(customData, "injected_custom_model_data") instanceof StringTag injectedCustomModelData) {
customData.remove(GLOBAL_MODEL_DATA_MARKER);
container.replace(StructuredDataKey.CUSTOM_MODEL_DATA1_21_4, customModelData -> {
final String target = injectedCustomModelData.getValue();
final String[] strings = customModelData.strings();
for (int i = 0; i < strings.length; i++) {
if (strings[i].equals(target)) {
// Remove the injected string
final String[] filteredStrings = ArrayUtil.remove(strings, i);
return new CustomModelData1_21_4(customModelData.floats(), customModelData.booleans(), filteredStrings, customModelData.colors());
}
}
return customModelData;
});
} else if (removeBackupTag(customData, "added_custom_model_data") != null) {
customData.remove(GLOBAL_MODEL_DATA_MARKER);
container.remove(StructuredDataKey.CUSTOM_MODEL_DATA1_21_4);
}
}
protected void saveListTag(CompoundTag tag, ListTag<?> original, String name) {
// Multiple places might try to backup data
String backupName = nbtTagName(name);
if (!tag.contains(backupName)) {
tag.put(backupName, original.copy());
}
}
public <T extends Tag> @Nullable ListTag<T> removeListTag(CompoundTag tag, String tagName, Class<T> tagType) {
String backupName = nbtTagName(tagName);
ListTag<T> data = tag.getListTag(backupName, tagType);
if (data == null) {
return null;
final BackwardsMappingData mappingData = protocol.getMappingData();
if (mappingData != null && mappingData.getItemMappings() != null) {
item.setIdentifier(mappingData.getOldItemId(item.identifier()));
}
tag.remove(backupName);
return data;
}
final StructuredDataContainer data = item.dataContainer();
data.setIdLookup(protocol, false);
protected void saveGenericTagList(CompoundTag tag, List<Tag> original, String name) {
// List tags cannot contain tags of different types, so we have to store them a bit more awkwardly as an indexed compound tag
String backupName = nbtTagName(name);
if (!tag.contains(backupName)) {
CompoundTag output = new CompoundTag();
for (int i = 0; i < original.size(); i++) {
output.put(Integer.toString(i), original.get(i));
if (protocol.getMappingData().getEnchantmentMappings() != null) {
enchantmentRewriter.handleToServer(item);
}
final CompoundTag tag = customTag(item);
if (tag != null) {
final Tag originalId = tag.remove(nbtTagName("id"));
if (originalId instanceof IntTag) {
item.setIdentifier(((NumberTag) originalId).asInt());
}
tag.put(backupName, output);
}
restoreDisplayTag(item);
return item;
}
protected List<Tag> removeGenericTagList(CompoundTag tag, String name) {
String backupName = nbtTagName(name);
CompoundTag data = tag.getCompoundTag(backupName);
if (data == null) {
return null;
}
tag.remove(backupName);
return new ArrayList<>(data.values());
protected @Nullable CompoundTag customTag(final Item item) {
final StructuredData<CompoundTag> customData = item.dataContainer().getNonEmpty(StructuredDataKey.CUSTOM_DATA);
return customData != null ? customData.value() : null;
}
protected Tag holderSetToTag(final HolderSet set) {
if (set.hasIds()) {
return new IntArrayTag(set.ids());
} else {
return new StringTag(set.tagKey());
}
}
protected HolderSet restoreHolderSet(final CompoundTag tag, final String key) {
final Tag savedTag = tag.get(key);
if (savedTag == null) {
return HolderSet.of(EMPTY_INT_ARRAY);
protected CompoundTag createCustomTag(final Item item) {
final StructuredDataContainer data = item.dataContainer();
final StructuredData<CompoundTag> customData = data.getNonEmpty(StructuredDataKey.CUSTOM_DATA);
if (customData != null) {
return customData.value();
}
if (savedTag instanceof StringTag tagKey) {
return HolderSet.of(tagKey.getValue());
} else if (savedTag instanceof IntArrayTag idsTag) {
return HolderSet.of(idsTag.getValue());
} else {
return HolderSet.of(EMPTY_INT_ARRAY);
}
}
protected <V> Tag holderToTag(final Holder<V> holder, final BiConsumer<V, CompoundTag> valueSaveFunction) {
if (holder.hasId()) {
return new IntTag(holder.id());
} else {
final CompoundTag savedTag = new CompoundTag();
valueSaveFunction.accept(holder.value(), savedTag);
return savedTag;
}
}
protected <V> Tag eitherHolderToTag(final EitherHolder<V> holder, final BiConsumer<V, CompoundTag> valueSaveFunction) {
if (holder.hasKey()) {
return new StringTag(holder.key());
} else {
return holderToTag(holder.holder(), valueSaveFunction);
}
}
protected <V> void saveEitherHolderData(final StructuredDataKey<EitherHolder<V>> key, final StructuredDataContainer data, final CompoundTag backupTag, final BiConsumer<V, CompoundTag> valueSaveFunction) {
final EitherHolder<V> holder = data.get(key);
if (holder != null) {
backupTag.put(key.identifier(), eitherHolderToTag(holder, valueSaveFunction));
}
}
protected <V> void saveHolderData(final StructuredDataKey<Holder<V>> key, final StructuredDataContainer data, final CompoundTag backupTag, final BiConsumer<V, CompoundTag> valueSaveFunction) {
final Holder<V> holder = data.get(key);
if (holder != null) {
backupTag.put(key.identifier(), holderToTag(holder, valueSaveFunction));
}
}
protected <V> Holder<V> restoreHolder(final CompoundTag tag, final String key, final Function<CompoundTag, V> valueRestoreFunction) {
final Tag savedTag = tag.get(key);
if (savedTag == null) {
return Holder.of(0);
}
if (savedTag instanceof IntTag idTag) {
return Holder.of(idTag.asInt());
} else if (savedTag instanceof CompoundTag compoundTag) {
return Holder.of(valueRestoreFunction.apply(compoundTag));
} else {
return Holder.of(0);
}
}
protected <V> EitherHolder<V> restoreEitherHolder(final CompoundTag tag, final String key, final Function<CompoundTag, V> valueRestoreFunction) {
final Tag savedTag = tag.get(key);
if (savedTag == null) {
return EitherHolder.of(Holder.of(0));
}
if (savedTag instanceof StringTag keyTag) {
return EitherHolder.of(keyTag.getValue());
} else {
return EitherHolder.of(restoreHolder(tag, key, valueRestoreFunction));
}
}
protected <V> void restoreHolderData(final StructuredDataKey<Holder<V>> key, final StructuredDataContainer data, final CompoundTag backupTag, final Function<CompoundTag, V> valueRestoreFunction) {
if (backupTag.contains(key.identifier())) {
data.set(key, restoreHolder(backupTag, key.identifier(), valueRestoreFunction));
}
}
protected void saveStringData(final StructuredDataKey<String> key, final StructuredDataContainer data, final CompoundTag backupTag) {
final String value = data.get(key);
if (value != null) {
backupTag.putString(key.identifier(), value);
}
}
protected void restoreStringData(final StructuredDataKey<String> key, final StructuredDataContainer data, final CompoundTag backupTag) {
final String value = backupTag.getString(key.identifier());
if (value != null) {
data.set(key, value);
}
}
protected void saveKeyData(final StructuredDataKey<Key> key, final StructuredDataContainer data, final CompoundTag backupTag) {
final Key value = data.get(key);
if (value != null) {
backupTag.putString(key.identifier(), value.original());
}
}
protected void restoreKeyData(final StructuredDataKey<Key> key, final StructuredDataContainer data, final CompoundTag backupTag) {
final String value = backupTag.getString(key.identifier());
if (value != null) {
data.set(key, Key.of(value));
}
}
protected void saveIntData(final StructuredDataKey<Integer> key, final StructuredDataContainer data, final CompoundTag backupTag) {
final Integer variant = data.get(key);
if (variant != null) {
backupTag.putInt(key.identifier(), variant);
}
}
protected void restoreIntData(final StructuredDataKey<Integer> key, final StructuredDataContainer data, final CompoundTag backupTag) {
final IntTag variant = backupTag.getIntTag(key.identifier());
if (variant != null) {
data.set(key, variant.asInt());
}
}
protected void saveFloatData(final StructuredDataKey<Float> key, final StructuredDataContainer data, final CompoundTag backupTag) {
final Float variant = data.get(key);
if (variant != null) {
backupTag.putFloat(key.identifier(), variant);
}
}
protected void restoreFloatData(final StructuredDataKey<Float> key, final StructuredDataContainer data, final CompoundTag backupTag) {
final FloatTag variant = backupTag.getFloatTag(key.identifier());
if (variant != null) {
data.set(key, variant.asFloat());
}
}
protected void saveSoundEventHolder(final CompoundTag tag, final Holder<SoundEvent> holder) {
tag.put("sound_event", holderToTag(holder, this::saveSoundEvent));
}
protected void saveSoundEvent(final SoundEvent soundEvent, final CompoundTag tag) {
tag.putString("identifier", soundEvent.identifier());
if (soundEvent.fixedRange() != null) {
tag.putFloat("fixed_range", soundEvent.fixedRange());
}
}
protected Holder<SoundEvent> restoreSoundEventHolder(final CompoundTag tag) {
return restoreSoundEventHolder(tag, "sound_event");
}
protected Holder<SoundEvent> restoreSoundEventHolder(final CompoundTag tag, final String key) {
return restoreHolder(tag, key, soundEventTag -> {
final String identifier = soundEventTag.getString("identifier");
final FloatTag fixedRange = soundEventTag.getFloatTag("fixed_range");
return new SoundEvent(identifier, fixedRange != null ? fixedRange.asFloat() : null);
});
final CompoundTag tag = new CompoundTag();
data.set(StructuredDataKey.CUSTOM_DATA, tag);
return tag;
}
@Override
public String nbtTagName() {
return this.nbtTagName;
protected void restoreDisplayTag(final Item item) {
final StructuredDataContainer data = item.dataContainer();
final StructuredData<CompoundTag> customData = data.getNonEmpty(StructuredDataKey.CUSTOM_DATA);
if (customData == null) {
return;
}
// Remove custom name
if (customData.value().remove(nbtTagName("customName")) != null) {
data.remove(StructuredDataKey.CUSTOM_NAME);
} else {
final Tag name = removeBackupTag(customData.value(), "Name");
if (name != null) {
data.set(StructuredDataKey.CUSTOM_NAME, name);
}
}
}
protected void saveTag(CompoundTag customData, Tag tag, String name) {
String backupName = nbtTagName(name);
if (!customData.contains(backupName)) {
customData.put(backupName, tag);
}
}
protected @Nullable Tag removeBackupTag(CompoundTag customData, String tagName) {
return customData.remove(nbtTagName(tagName));
}
}
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -17,12 +17,12 @@
*/
package com.viaversion.viabackwards.api.rewriters;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.NumberTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viabackwards.utils.ChatUtil;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.util.ComponentUtil;
import com.viaversion.viaversion.util.Key;
import java.util.ArrayList;
import java.util.HashMap;
@@ -35,8 +35,6 @@ import java.util.Map;
*/
public class EnchantmentRewriter {
public static final String ENCHANTMENT_LEVEL_TRANSLATION = "enchantment.level.%s";
protected final Map<String, String> enchantmentMappings = new HashMap<>();
protected final BackwardsItemRewriter<?, ?, ?> itemRewriter;
private final boolean jsonFormat;
@@ -105,11 +103,9 @@ public class EnchantmentRewriter {
NumberTag levelTag = enchantmentEntry.getNumberTag("lvl");
int level = levelTag != null ? levelTag.asInt() : 1;
String loreValue;
String loreValue = remappedName + " " + getRomanNumber(level);
if (jsonFormat) {
loreValue = ChatUtil.legacyToJsonString(remappedName, ENCHANTMENT_LEVEL_TRANSLATION.formatted(level), true);
} else {
loreValue = remappedName + " " + getRomanNumber(level);
loreValue = ComponentUtil.legacyToJsonString(loreValue);
}
loreToAdd.add(new StringTag(loreValue));
@@ -161,7 +157,7 @@ public class EnchantmentRewriter {
case 8 -> "VIII";
case 9 -> "IX";
case 10 -> "X";
default -> ENCHANTMENT_LEVEL_TRANSLATION.formatted(number); // Fallback to translation to match vanilla style
default -> Integer.toString(number);
};
}
}
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -24,6 +24,8 @@ import com.viaversion.viaversion.api.minecraft.entitydata.EntityDataType;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandler;
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.version.Types1_14;
@@ -38,50 +40,56 @@ public abstract class EntityRewriter<C extends ClientboundPacketType, T extends
}
@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);
public void registerTrackerWithData(C packetType, EntityType fallingBlockType) {
protocol.registerClientbound(packetType, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // 0 - Entity id
map(Types.UUID); // 1 - Entity UUID
map(Types.VAR_INT); // 2 - Entity Type
map(Types.DOUBLE); // 3 - X
map(Types.DOUBLE); // 4 - Y
map(Types.DOUBLE); // 5 - Z
map(Types.BYTE); // 6 - Pitch
map(Types.BYTE); // 7 - Yaw
map(Types.INT); // 8 - Data
handler(getSpawnTrackerWithDataHandler(fallingBlockType));
}
});
}
@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 void registerTrackerWithData1_19(C packetType, EntityType fallingBlockType) {
protocol.registerClientbound(packetType, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // Entity id
map(Types.UUID); // Entity UUID
map(Types.VAR_INT); // Entity type
map(Types.DOUBLE); // X
map(Types.DOUBLE); // Y
map(Types.DOUBLE); // Z
map(Types.BYTE); // Pitch
map(Types.BYTE); // Yaw
map(Types.BYTE); // Head yaw
map(Types.VAR_INT); // Data
handler(getSpawnTrackerWithDataHandler1_19(fallingBlockType));
}
});
}
public PacketHandler getSpawnTrackerWithDataHandler() {
public PacketHandler getSpawnTrackerWithDataHandler(EntityType fallingBlockType) {
return wrapper -> {
// Check against the UNMAPPED entity type
EntityType entityType = trackAndMapEntity(wrapper);
if (entityType == typeFromId("falling_block")) {
if (entityType == fallingBlockType) {
int blockState = wrapper.get(Types.INT, 0);
wrapper.set(Types.INT, 0, protocol.getMappingData().getNewBlockStateId(blockState));
}
};
}
public PacketHandler getSpawnTrackerWithDataHandler1_19() {
public PacketHandler getSpawnTrackerWithDataHandler1_19(EntityType fallingBlockType) {
return wrapper -> {
if (protocol.getMappingData() == null) {
return;
@@ -89,20 +97,22 @@ public abstract class EntityRewriter<C extends ClientboundPacketType, T extends
// Check against the UNMAPPED entity type
EntityType entityType = trackAndMapEntity(wrapper);
if (entityType == typeFromId("falling_block")) {
if (entityType == fallingBlockType) {
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);
public void registerSpawnTracker(C packetType) {
protocol.registerClientbound(packetType, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // 0 - Entity ID
map(Types.UUID); // 1 - Entity UUID
map(Types.VAR_INT); // 2 - Entity Type
handler(wrapper -> trackAndMapEntity(wrapper));
}
});
}
@@ -117,6 +127,7 @@ public abstract class EntityRewriter<C extends ClientboundPacketType, T extends
String world = wrapper.get(Types.STRING, 1);
if (tracker.currentWorld() != null && !tracker.currentWorld().equals(world)) {
tracker.clearEntities();
tracker.trackClientEntity();
}
tracker.setCurrentWorld(world);
};
@@ -131,10 +142,6 @@ public abstract class EntityRewriter<C extends ClientboundPacketType, T extends
protected EntityType trackAndMapEntity(PacketWrapper wrapper) {
int typeId = wrapper.get(Types.VAR_INT, 1);
EntityType entityType = typeFromId(typeId);
if (entityType == null) {
return null;
}
tracker(wrapper.user()).addEntity(wrapper.get(Types.VAR_INT, 0), entityType);
int mappedTypeId = newEntityId(entityType.getId());
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -21,9 +21,8 @@ import com.google.common.base.Preconditions;
import com.viaversion.viabackwards.ViaBackwards;
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.viabackwards.api.entities.storage.WrappedMetadata;
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;
@@ -51,24 +50,24 @@ import org.checkerframework.checker.nullness.qual.Nullable;
*/
public abstract class EntityRewriterBase<C extends ClientboundPacketType, T extends BackwardsProtocol<C, ?, ?, ?>> extends EntityRewriter<C, T> {
private final Int2ObjectMap<EntityReplacement> entityDataMappings = new Int2ObjectOpenHashMap<>();
private final EntityDataType displayNameDataType;
private final EntityDataType displayVisibilityDataType;
private final EntityDataType displayNameMetaType;
private final EntityDataType displayVisibilityMetaType;
private final int displayNameIndex;
private final int displayVisibilityIndex;
EntityRewriterBase(T protocol, EntityDataType displayNameDataType, int displayNameIndex,
EntityDataType displayVisibilityDataType, int displayVisibilityIndex) {
EntityRewriterBase(T protocol, EntityDataType displayNameMetaType, int displayNameIndex,
EntityDataType displayVisibilityMetaType, int displayVisibilityIndex) {
super(protocol, false);
this.displayNameDataType = displayNameDataType;
this.displayNameMetaType = displayNameMetaType;
this.displayNameIndex = displayNameIndex;
this.displayVisibilityDataType = displayVisibilityDataType;
this.displayVisibilityMetaType = displayVisibilityMetaType;
this.displayVisibilityIndex = displayVisibilityIndex;
}
@Override
public void handleEntityData(int entityId, List<EntityData> entityDataList, UserConnection connection) {
final TrackedEntity entity = tracker(connection).entity(entityId);
final boolean initialEntityData = !(entity != null && entity.hasSentEntityData());
final boolean initialMetadata = !(entity != null && entity.hasSentEntityData());
super.handleEntityData(entityId, entityDataList, connection);
@@ -81,37 +80,37 @@ public abstract class EntityRewriterBase<C extends ClientboundPacketType, T exte
final Object displayNameObject;
if (entityMapping != null && (displayNameObject = entityMapping.entityName()) != null) {
final EntityData displayName = getData(displayNameIndex, entityDataList);
if (initialEntityData) {
if (initialMetadata) {
if (displayName == null) {
// Add it as new entity data
entityDataList.add(new EntityData(displayNameIndex, displayNameDataType, displayNameObject));
addDisplayVisibilityData(entityDataList);
// Add it as new metadata
entityDataList.add(new EntityData(displayNameIndex, displayNameMetaType, displayNameObject));
addDisplayVisibilityMeta(entityDataList);
} else if (displayName.getValue() == null || displayName.getValue().toString().isEmpty()) {
// Overwrite the existing null/empty display name
displayName.setValue(displayNameObject);
addDisplayVisibilityData(entityDataList);
addDisplayVisibilityMeta(entityDataList);
}
} else if (displayName != null && (displayName.getValue() == null || displayName.getValue().toString().isEmpty())) {
// Overwrite null/empty display name
displayName.setValue(displayNameObject);
addDisplayVisibilityData(entityDataList);
addDisplayVisibilityMeta(entityDataList);
}
}
// Add any other extra data for mapped entities
if (entityMapping != null && entityMapping.hasBaseData() && initialEntityData) {
entityMapping.defaultData().createData(new WrappedEntityData(entityDataList));
// Add any other extra meta for mapped entities
if (entityMapping != null && entityMapping.hasBaseMeta() && initialMetadata) {
entityMapping.defaultMeta().createMeta(new WrappedMetadata(entityDataList));
}
}
private void addDisplayVisibilityData(List<EntityData> entityDataList) {
private void addDisplayVisibilityMeta(List<EntityData> metadataList) {
if (alwaysShowOriginalMobName()) {
removeData(displayVisibilityIndex, entityDataList);
entityDataList.add(new EntityData(displayVisibilityIndex, displayVisibilityDataType, getDisplayVisibilityDataValue()));
removeMeta(displayVisibilityIndex, metadataList);
metadataList.add(new EntityData(displayVisibilityIndex, displayVisibilityMetaType, getDisplayVisibilityMetaValue()));
}
}
protected Object getDisplayVisibilityDataValue() {
protected Object getDisplayVisibilityMetaValue() {
return true;
}
@@ -119,17 +118,17 @@ public abstract class EntityRewriterBase<C extends ClientboundPacketType, T exte
return ViaBackwards.getConfig().alwaysShowOriginalMobName();
}
protected @Nullable EntityData getData(int dataIndex, List<EntityData> entityDataList) {
for (EntityData entityData : entityDataList) {
if (entityData.id() == dataIndex) {
return entityData;
protected @Nullable EntityData getData(int metaIndex, List<EntityData> metadataList) {
for (EntityData metadata : metadataList) {
if (metadata.id() == metaIndex) {
return metadata;
}
}
return null;
}
protected void removeData(int dataIndex, List<EntityData> entityDataList) {
entityDataList.removeIf(data -> data.id() == dataIndex);
protected void removeMeta(int metaIndex, List<EntityData> metadataList) {
metadataList.removeIf(meta -> meta.id() == metaIndex);
}
protected boolean hasData(EntityType type) {
@@ -164,7 +163,7 @@ public abstract class EntityRewriterBase<C extends ClientboundPacketType, T exte
return data;
}
public void registerEntityDataTypeHandler(
public void registerMetaTypeHandler(
@Nullable EntityDataType itemType,
@Nullable EntityDataType blockStateType,
@Nullable EntityDataType optionalBlockStateType,
@@ -172,28 +171,28 @@ public abstract class EntityRewriterBase<C extends ClientboundPacketType, T exte
@Nullable EntityDataType componentType,
@Nullable EntityDataType optionalComponentType
) {
filter().handler((event, data) -> {
EntityDataType type = data.dataType();
filter().handler((event, meta) -> {
EntityDataType type = meta.dataType();
if (type == itemType) {
data.setValue(protocol.getItemRewriter().handleItemToClient(event.user(), data.value()));
protocol.getItemRewriter().handleItemToClient(event.user(), meta.value());
} else if (type == blockStateType) {
int value = data.value();
data.setValue(protocol.getMappingData().getNewBlockStateId(value));
int data = meta.value();
meta.setValue(protocol.getMappingData().getNewBlockStateId(data));
} else if (type == optionalBlockStateType) {
int value = data.value();
if (value != 0) {
data.setValue(protocol.getMappingData().getNewBlockStateId(value));
int data = meta.value();
if (data != 0) {
meta.setValue(protocol.getMappingData().getNewBlockStateId(data));
}
} else if (type == particleType) {
protocol.getParticleRewriter().rewriteParticle(event.user(), data.value());
rewriteParticle(event.user(), meta.value());
} else if (type == optionalComponentType || type == componentType) {
JsonElement text = data.value();
protocol.getComponentRewriter().processText(event.user(), text);
JsonElement text = meta.value();
protocol.getTranslatableRewriter().processText(event.user(), text);
}
});
}
public void registerEntityDataTypeHandler1_20_3(
public void registerMetaTypeHandler1_20_3(
@Nullable EntityDataType itemType,
@Nullable EntityDataType blockStateType,
@Nullable EntityDataType optionalBlockStateType,
@@ -202,27 +201,27 @@ public abstract class EntityRewriterBase<C extends ClientboundPacketType, T exte
@Nullable EntityDataType componentType,
@Nullable EntityDataType optionalComponentType
) {
filter().handler((event, data) -> {
EntityDataType type = data.dataType();
filter().handler((event, meta) -> {
EntityDataType type = meta.dataType();
if (type == itemType) {
data.setValue(protocol.getItemRewriter().handleItemToClient(event.user(), data.value()));
meta.setValue(protocol.getItemRewriter().handleItemToClient(event.user(), meta.value()));
} else if (type == blockStateType) {
int value = data.value();
data.setValue(protocol.getMappingData().getNewBlockStateId(value));
int data = meta.value();
meta.setValue(protocol.getMappingData().getNewBlockStateId(data));
} else if (type == optionalBlockStateType) {
int value = data.value();
if (value != 0) {
data.setValue(protocol.getMappingData().getNewBlockStateId(value));
int data = meta.value();
if (data != 0) {
meta.setValue(protocol.getMappingData().getNewBlockStateId(data));
}
} else if (type == particleType) {
protocol.getParticleRewriter().rewriteParticle(event.user(), data.value());
rewriteParticle(event.user(), meta.value());
} else if (type == particlesType) {
Particle[] particles = data.value();
Particle[] particles = meta.value();
for (final Particle particle : particles) {
protocol.getParticleRewriter().rewriteParticle(event.user(), particle);
rewriteParticle(event.user(), particle);
}
} else if (type == optionalComponentType || type == componentType) {
protocol.getComponentRewriter().processTag(event.user(), data.value());
protocol.getTranslatableRewriter().processTag(event.user(), meta.value());
}
});
}
@@ -231,10 +230,7 @@ public abstract class EntityRewriterBase<C extends ClientboundPacketType, T exte
protected PacketHandler getTrackerHandler(Type<? extends Number> intType, int typeIndex) {
return wrapper -> {
Number id = wrapper.get(intType, typeIndex);
EntityType entityType = typeFromId(id.intValue());
if (entityType != null) {
tracker(wrapper.user()).addEntity(wrapper.get(Types.VAR_INT, 0), entityType);
}
tracker(wrapper.user()).addEntity(wrapper.get(Types.VAR_INT, 0), typeFromId(id.intValue()));
};
}
@@ -242,27 +238,15 @@ 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 getTrackerHandler(EntityType entityType, Type<? extends Number> intType) {
return wrapper -> tracker(wrapper.user()).addEntity((int) wrapper.get(intType, 0), entityType);
}
protected PacketHandler getDimensionHandler(int index) {
return wrapper -> {
ClientWorld clientWorld = wrapper.user().getClientWorld(this.protocol.getClass());
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
int dimensionId = wrapper.get(Types.INT, index);
if (clientWorld.setEnvironment(dimensionId)) {
tracker(wrapper.user()).clearEntities();
}
clientWorld.setEnvironment(dimensionId);
};
}
}
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -18,16 +18,9 @@
package com.viaversion.viabackwards.api.rewriters;
import com.viaversion.nbt.tag.ByteTag;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.IntTag;
import com.viaversion.nbt.tag.NumberTag;
import com.viaversion.nbt.tag.ShortTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.data.BackwardsMappingDataLoader;
import com.viaversion.viabackwards.api.data.MappedLegacyBlockItem;
import com.viaversion.viabackwards.api.data.BackwardsMappingDataLoader;
import com.viaversion.viabackwards.protocol.v1_12to1_11_1.data.BlockColors1_11_1;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.BlockChangeRecord;
@@ -48,10 +41,18 @@ import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectOpenHashMap;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.libs.gson.JsonObject;
import com.viaversion.viaversion.libs.gson.JsonPrimitive;
import com.viaversion.nbt.tag.ByteTag;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.IntTag;
import com.viaversion.nbt.tag.NumberTag;
import com.viaversion.nbt.tag.ShortTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.util.ComponentUtil;
import com.viaversion.viaversion.util.IdAndData;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import com.viaversion.viaversion.util.IdAndData;
import org.checkerframework.checker.nullness.qual.Nullable;
public abstract class LegacyBlockItemRewriter<C extends ClientboundPacketType, S extends ServerboundPacketType,
@@ -103,9 +104,9 @@ public abstract class LegacyBlockItemRewriter<C extends ClientboundPacketType, S
// Include data
short unmappedData = Short.parseShort(key.substring(dataSeparatorIndex + 1));
unmappedId = Integer.parseInt(key.substring(0, dataSeparatorIndex));
unmappedId = compress(unmappedId, unmappedData);
unmappedId = IdAndData.toRawData(unmappedId, unmappedData);
} else {
unmappedId = compress(Integer.parseInt(key), -1);
unmappedId = IdAndData.toRawData(Integer.parseInt(key), -1);
}
mappings.put(unmappedId, new MappedLegacyBlockItem(id, data, name, type));
@@ -120,12 +121,12 @@ public abstract class LegacyBlockItemRewriter<C extends ClientboundPacketType, S
// Special block color handling
if (name != null && name.contains("%color%")) {
for (int i = from; i <= to; i++) {
mappings.put(compress(i, -1), new MappedLegacyBlockItem(id, data, name.replace("%color%", BlockColors1_11_1.get(i - from)), type));
mappings.put(IdAndData.toRawData(i, -1), new MappedLegacyBlockItem(id, data, name.replace("%color%", BlockColors1_11_1.get(i - from)), type));
}
} else {
MappedLegacyBlockItem mappedBlockItem = new MappedLegacyBlockItem(id, data, name, type);
for (int i = from; i <= to; i++) {
mappings.put(compress(i, -1), mappedBlockItem);
mappings.put(IdAndData.toRawData(i, -1), mappedBlockItem);
}
}
}
@@ -208,9 +209,9 @@ public abstract class LegacyBlockItemRewriter<C extends ClientboundPacketType, S
}
@Override
public @Nullable Item handleItemToServer(UserConnection connection, @Nullable Item item) {
public @Nullable Item handleItemToServer(UserConnection connection, @Nullable final Item item) {
if (item == null) return null;
item = super.handleItemToServer(connection, item);
super.handleItemToServer(connection, item);
if (item.tag() != null) {
Tag originalId = item.tag().remove(nbtTagName("id"));
if (originalId instanceof IntTag) {
@@ -226,9 +227,10 @@ public abstract class LegacyBlockItemRewriter<C extends ClientboundPacketType, S
public PacketHandler getFallingBlockHandler() {
return wrapper -> {
final int objectData = wrapper.get(Types.INT, 0);
final EntityTypes1_12.ObjectType type = EntityTypes1_12.ObjectType.findById(wrapper.get(Types.BYTE, 0), objectData);
final EntityTypes1_12.ObjectType type = EntityTypes1_12.ObjectType.findById(wrapper.get(Types.BYTE, 0));
if (type == EntityTypes1_12.ObjectType.FALLING_BLOCK) {
final int objectData = wrapper.get(Types.INT, 0);
final IdAndData block = handleBlock(objectData & 4095, objectData >> 12 & 15);
if (block == null) return;
@@ -287,7 +289,7 @@ public abstract class LegacyBlockItemRewriter<C extends ClientboundPacketType, S
MappedLegacyBlockItem settings = getMappedBlock(block);
if (settings != null && settings.hasBlockEntityHandler()) {
settings.getBlockEntityHandler().handleCompoundTag(block, tag);
settings.getBlockEntityHandler().handleOrNewCompoundTag(block, tag);
}
}
@@ -341,7 +343,7 @@ public abstract class LegacyBlockItemRewriter<C extends ClientboundPacketType, S
tag.putInt("y", y + (i << 4));
tag.putInt("z", z + (chunk.getZ() << 4));
settings.getBlockEntityHandler().handleCompoundTag(block, tag);
settings.getBlockEntityHandler().handleOrNewCompoundTag(block, tag);
chunk.getBlockEntities().add(tag);
}
}
@@ -359,13 +361,13 @@ public abstract class LegacyBlockItemRewriter<C extends ClientboundPacketType, S
}
private @Nullable MappedLegacyBlockItem getMappedBlock(int id, int data) {
MappedLegacyBlockItem mapping = blockReplacements.get(compress(id, data));
return mapping != null ? mapping : blockReplacements.get(compress(id, -1));
MappedLegacyBlockItem mapping = blockReplacements.get(IdAndData.toRawData(id, data));
return mapping != null ? mapping : blockReplacements.get(IdAndData.toRawData(id, -1));
}
private @Nullable MappedLegacyBlockItem getMappedItem(int id, int data) {
MappedLegacyBlockItem mapping = itemReplacements.get(compress(id, data));
return mapping != null ? mapping : itemReplacements.get(compress(id, -1));
MappedLegacyBlockItem mapping = itemReplacements.get(IdAndData.toRawData(id, data));
return mapping != null ? mapping : itemReplacements.get(IdAndData.toRawData(id, -1));
}
private @Nullable MappedLegacyBlockItem getMappedBlock(int rawId) {
@@ -378,11 +380,6 @@ public abstract class LegacyBlockItemRewriter<C extends ClientboundPacketType, S
return BackwardsMappingDataLoader.INSTANCE.loadFromDataDir(name);
}
protected int compress(final int id, final int data) {
// Using IdAndData for the internal storage can cause id overlaps in edge cases and would lead to wrong data
return (id << 16) | (data & 0xFFFF);
}
private record Pos(int x, short y, int z) {
public Pos(int x, int y, int z) {
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -17,6 +17,7 @@
*/
package com.viaversion.viabackwards.api.rewriters;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.nbt.tag.ByteTag;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.IntTag;
@@ -24,7 +25,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.viaversion.api.minecraft.item.Item;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -18,9 +18,9 @@
package com.viaversion.viabackwards.api.rewriters;
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.viabackwards.api.entities.storage.EntityObjectData;
import com.viaversion.viabackwards.api.entities.storage.WrappedMetadata;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.ObjectType;
@@ -36,6 +36,7 @@ import com.viaversion.viaversion.api.type.Types;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import org.checkerframework.checker.nullness.qual.Nullable;
public abstract class LegacyEntityRewriter<C extends ClientboundPacketType, T extends BackwardsProtocol<C, ?, ?, ?>> extends EntityRewriterBase<C, T> {
@@ -65,10 +66,8 @@ public abstract class LegacyEntityRewriter<C extends ClientboundPacketType, T ex
public void register() {
map(Types.INT);
handler(wrapper -> {
ClientWorld clientWorld = wrapper.user().getClientWorld(protocol.getClass());
if (clientWorld.setEnvironment(wrapper.get(Types.INT, 0))) {
tracker(wrapper.user()).clearEntities();
}
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
clientWorld.setEnvironment(wrapper.get(Types.INT, 0));
});
}
});
@@ -82,95 +81,102 @@ 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().getClientWorld(protocol.getClass());
clientWorld.setEnvironment(wrapper.get(Types.INT, 1));
final int entityId = wrapper.get(Types.INT, 0);
tracker(wrapper.user()).addEntity(entityId, playerType);
tracker(wrapper.user()).setClientEntityId(entityId);
ClientWorld clientChunks = wrapper.user().get(ClientWorld.class);
clientChunks.setEnvironment(wrapper.get(Types.INT, 1));
addTrackedEntity(wrapper, wrapper.get(Types.INT, 0), playerType);
});
}
});
}
protected PacketHandler getMobSpawnRewriter(Type<List<EntityData>> dataType, IdSetter idSetter) {
@Override
public void registerSetEntityData(C packetType, Type<List<EntityData>> oldMetaType, Type<List<EntityData>> newMetaType) {
protocol.registerClientbound(packetType, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // 0 - Entity ID
if (oldMetaType != null) {
map(oldMetaType, newMetaType);
} else {
map(newMetaType);
}
handler(wrapper -> {
List<EntityData> metadata = wrapper.get(newMetaType, 0);
handleEntityData(wrapper.get(Types.VAR_INT, 0), metadata, wrapper.user());
});
}
});
}
@Override
public void registerSetEntityData(C packetType, Type<List<EntityData>> metaType) {
registerSetEntityData(packetType, null, metaType);
}
protected PacketHandler getMobSpawnRewriter(Type<List<EntityData>> metaType, IdSetter idSetter) {
return wrapper -> {
int entityId = wrapper.get(Types.VAR_INT, 0);
EntityType type = tracker(wrapper.user()).entityType(entityId);
if (type == null) {
return;
}
List<EntityData> entityDataList = wrapper.get(dataType, 0);
handleEntityData(entityId, entityDataList, wrapper.user());
List<EntityData> metadata = wrapper.get(metaType, 0);
handleEntityData(entityId, metadata, wrapper.user());
EntityReplacement entityReplacement = entityDataForType(type);
if (entityReplacement != null) {
idSetter.setId(wrapper, entityReplacement.replacementId());
if (entityReplacement.hasBaseData()) {
entityReplacement.defaultData().createData(new WrappedEntityData(entityDataList));
if (entityReplacement.hasBaseMeta()) {
entityReplacement.defaultMeta().createMeta(new WrappedMetadata(metadata));
}
}
};
}
public PacketHandler getMobSpawnRewriter(Type<List<EntityData>> dataType) {
return getMobSpawnRewriter(dataType, (wrapper, id) -> wrapper.set(Types.UNSIGNED_BYTE, 0, (short) id));
public PacketHandler getMobSpawnRewriter(Type<List<EntityData>> metaType) {
return getMobSpawnRewriter(metaType, (wrapper, id) -> wrapper.set(Types.UNSIGNED_BYTE, 0, (short) id));
}
public PacketHandler getMobSpawnRewriter1_11(Type<List<EntityData>> dataType) {
return getMobSpawnRewriter(dataType, (wrapper, id) -> wrapper.set(Types.VAR_INT, 1, id));
public PacketHandler getMobSpawnRewriter1_11(Type<List<EntityData>> metaType) {
return getMobSpawnRewriter(metaType, (wrapper, id) -> wrapper.set(Types.VAR_INT, 1, id));
}
protected PacketHandler getObjectTrackerHandler() {
return wrapper -> {
int id = wrapper.get(Types.BYTE, 0);
int data = wrapper.get(Types.INT, 0);
EntityType type = objectTypeFromId(id, data);
if (type == null) {
return;
}
return wrapper -> addTrackedEntity(wrapper, wrapper.get(Types.VAR_INT, 0), objectTypeFromId(wrapper.get(Types.BYTE, 0)));
}
tracker(wrapper.user()).addEntity(wrapper.get(Types.VAR_INT, 0), type);
protected PacketHandler getTrackerAndMetaHandler(Type<List<EntityData>> metaType, EntityType entityType) {
return wrapper -> {
addTrackedEntity(wrapper, wrapper.get(Types.VAR_INT, 0), entityType);
List<EntityData> metadata = wrapper.get(metaType, 0);
handleEntityData(wrapper.get(Types.VAR_INT, 0), metadata, wrapper.user());
};
}
protected PacketHandler getTrackerAndDataHandler(Type<List<EntityData>> dataType, EntityType entityType) {
protected PacketHandler getObjectRewriter(Function<Byte, ObjectType> objectGetter) {
return wrapper -> {
tracker(wrapper.user()).addEntity(wrapper.get(Types.VAR_INT, 0), entityType);
List<EntityData> entityDataList = wrapper.get(dataType, 0);
handleEntityData(wrapper.get(Types.VAR_INT, 0), entityDataList, wrapper.user());
};
}
protected PacketHandler getObjectRewriter(ObjectTypeGetter objectGetter) {
return wrapper -> {
int id = wrapper.get(Types.BYTE, 0);
int data = wrapper.get(Types.INT, 0);
ObjectType type = objectGetter.get(id, data);
ObjectType type = objectGetter.apply(wrapper.get(Types.BYTE, 0));
if (type == null) {
protocol.getLogger().warning("Could not find Entity Type" + wrapper.get(Types.BYTE, 0));
return;
}
EntityReplacement replacement = getObjectData(type);
if (replacement != null) {
wrapper.set(Types.BYTE, 0, (byte) replacement.replacementId());
if (replacement.objectData() != -1) {
wrapper.set(Types.INT, 0, replacement.objectData());
EntityReplacement data = getObjectData(type);
if (data != null) {
wrapper.set(Types.BYTE, 0, (byte) data.replacementId());
if (data.objectData() != -1) {
wrapper.set(Types.INT, 0, data.objectData());
}
}
};
}
@Deprecated
protected void addTrackedEntity(PacketWrapper wrapper, int entityId, EntityType type) {
tracker(wrapper.user()).addEntity(entityId, type);
}
@FunctionalInterface
protected interface IdSetter {
void setId(PacketWrapper wrapper, int id);
}
@FunctionalInterface
protected interface ObjectTypeGetter {
ObjectType get(int id, int data);
}
}
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -17,47 +17,13 @@
*/
package com.viaversion.viabackwards.api.rewriters;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandler;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.rewriter.IdRewriteFunction;
public final class MapColorRewriter {
/**
* Rewrite map colors using the provided id rewriter.
*
* @param wrapper packet wrapper
* @param rewriter id rewriter returning mapped colors, or -1 if unmapped
* @param iconCount number of icons to read
*/
public static void rewriteMapColors(PacketWrapper wrapper, IdRewriteFunction rewriter, int iconCount) {
for (int i = 0; i < iconCount; i++) {
wrapper.passthrough(Types.VAR_INT); // Type
wrapper.passthrough(Types.BYTE); // X
wrapper.passthrough(Types.BYTE); // Z
wrapper.passthrough(Types.BYTE); // Direction
wrapper.passthrough(Types.OPTIONAL_COMPONENT); // Display Name
}
short columns = wrapper.passthrough(Types.UNSIGNED_BYTE);
if (columns < 1) {
return;
}
wrapper.passthrough(Types.UNSIGNED_BYTE); // Rows
wrapper.passthrough(Types.UNSIGNED_BYTE); // X
wrapper.passthrough(Types.UNSIGNED_BYTE); // Z
byte[] data = wrapper.passthrough(Types.BYTE_ARRAY_PRIMITIVE);
for (int i = 0; i < data.length; i++) {
int color = data[i] & 0xFF;
int mappedColor = rewriter.rewrite(color);
if (mappedColor != -1) {
data[i] = (byte) mappedColor;
}
}
}
/**
* Returns a packethandler to rewrite map data color ids. Reading starts from the icon count.
*
@@ -65,6 +31,30 @@ public final class MapColorRewriter {
* @return packethandler to rewrite map data color ids
*/
public static PacketHandler getRewriteHandler(IdRewriteFunction rewriter) {
return wrapper -> rewriteMapColors(wrapper, rewriter, wrapper.passthrough(Types.VAR_INT));
return wrapper -> {
int iconCount = wrapper.passthrough(Types.VAR_INT);
for (int i = 0; i < iconCount; i++) {
wrapper.passthrough(Types.VAR_INT); // Type
wrapper.passthrough(Types.BYTE); // X
wrapper.passthrough(Types.BYTE); // Z
wrapper.passthrough(Types.BYTE); // Direction
wrapper.passthrough(Types.OPTIONAL_COMPONENT); // Display Name
}
short columns = wrapper.passthrough(Types.UNSIGNED_BYTE);
if (columns < 1) return;
wrapper.passthrough(Types.UNSIGNED_BYTE); // Rows
wrapper.passthrough(Types.UNSIGNED_BYTE); // X
wrapper.passthrough(Types.UNSIGNED_BYTE); // Z
byte[] data = wrapper.passthrough(Types.BYTE_ARRAY_PRIMITIVE);
for (int i = 0; i < data.length; i++) {
int color = data[i] & 0xFF;
int mappedColor = rewriter.rewrite(color);
if (mappedColor != -1) {
data[i] = (byte) mappedColor;
}
}
};
}
}
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -17,41 +17,70 @@
*/
package com.viaversion.viabackwards.api.rewriters;
import com.viaversion.viaversion.api.data.Mappings;
import com.viaversion.viaversion.api.protocol.AbstractProtocol;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viaversion.api.minecraft.Holder;
import com.viaversion.viaversion.api.minecraft.SoundEvent;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandler;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
public class SoundRewriter<C extends ClientboundPacketType> extends com.viaversion.viaversion.rewriter.SoundRewriter<C> {
public SoundRewriter(final AbstractProtocol<C, ?, ?, ?> protocol) {
private final BackwardsProtocol<C, ?, ?, ?> protocol;
public SoundRewriter(final BackwardsProtocol<C, ?, ?, ?> protocol) {
super(protocol);
this.protocol = protocol;
}
public void registerNamedSound(final C packetType) {
if (protocol.getMappingData() == null || Mappings.isFullIdentity(protocol.getMappingData().getFullSoundMappings())) {
return;
}
protocol.registerClientbound(packetType, wrapper -> {
wrapper.passthrough(Types.STRING); // Sound identifier
getNamedSoundHandler().handle(wrapper);
protocol.registerClientbound(packetType, new PacketHandlers() {
@Override
public void register() {
map(Types.STRING); // Sound identifier
handler(getNamedSoundHandler());
}
});
}
public void registerStopSound(final C packetType) {
if (protocol.getMappingData() == null || Mappings.isFullIdentity(protocol.getMappingData().getFullSoundMappings())) {
return;
}
protocol.registerClientbound(packetType, wrapper -> {
protocol.registerClientbound(packetType, new PacketHandlers() {
@Override
public void register() {
handler(getStopSoundHandler());
}
});
}
public PacketHandler getNamedSoundHandler() {
return wrapper -> {
final String soundId = wrapper.get(Types.STRING, 0);
final String mappedId = protocol.getMappingData().getMappedNamedSound(soundId);
if (mappedId == null) {
return;
}
if (!mappedId.isEmpty()) {
wrapper.set(Types.STRING, 0, mappedId);
} else {
wrapper.cancel();
}
};
}
public PacketHandler getStopSoundHandler() {
return wrapper -> {
final byte flags = wrapper.passthrough(Types.BYTE);
if ((flags & 0x02) == 0) return; // No sound specified
if ((flags & 0x01) != 0) {
wrapper.passthrough(Types.VAR_INT); // Source
}
if ((flags & 0x02) == 0) return; // No sound specified
final String soundId = wrapper.read(Types.STRING);
final String mappedId = protocol.getMappingData().getFullSoundMappings().mappedIdentifier(soundId);
final String mappedId = protocol.getMappingData().getMappedNamedSound(soundId);
if (mappedId == null) {
// No mapping found
wrapper.write(Types.STRING, soundId);
@@ -64,22 +93,45 @@ public class SoundRewriter<C extends ClientboundPacketType> extends com.viaversi
// Cancel if set to empty
wrapper.cancel();
}
});
};
}
public PacketHandler getNamedSoundHandler() {
@Override
public void registerSound1_19_3(final C packetType) {
protocol.registerClientbound(packetType, getSoundHandler1_19_3());
}
public PacketHandler getSoundHandler1_19_3() {
return wrapper -> {
final String soundId = wrapper.get(Types.STRING, 0);
final String mappedId = protocol.getMappingData().getFullSoundMappings().mappedIdentifier(soundId);
if (mappedId == null) {
Holder<SoundEvent> soundEventHolder = wrapper.read(Types.SOUND_EVENT);
if (soundEventHolder.isDirect()) {
wrapper.write(Types.SOUND_EVENT, rewriteSoundEvent(wrapper, soundEventHolder));
return;
}
if (!mappedId.isEmpty()) {
wrapper.set(Types.STRING, 0, mappedId);
} else {
final int mappedId = idRewriter.rewrite(soundEventHolder.id());
if (mappedId == -1) {
wrapper.cancel();
return;
}
if (mappedId != soundEventHolder.id()) {
soundEventHolder = Holder.of(mappedId);
}
wrapper.write(Types.SOUND_EVENT, soundEventHolder);
};
}
public Holder<SoundEvent> rewriteSoundEvent(final PacketWrapper wrapper, final Holder<SoundEvent> soundEventHolder) {
final SoundEvent soundEvent = soundEventHolder.value();
final String mappedIdentifier = protocol.getMappingData().getMappedNamedSound(soundEvent.identifier());
if (mappedIdentifier != null) {
if (!mappedIdentifier.isEmpty()) {
return Holder.of(soundEvent.withIdentifier(mappedIdentifier));
}
wrapper.cancel();
}
return soundEventHolder;
}
}
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -17,150 +17,132 @@
*/
package com.viaversion.viabackwards.api.rewriters;
import com.viaversion.nbt.tag.ByteTag;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.NumberTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viabackwards.api.data.BackwardsMappingData;
import com.viaversion.viabackwards.utils.ChatUtil;
import com.viaversion.viaversion.api.data.Mappings;
import com.viaversion.viaversion.api.minecraft.data.StructuredData;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataContainer;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.minecraft.item.data.Enchantments;
import com.viaversion.viaversion.libs.fastutil.ints.Int2IntMap;
import com.viaversion.viaversion.libs.fastutil.ints.IntIntPair;
import com.viaversion.viaversion.libs.fastutil.objects.ObjectIterator;
import com.viaversion.viaversion.rewriter.IdRewriteFunction;
import com.viaversion.nbt.tag.ByteTag;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.NumberTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.util.ComponentUtil;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static com.viaversion.viabackwards.api.rewriters.EnchantmentRewriter.ENCHANTMENT_LEVEL_TRANSLATION;
public class StructuredEnchantmentRewriter {
protected final BackwardsStructuredItemRewriter<?, ?, ?> itemRewriter;
protected final BackwardsItemRewriter<?, ?, ?> itemRewriter;
private boolean rewriteIds = true;
public StructuredEnchantmentRewriter(final BackwardsStructuredItemRewriter<?, ?, ?> itemRewriter) {
public StructuredEnchantmentRewriter(final BackwardsItemRewriter<?, ?, ?> itemRewriter) {
this.itemRewriter = itemRewriter;
}
public void handleToClient(final Item item) {
final StructuredDataContainer data = item.dataContainer();
final BackwardsMappingData mappingData = itemRewriter.protocol().getMappingData();
final IdRewriteFunction idRewriteFunction = id -> {
final Mappings mappings = mappingData.getEnchantmentMappings();
return mappings.getNewId(id);
};
final DescriptionSupplier descriptionSupplier = (id, level) -> {
final String remappedName = mappingData.mappedEnchantmentName(id);
return ComponentUtil.jsonStringToTag(ChatUtil.legacyToJsonString("§7" + remappedName, ENCHANTMENT_LEVEL_TRANSLATION.formatted(level), true));
};
rewriteEnchantmentsToClient(data, StructuredDataKey.ENCHANTMENTS1_20_5, idRewriteFunction, descriptionSupplier, false);
rewriteEnchantmentsToClient(data, StructuredDataKey.STORED_ENCHANTMENTS1_20_5, idRewriteFunction, descriptionSupplier, true);
rewriteEnchantmentsToClient(data, StructuredDataKey.ENCHANTMENTS, false);
rewriteEnchantmentsToClient(data, StructuredDataKey.STORED_ENCHANTMENTS, true);
}
public void handleToServer(final Item item) {
final StructuredDataContainer data = item.dataContainer();
final CompoundTag customData = data.get(StructuredDataKey.CUSTOM_DATA);
if (customData != null) {
rewriteEnchantmentsToServer(data, customData, StructuredDataKey.ENCHANTMENTS1_20_5);
rewriteEnchantmentsToServer(data, customData, StructuredDataKey.STORED_ENCHANTMENTS1_20_5);
}
}
public void rewriteEnchantmentsToClient(final StructuredDataContainer data, final StructuredDataKey<Enchantments> key, final IdRewriteFunction rewriteFunction, final DescriptionSupplier descriptionSupplier, final boolean storedEnchant) {
final Enchantments enchantments = data.get(key);
if (enchantments == null || enchantments.size() == 0) {
final StructuredData<CompoundTag> customData = data.getNonEmpty(StructuredDataKey.CUSTOM_DATA);
if (customData == null) {
return;
}
final CompoundTag tag = customData.value();
if (tag.contains(itemRewriter.nbtTagName("enchantments"))) {
rewriteEnchantmentsToServer(data, tag, StructuredDataKey.ENCHANTMENTS, false);
}
if (tag.contains(itemRewriter.nbtTagName("stored_enchantments"))) {
rewriteEnchantmentsToServer(data, tag, StructuredDataKey.STORED_ENCHANTMENTS, true);
}
}
public void rewriteEnchantmentsToClient(final StructuredDataContainer data, final StructuredDataKey<Enchantments> key, final boolean storedEnchant) {
final StructuredData<Enchantments> enchantmentsData = data.getNonEmpty(key);
if (enchantmentsData == null) {
return;
}
final CompoundTag tag = data.computeIfAbsent(StructuredDataKey.CUSTOM_DATA, $ -> new CompoundTag()).value();
final Enchantments enchantments = enchantmentsData.value();
final List<Tag> loreToAdd = new ArrayList<>();
boolean removedEnchantments = false;
boolean updatedLore = false;
boolean changed = false;
final ObjectIterator<Int2IntMap.Entry> iterator = enchantments.enchantments().int2IntEntrySet().iterator();
final List<PendingIdChange> updatedIds = new ArrayList<>();
final List<IntIntPair> updatedIds = new ArrayList<>();
while (iterator.hasNext()) {
final Int2IntMap.Entry entry = iterator.next();
final int id = entry.getIntKey();
final int mappedId = rewriteFunction.rewrite(id);
final int level = entry.getIntValue();
final BackwardsMappingData mappingData = itemRewriter.protocol().getMappingData();
final Mappings mappings = mappingData.getEnchantmentMappings();
final int mappedId = mappings.getNewId(entry.getIntKey());
if (mappedId != -1) {
if (rewriteIds) {
// Update the map after to iteration to preserve the current ids before possibly saving the original, avoid CME
updatedIds.add(new PendingIdChange(id, mappedId, level));
updatedIds.add(IntIntPair.of(entry.getIntKey(), mappedId));
}
continue;
}
if (!removedEnchantments) {
// Backup original before doing modifications
final CompoundTag customData = customData(data);
itemRewriter.saveListTag(customData, asTag(enchantments), key.identifier());
removedEnchantments = true;
}
final Tag description = descriptionSupplier.get(id, level);
if (description != null && enchantments.showInTooltip()) {
loreToAdd.add(description);
updatedLore = true;
}
iterator.remove();
}
// Remove all first, then add the new ones
for (final PendingIdChange change : updatedIds) {
enchantments.remove(change.id());
}
for (final PendingIdChange change : updatedIds) {
enchantments.add(change.mappedId(), change.level());
}
if (removedEnchantments) {
final CompoundTag tag = customData(data);
if (!storedEnchant && enchantments.size() == 0) {
// Add glint override if there are no enchantments left
final Boolean glintOverride = data.get(StructuredDataKey.ENCHANTMENT_GLINT_OVERRIDE);
if (glintOverride != null) {
tag.putBoolean(itemRewriter.nbtTagName("glint"), glintOverride);
} else {
tag.putBoolean(itemRewriter.nbtTagName("noglint"), true);
final String remappedName = mappingData.mappedEnchantmentName(entry.getIntKey());
if (remappedName != null) {
if (!changed) {
// Backup original before doing modifications
itemRewriter.saveListTag(tag, asTag(enchantments), key.identifier());
changed = true;
}
data.set(StructuredDataKey.ENCHANTMENT_GLINT_OVERRIDE, true);
}
if (enchantments.showInTooltip()) {
tag.putBoolean(itemRewriter.nbtTagName("show_" + key.identifier()), true);
final int level = entry.getIntValue();
loreToAdd.add(ComponentUtil.jsonStringToTag(ComponentUtil.legacyToJsonString("§7" + remappedName + " " + EnchantmentRewriter.getRomanNumber(level), true)));
iterator.remove();
}
}
if (updatedLore) {
// Save original lore
final CompoundTag tag = customData(data);
final Tag[] lore = data.get(StructuredDataKey.LORE);
if (lore != null) {
final List<Tag> loreList = Arrays.asList(lore);
itemRewriter.saveGenericTagList(tag, loreList, "lore");
loreToAdd.addAll(loreList);
for (final IntIntPair pair : updatedIds) {
enchantments.add(pair.firstInt(), pair.secondInt());
}
if (loreToAdd.isEmpty()) {
// No removed enchantments
return;
}
// Add glint override if there are no enchantments left
if (!storedEnchant && enchantments.size() == 0) {
final StructuredData<Boolean> glintOverride = data.getNonEmpty(StructuredDataKey.ENCHANTMENT_GLINT_OVERRIDE);
if (glintOverride != null) {
tag.putBoolean(itemRewriter.nbtTagName("glint"), glintOverride.value());
} else {
tag.putBoolean(itemRewriter.nbtTagName("nolore"), true);
tag.putBoolean(itemRewriter.nbtTagName("noglint"), true);
}
data.set(StructuredDataKey.LORE, loreToAdd.toArray(new Tag[0]));
data.set(StructuredDataKey.ENCHANTMENT_GLINT_OVERRIDE, true);
}
}
private CompoundTag customData(final StructuredDataContainer data) {
CompoundTag tag = data.get(StructuredDataKey.CUSTOM_DATA);
if (tag == null) {
tag = new CompoundTag();
data.set(StructuredDataKey.CUSTOM_DATA, tag);
// Save original lore
final StructuredData<Tag[]> loreData = data.getNonEmpty(StructuredDataKey.LORE);
if (loreData != null) {
final List<Tag> loreList = Arrays.asList(loreData.value());
itemRewriter.saveGenericTagList(tag, loreList, "lore");
loreToAdd.addAll(loreList);
} else {
tag.putBoolean(itemRewriter.nbtTagName("nolore"), true);
}
return tag;
if (enchantments.showInTooltip()) {
tag.putBoolean(itemRewriter.nbtTagName("show_" + key.identifier()), true);
}
data.set(StructuredDataKey.LORE, loreToAdd.toArray(new Tag[0]));
}
private ListTag<CompoundTag> asTag(final Enchantments enchantments) {
@@ -174,7 +156,7 @@ public class StructuredEnchantmentRewriter {
return listTag;
}
public void rewriteEnchantmentsToServer(final StructuredDataContainer data, final CompoundTag tag, final StructuredDataKey<Enchantments> key) {
public void rewriteEnchantmentsToServer(final StructuredDataContainer data, final CompoundTag tag, final StructuredDataKey<Enchantments> key, final boolean storedEnchant) {
final ListTag<CompoundTag> enchantmentsTag = itemRewriter.removeListTag(tag, key.identifier(), CompoundTag.class);
if (enchantmentsTag == null) {
return;
@@ -204,13 +186,4 @@ public class StructuredEnchantmentRewriter {
public void setRewriteIds(final boolean rewriteIds) {
this.rewriteIds = rewriteIds;
}
@FunctionalInterface
public interface DescriptionSupplier {
Tag get(int id, int level);
}
private record PendingIdChange(int id, int mappedId, int level) {
}
}
@@ -0,0 +1,93 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2024 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.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.data.BackwardsMappingDataLoader;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.libs.gson.JsonObject;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viaversion.rewriter.ComponentRewriter;
import java.util.HashMap;
import java.util.Map;
import org.checkerframework.checker.nullness.qual.Nullable;
public class TranslatableRewriter<C extends ClientboundPacketType> extends ComponentRewriter<C> {
private static final Map<String, Map<String, String>> TRANSLATABLES = new HashMap<>();
private final Map<String, String> translatables;
public static void loadTranslatables() {
if (!TRANSLATABLES.isEmpty()) {
throw new IllegalStateException("Translatables already loaded!");
}
fillTranslatables(BackwardsMappingDataLoader.INSTANCE.loadFromDataDir("translation-mappings.json"), TRANSLATABLES);
}
public static void fillTranslatables(final JsonObject jsonObject, final Map<String, Map<String, String>> translatables) {
for (final Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
final Map<String, String> versionMappings = new HashMap<>();
translatables.put(entry.getKey(), versionMappings);
for (final Map.Entry<String, JsonElement> translationEntry : entry.getValue().getAsJsonObject().entrySet()) {
versionMappings.put(translationEntry.getKey(), translationEntry.getValue().getAsString());
}
}
}
public TranslatableRewriter(final BackwardsProtocol<C, ?, ?, ?> protocol, final ReadType type) {
this(protocol, type, protocol.getClass().getSimpleName().replace("Protocol", "").split("To")[0].replace("_", "."));
}
public TranslatableRewriter(final BackwardsProtocol<C, ?, ?, ?> protocol, final ReadType type, final String sectionIdentifier) {
super(protocol, type);
final Map<String, String> translatableMappings = getTranslatableMappings(sectionIdentifier);
if (translatableMappings == null) {
protocol.getLogger().warning("Missing " + sectionIdentifier + " translatables!");
this.translatables = new HashMap<>();
} else {
this.translatables = translatableMappings;
}
}
@Override
protected void handleTranslate(final JsonObject root, final String translate) {
final String newTranslate = mappedTranslationKey(translate);
if (newTranslate != null) {
root.addProperty("translate", newTranslate);
}
}
@Override
protected void handleTranslate(final UserConnection connection, final CompoundTag parentTag, final StringTag translateTag) {
final String newTranslate = mappedTranslationKey(translateTag.getValue());
if (newTranslate != null) {
parentTag.put("translate", new StringTag(newTranslate));
}
}
public @Nullable String mappedTranslationKey(final String translationKey) {
return translatables.get(translationKey);
}
public Map<String, String> getTranslatableMappings(final String sectionIdentifier) {
return TRANSLATABLES.get(sectionIdentifier);
}
}
@@ -1,64 +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.text;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.data.TranslatableMappings;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.libs.gson.JsonObject;
import java.util.Map;
import org.checkerframework.checker.nullness.qual.Nullable;
public class JsonNBTComponentRewriter<C extends ClientboundPacketType> extends com.viaversion.viaversion.rewriter.text.JsonNBTComponentRewriter<C> implements TranslatableRewriter {
private final Map<String, String> translatables;
public JsonNBTComponentRewriter(final BackwardsProtocol<C, ?, ?, ?> protocol, final ReadType type) {
super(protocol, type);
this.translatables = TranslatableMappings.translatablesFor(protocol);
}
public JsonNBTComponentRewriter(final BackwardsProtocol<C, ?, ?, ?> protocol, final ReadType type, final String version) {
super(protocol, type);
this.translatables = TranslatableMappings.translatablesFor(version);
}
@Override
protected void handleTranslate(final JsonObject root, final String translate) {
final String newTranslate = mappedTranslationKey(translate);
if (newTranslate != null) {
root.addProperty("translate", newTranslate);
}
}
@Override
protected void handleTranslate(final UserConnection connection, final CompoundTag parentTag, final StringTag translateTag) {
final String newTranslate = mappedTranslationKey(translateTag.getValue());
if (newTranslate != null) {
parentTag.put("translate", new StringTag(newTranslate));
}
}
@Override
public @Nullable String mappedTranslationKey(final String translationKey) {
return translatables.get(translationKey);
}
}
@@ -1,64 +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.text;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.data.TranslatableMappings;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.libs.gson.JsonObject;
import java.util.Map;
import org.checkerframework.checker.nullness.qual.Nullable;
public class NBTComponentRewriter<C extends ClientboundPacketType> extends com.viaversion.viaversion.rewriter.text.NBTComponentRewriter<C> implements TranslatableRewriter {
private final Map<String, String> translatables;
public NBTComponentRewriter(final BackwardsProtocol<C, ?, ?, ?> protocol) {
super(protocol);
this.translatables = TranslatableMappings.translatablesFor(protocol);
}
public NBTComponentRewriter(final BackwardsProtocol<C, ?, ?, ?> protocol, final String version) {
super(protocol);
this.translatables = TranslatableMappings.translatablesFor(version);
}
@Override
protected void handleTranslate(final JsonObject root, final String translate) {
final String newTranslate = mappedTranslationKey(translate);
if (newTranslate != null) {
root.addProperty("translate", newTranslate);
}
}
@Override
protected void handleTranslate(final UserConnection connection, final CompoundTag parentTag, final StringTag translateTag) {
final String newTranslate = mappedTranslationKey(translateTag.getValue());
if (newTranslate != null) {
parentTag.put("translate", new StringTag(newTranslate));
}
}
@Override
public @Nullable String mappedTranslationKey(final String translationKey) {
return translatables.get(translationKey);
}
}
@@ -1,27 +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.text;
import com.viaversion.viaversion.api.rewriter.ComponentRewriter;
import org.checkerframework.checker.nullness.qual.Nullable;
public interface TranslatableRewriter extends ComponentRewriter {
@Nullable
String mappedTranslationKey(String translationKey);
}
@@ -1,103 +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.item;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viaversion.api.minecraft.item.DataItem;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.libs.gson.JsonParser;
import com.viaversion.viaversion.libs.gson.JsonPrimitive;
import com.viaversion.viaversion.libs.gson.JsonSyntaxException;
import java.util.ArrayList;
import java.util.List;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Prevent expensive parsing/toString by checking against cached JsonElement instances, used from 1.14 to 1.20.5.
* <p>
* When using this, be careful not to break caching by modifying the display tag directly.
*/
public final class DataItemWithExtras extends DataItem {
private JsonElement name;
private List<JsonElement> lore;
public DataItemWithExtras(final Item from) {
setIdentifier(from.identifier());
setAmount(from.amount());
setData(from.data());
setTag(from.tag());
if (tag() == null) {
return;
}
final CompoundTag display = tag().getCompoundTag("display");
if (display == null) {
return;
}
final StringTag name = display.getStringTag("Name");
if (name != null) {
this.name = parse(name.getValue());
}
final ListTag<StringTag> lore = display.getListTag("Lore", StringTag.class);
if (lore != null) {
this.lore = new ArrayList<>(lore.size());
for (int i = 0; i < lore.size(); i++) {
this.lore.add(parse(lore.get(i).getValue()));
}
}
}
public @Nullable JsonElement name() {
return name;
}
public @Nullable StringTag rawName() {
if (tag() == null) {
return null;
}
final CompoundTag display = tag().getCompoundTag("display");
return display != null ? display.getStringTag("Name") : null;
}
public @Nullable List<JsonElement> lore() {
return lore;
}
public @Nullable ListTag<StringTag> rawLore() {
if (tag() == null) {
return null;
}
final CompoundTag display = tag().getCompoundTag("display");
return display != null ? display.getListTag("Lore", StringTag.class) : null;
}
private JsonElement parse(final String value) {
try {
return JsonParser.parseString(value);
} catch (final JsonSyntaxException e) {
return new JsonPrimitive(value);
}
}
}
@@ -1,38 +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.registration;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import com.viaversion.viaversion.protocol.shared_registration.SharedRegistrations;
public final class BackwardsRegistrations {
private static final SharedRegistrations REGISTRATIONS = SharedRegistrations.create();
public static void apply() {
REGISTRATIONS.registrations()
.range(ProtocolVersion.v1_10, ProtocolVersion.v1_19_3, RegistryRegistrations::registerNamedSound1_10)
.since(ProtocolVersion.v1_14, RegistryRegistrations::registerStopSound1_14)
.register();
}
public static SharedRegistrations registrations() {
return REGISTRATIONS;
}
}
@@ -1,36 +0,0 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* 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.registration;
import com.viaversion.viabackwards.api.rewriters.SoundRewriter;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.protocol.shared_registration.PacketBound;
import com.viaversion.viaversion.protocol.shared_registration.RegistrationContext;
import com.viaversion.viaversion.protocols.v1_13_2to1_14.packet.ClientboundPackets1_14;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ClientboundPackets1_9_3;
final class RegistryRegistrations {
static <CU extends ClientboundPacketType> void registerNamedSound1_10(final RegistrationContext<CU, ?> ctx) {
ctx.clientbound(ClientboundPackets1_9_3.CUSTOM_SOUND, new SoundRewriter<>(ctx.protocol())::registerNamedSound, PacketBound.REMOVED_AT_MAX);
}
static <CU extends ClientboundPacketType> void registerStopSound1_14(final RegistrationContext<CU, ?> ctx) {
ctx.clientbound(ClientboundPackets1_14.STOP_SOUND, new SoundRewriter<>(ctx.protocol())::registerStopSound);
}
}
@@ -1,64 +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.template;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viabackwards.api.rewriters.BackwardsStructuredItemRewriter;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataContainer;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.protocols.v1_21_11to26_1.packet.ClientboundPacket26_1;
import com.viaversion.viaversion.protocols.v1_21_7to1_21_9.packet.ServerboundPacket1_21_9;
// To replace if needed:
// ChunkType1_21_5
// RecipeDisplayRewriter
final class BlockItemPacketRewriter99_1 extends BackwardsStructuredItemRewriter<ClientboundPacket26_1, ServerboundPacket1_21_9, Protocol99_1To98_1> {
public BlockItemPacketRewriter99_1(final Protocol99_1To98_1 protocol) {
super(protocol);
}
@Override
public void registerPackets() {
}
@Override
protected void handleItemDataComponentsToClient(final UserConnection connection, final Item item, final StructuredDataContainer container) {
super.handleItemDataComponentsToClient(connection, item, container);
// downgradeData(item, container); // static import VV method
}
@Override
protected void handleItemDataComponentsToServer(final UserConnection connection, final Item item, final StructuredDataContainer container) {
super.handleItemDataComponentsToServer(connection, item, container);
// upgradeData(item, container); // static import VV method
}
@Override
protected void restoreBackupData(final Item item, final StructuredDataContainer container, final CompoundTag customData) {
super.restoreBackupData(item, container, customData);
// restore any data if needed here
}
@Override
protected void backupInconvertibleData(final UserConnection connection, final Item item, final StructuredDataContainer dataContainer, final CompoundTag backupTag) {
super.backupInconvertibleData(connection, item, dataContainer, backupTag);
// back up any data if needed here, called before the method below
}
}
@@ -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.template;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.rewriters.text.NBTComponentRewriter;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.protocols.v1_21_11to26_1.packet.ClientboundPacket26_1;
final class ComponentRewriter99_1 extends NBTComponentRewriter<ClientboundPacket26_1> {
public ComponentRewriter99_1(final BackwardsProtocol<ClientboundPacket26_1, ?, ?, ?> protocol) {
super(protocol);
}
@Override
protected void handleShowItem(final UserConnection connection, final CompoundTag itemTag, final CompoundTag componentsTag) {
super.handleShowItem(connection, itemTag, componentsTag);
if (componentsTag == null) {
return;
}
// Remove or update data from componentsTag
// Newly added data which is not handled otherwise needs to be removed to prevent errors on the client
}
}
@@ -1,75 +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.template;
import com.viaversion.viabackwards.api.rewriters.EntityRewriter;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_21_11;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes26_1;
import com.viaversion.viaversion.api.type.types.version.VersionedTypes;
import com.viaversion.viaversion.protocols.v1_21_11to26_1.packet.ClientboundPacket26_1;
// Replace if needed
// VersionedTypes
final class EntityPacketRewriter99_1 extends EntityRewriter<ClientboundPacket26_1, Protocol99_1To98_1> {
private static final EntityDataTypes26_1 MAPPED_DATA_TYPES = VersionedTypes.V26_1.entityDataTypes;
public EntityPacketRewriter99_1(final Protocol99_1To98_1 protocol) {
super(protocol, MAPPED_DATA_TYPES.optionalComponentType, MAPPED_DATA_TYPES.booleanType);
}
@Override
public void registerPackets() {
}
@Override
protected void registerRewrites() {
dataTypeMapper().register();
/* ... or like this for additions and removals that are not at the very end
dataTypeMapper()
.added(MAPPED_DATA_TYPES.catSoundVariant)
.removed(MAPPED_DATA_TYPES.cowSoundVariant)
.skip(MAPPED_DATA_TYPES.pigSoundVariant) // if neither removed nor added, but the value type has to be changed separately
.register();*/
registerEntityDataTypeHandler1_20_3(
MAPPED_DATA_TYPES.itemType,
MAPPED_DATA_TYPES.blockStateType,
MAPPED_DATA_TYPES.optionalBlockStateType,
MAPPED_DATA_TYPES.particleType,
MAPPED_DATA_TYPES.particlesType,
MAPPED_DATA_TYPES.componentType,
MAPPED_DATA_TYPES.optionalComponentType
);
// Remove entity data of new entity type
// filter().type(EntityTypes1_21_11.SNIFFER).removeIndex(newIndex);
}
@Override
public void onMappingDataLoaded() {
super.onMappingDataLoaded();
// mapEntityTypeWithData(EntityTypes1_21_11.SNIFFER, EntityTypes1_21_11.RAVAGER).tagName();
}
@Override
public EntityType typeFromId(final int type) {
return EntityTypes1_21_11.getTypeFromId(type);
}
}
@@ -1,150 +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.template;
import com.viaversion.viabackwards.api.BackwardsProtocol;
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.rewriter.BlockRewriter;
import com.viaversion.viaversion.rewriter.ParticleRewriter;
import com.viaversion.viaversion.rewriter.RecipeDisplayRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
import com.viaversion.viaversion.rewriter.block.BlockRewriter1_21_5;
import static com.viaversion.viaversion.util.ProtocolUtil.packetTypeMap;
// Placeholders to replace (in the entire package):
// Protocol1_21_11To26_1 (the ViaVersion protocol class the mappings depend on)
// ClientboundPacket26_1
// ServerboundPacket1_21_9
// ClientboundConfigurationPackets1_21
// ServerboundConfigurationPackets1_20_5
// EntityTypes1_21_11 (UNMAPPED type)
// VersionedTypes.V26_1
// 99.1, 98.1
final class Protocol99_1To98_1 extends BackwardsProtocol<ClientboundPacket26_1, ClientboundPacket26_1, ServerboundPacket1_21_9, ServerboundPacket1_21_9> {
// ViaBackwards uses its own mappings and also needs a translatablerewriter for translation mappings
public static final BackwardsMappingData MAPPINGS = new BackwardsMappingData("99.1", "98.1", Protocol1_21_11To26_1.class); // Change the VV (!) protocol class
private final EntityPacketRewriter99_1 entityRewriter = new EntityPacketRewriter99_1(this);
private final BlockItemPacketRewriter99_1 itemRewriter = new BlockItemPacketRewriter99_1(this);
private final ParticleRewriter<ClientboundPacket26_1> particleRewriter = new ParticleRewriter<>(this);
private final NBTComponentRewriter<ClientboundPacket26_1> translatableRewriter = new ComponentRewriter99_1(this);
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 RecipeDisplayRewriter1_21_5<>(this);
public Protocol99_1To98_1() {
super(ClientboundPacket26_1.class, ClientboundPacket26_1.class, ServerboundPacket1_21_9.class, ServerboundPacket1_21_9.class);
}
@Override
protected void registerPackets() {
super.registerPackets();
}
@Override
public void init(final UserConnection connection) {
addEntityTracker(connection, new EntityTrackerBase(connection, EntityTypes1_21_11.PLAYER));
connection.addItemHasher(this.getClass(), new ItemHasherBase(this, connection));
}
@Override
public BackwardsMappingData getMappingData() {
return MAPPINGS;
}
@Override
public EntityPacketRewriter99_1 getEntityRewriter() {
return entityRewriter;
}
@Override
public BlockItemPacketRewriter99_1 getItemRewriter() {
return itemRewriter;
}
@Override
public BlockRewriter<ClientboundPacket26_1> getBlockRewriter() {
return blockRewriter;
}
@Override
public RecipeDisplayRewriter<ClientboundPacket26_1> getRecipeRewriter() {
return recipeRewriter;
}
@Override
public BackwardsRegistryRewriter getRegistryDataRewriter() {
return registryDataRewriter;
}
@Override
public ParticleRewriter<ClientboundPacket26_1> getParticleRewriter() {
return particleRewriter;
}
@Override
public NBTComponentRewriter<ClientboundPacket26_1> getComponentRewriter() {
return translatableRewriter;
}
@Override
public TagRewriter<ClientboundPacket26_1> getTagRewriter() {
return tagRewriter;
}
@Override
public VersionedTypesHolder types() {
return VersionedTypes.V26_1;
}
@Override
public VersionedTypesHolder mappedTypes() {
return VersionedTypes.V26_1;
}
@Override
protected PacketTypesProvider<ClientboundPacket26_1, ClientboundPacket26_1, ServerboundPacket1_21_9, ServerboundPacket1_21_9> createPacketTypesProvider() {
return new SimplePacketTypesProvider<>(
packetTypeMap(unmappedClientboundPacketType, ClientboundPackets26_1.class, ClientboundConfigurationPackets1_21_9.class),
packetTypeMap(mappedClientboundPacketType, ClientboundPackets26_1.class, ClientboundConfigurationPackets1_21_9.class),
packetTypeMap(mappedServerboundPacketType, ServerboundPackets1_21_6.class, ServerboundConfigurationPackets1_21_9.class),
packetTypeMap(unmappedServerboundPacketType, ServerboundPackets1_21_6.class, ServerboundConfigurationPackets1_21_9.class)
);
}
}
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -21,7 +21,7 @@ package com.viaversion.viabackwards.protocol.v1_10to1_9_3;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.data.BackwardsMappingData;
import com.viaversion.viabackwards.api.rewriters.SoundRewriter;
import com.viaversion.viabackwards.api.rewriters.text.JsonNBTComponentRewriter;
import com.viaversion.viabackwards.api.rewriters.TranslatableRewriter;
import com.viaversion.viabackwards.protocol.v1_10to1_9_3.rewriter.BlockItemPacketRewriter1_10;
import com.viaversion.viabackwards.protocol.v1_10to1_9_3.rewriter.EntityPacketRewriter1_10;
import com.viaversion.viaversion.api.connection.UserConnection;
@@ -34,7 +34,7 @@ import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.data.entity.EntityTrackerBase;
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.rewriter.text.ComponentRewriterBase;
import com.viaversion.viaversion.rewriter.ComponentRewriter;
public class Protocol1_10To1_9_3 extends BackwardsProtocol<ClientboundPackets1_9_3, ClientboundPackets1_9_3, ServerboundPackets1_9_3, ServerboundPackets1_9_3> {
@@ -57,7 +57,7 @@ public class Protocol1_10To1_9_3 extends BackwardsProtocol<ClientboundPackets1_9
itemRewriter.register();
SoundRewriter<ClientboundPackets1_9_3> soundRewriter = new SoundRewriter<>(this);
replaceClientbound(ClientboundPackets1_9_3.CUSTOM_SOUND, new PacketHandlers() {
registerClientbound(ClientboundPackets1_9_3.CUSTOM_SOUND, new PacketHandlers() {
@Override
public void register() {
map(Types.STRING); // 0 - Sound name
@@ -70,7 +70,7 @@ public class Protocol1_10To1_9_3 extends BackwardsProtocol<ClientboundPackets1_9
handler(soundRewriter.getNamedSoundHandler());
}
});
replaceClientbound(ClientboundPackets1_9_3.SOUND, new PacketHandlers() {
registerClientbound(ClientboundPackets1_9_3.SOUND, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // 0 - Sound name
@@ -92,14 +92,17 @@ public class Protocol1_10To1_9_3 extends BackwardsProtocol<ClientboundPackets1_9
}
});
JsonNBTComponentRewriter<ClientboundPackets1_9_3> componentRewriter = new JsonNBTComponentRewriter<>(this, ComponentRewriterBase.ReadType.JSON);
TranslatableRewriter<ClientboundPackets1_9_3> componentRewriter = new TranslatableRewriter<>(this, ComponentRewriter.ReadType.JSON);
componentRewriter.registerComponentPacket(ClientboundPackets1_9_3.CHAT);
}
@Override
public void init(UserConnection user) {
if (!user.has(ClientWorld.class)) {
user.put(new ClientWorld());
}
user.addEntityTracker(this.getClass(), new EntityTrackerBase(user, EntityTypes1_10.EntityType.PLAYER));
user.addClientWorld(this.getClass(), new ClientWorld());
}
@Override
@@ -116,4 +119,9 @@ public class Protocol1_10To1_9_3 extends BackwardsProtocol<ClientboundPackets1_9
public BlockItemPacketRewriter1_10 getItemRewriter() {
return itemRewriter;
}
@Override
public boolean hasMappingDataToLoad() {
return true;
}
}
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -20,10 +20,12 @@ package com.viaversion.viabackwards.protocol.v1_10to1_9_3.rewriter;
import com.viaversion.viabackwards.api.rewriters.LegacyBlockItemRewriter;
import com.viaversion.viabackwards.protocol.v1_10to1_9_3.Protocol1_10To1_9_3;
import com.viaversion.viaversion.api.minecraft.BlockChangeRecord;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_9_3;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ClientboundPackets1_9_3;
@@ -44,13 +46,40 @@ public class BlockItemPacketRewriter1_10 extends LegacyBlockItemRewriter<Clientb
registerSetContent(ClientboundPackets1_9_3.CONTAINER_SET_CONTENT);
registerSetEquippedItem(ClientboundPackets1_9_3.SET_EQUIPPED_ITEM);
registerCustomPayloadTradeList(ClientboundPackets1_9_3.CUSTOM_PAYLOAD);
protocol.registerClientbound(ClientboundPackets1_9_3.CUSTOM_PAYLOAD, new PacketHandlers() {
@Override
public void register() {
map(Types.STRING); // 0 - Channel
handler(wrapper -> {
if (wrapper.get(Types.STRING, 0).equals("MC|TrList")) {
wrapper.passthrough(Types.INT); // Passthrough Window ID
int size = wrapper.passthrough(Types.UNSIGNED_BYTE);
for (int i = 0; i < size; i++) {
wrapper.write(Types.ITEM1_8, handleItemToClient(wrapper.user(), wrapper.read(Types.ITEM1_8))); // Input Item
wrapper.write(Types.ITEM1_8, handleItemToClient(wrapper.user(), wrapper.read(Types.ITEM1_8))); // Output Item
boolean secondItem = wrapper.passthrough(Types.BOOLEAN); // Has second item
if (secondItem) {
wrapper.write(Types.ITEM1_8, handleItemToClient(wrapper.user(), wrapper.read(Types.ITEM1_8))); // Second Item
}
wrapper.passthrough(Types.BOOLEAN); // Trade disabled
wrapper.passthrough(Types.INT); // Number of tools uses
wrapper.passthrough(Types.INT); // Maximum number of trade uses
}
}
});
}
});
registerContainerClick(ServerboundPackets1_9_3.CONTAINER_CLICK);
registerSetCreativeModeSlot(ServerboundPackets1_9_3.SET_CREATIVE_MODE_SLOT);
protocol.registerClientbound(ClientboundPackets1_9_3.LEVEL_CHUNK, wrapper -> {
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_10To1_9_3.class);
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
ChunkType1_9_3 type = ChunkType1_9_3.forEnvironment(clientWorld.getEnvironment());
Chunk chunk = wrapper.passthrough(type);
@@ -58,10 +87,10 @@ public class BlockItemPacketRewriter1_10 extends LegacyBlockItemRewriter<Clientb
handleChunk(chunk);
});
// Rewrite entity data items
protocol.getEntityRewriter().filter().handler((event, data) -> {
if (data.dataType().type().equals(Types.ITEM1_8)) // Is Item
data.setValue(handleItemToClient(event.user(), (Item) data.getValue()));
// Rewrite metadata items
protocol.getEntityRewriter().filter().handler((event, meta) -> {
if (meta.dataType().type().equals(Types.ITEM1_8)) // Is Item
meta.setValue(handleItemToClient(event.user(), (Item) meta.getValue()));
});
// Particle
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -19,7 +19,7 @@
package com.viaversion.viabackwards.protocol.v1_10to1_9_3.rewriter;
import com.viaversion.viabackwards.api.entities.storage.EntityReplacement;
import com.viaversion.viabackwards.api.entities.storage.WrappedEntityData;
import com.viaversion.viabackwards.api.entities.storage.WrappedMetadata;
import com.viaversion.viabackwards.api.rewriters.LegacyEntityRewriter;
import com.viaversion.viabackwards.protocol.v1_10to1_9_3.Protocol1_10To1_9_3;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
@@ -29,6 +29,7 @@ import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_9;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.version.Types1_9;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ClientboundPackets1_9_3;
import java.util.List;
@@ -79,28 +80,25 @@ public class EntityPacketRewriter1_10 extends LegacyEntityRewriter<ClientboundPa
map(Types.SHORT); // 9 - Velocity X
map(Types.SHORT); // 10 - Velocity Y
map(Types.SHORT); // 11 - Velocity Z
map(Types.ENTITY_DATA_LIST1_9); // 12 - Entity data
map(Types1_9.ENTITY_DATA_LIST); // 12 - Metadata
// Track entity
handler(getTrackerHandler(Types.UNSIGNED_BYTE, 0));
// Rewrite entity type / data
// Rewrite entity type / metadata
handler(wrapper -> {
int entityId = wrapper.get(Types.VAR_INT, 0);
EntityType type = tracker(wrapper.user()).entityType(entityId);
if (type == null) {
return;
}
List<EntityData> entityDataList = wrapper.get(Types.ENTITY_DATA_LIST1_9, 0);
handleEntityData(wrapper.get(Types.VAR_INT, 0), entityDataList, wrapper.user());
List<EntityData> metadata = wrapper.get(Types1_9.ENTITY_DATA_LIST, 0);
handleEntityData(wrapper.get(Types.VAR_INT, 0), metadata, wrapper.user());
EntityReplacement entityReplacement = entityDataForType(type);
if (entityReplacement != null) {
WrappedEntityData storage = new WrappedEntityData(entityDataList);
WrappedMetadata storage = new WrappedMetadata(metadata);
wrapper.set(Types.UNSIGNED_BYTE, 0, (short) entityReplacement.replacementId());
if (entityReplacement.hasBaseData())
entityReplacement.defaultData().createData(storage);
if (entityReplacement.hasBaseMeta())
entityReplacement.defaultMeta().createMeta(storage);
}
});
@@ -121,14 +119,14 @@ public class EntityPacketRewriter1_10 extends LegacyEntityRewriter<ClientboundPa
map(Types.DOUBLE); // 4 - Z
map(Types.BYTE); // 5 - Yaw
map(Types.BYTE); // 6 - Pitch
map(Types.ENTITY_DATA_LIST1_9); // 7 - Entity data list
map(Types1_9.ENTITY_DATA_LIST); // 7 - Metadata list
handler(getTrackerAndDataHandler(Types.ENTITY_DATA_LIST1_9, EntityTypes1_11.EntityType.PLAYER));
handler(getTrackerAndMetaHandler(Types1_9.ENTITY_DATA_LIST, EntityTypes1_11.EntityType.PLAYER));
}
});
registerRemoveEntities(ClientboundPackets1_9_3.REMOVE_ENTITIES);
registerSetEntityData(ClientboundPackets1_9_3.SET_ENTITY_DATA, Types.ENTITY_DATA_LIST1_9);
registerSetEntityData(ClientboundPackets1_9_3.SET_ENTITY_DATA, Types1_9.ENTITY_DATA_LIST);
}
@Override
@@ -136,41 +134,38 @@ public class EntityPacketRewriter1_10 extends LegacyEntityRewriter<ClientboundPa
mapEntityTypeWithData(EntityTypes1_10.EntityType.POLAR_BEAR, EntityTypes1_10.EntityType.SHEEP).plainName();
// Change the sheep color when the polar bear is standing up (index 13 -> Standing up)
filter().type(EntityTypes1_10.EntityType.POLAR_BEAR).index(13).handler((event, data) -> {
boolean b = (boolean) data.getValue();
filter().type(EntityTypes1_10.EntityType.POLAR_BEAR).index(13).handler((event, meta) -> {
boolean b = (boolean) meta.getValue();
data.setTypeAndValue(EntityDataTypes1_9.BYTE, b ? (byte) (14 & 0x0F) : (byte) (0));
meta.setTypeAndValue(EntityDataTypes1_9.BYTE, b ? (byte) (14 & 0x0F) : (byte) (0));
});
// Handle husk (index 13 -> Zombie Type)
filter().type(EntityTypes1_10.EntityType.ZOMBIE).index(13).handler((event, data) -> {
if ((int) data.getValue() == 6) { // Is type Husk
data.setValue(0);
filter().type(EntityTypes1_10.EntityType.ZOMBIE).index(13).handler((event, meta) -> {
if ((int) meta.getValue() == 6) { // Is type Husk
meta.setValue(0);
}
});
// Handle Stray (index 12 -> Skeleton Type)
filter().type(EntityTypes1_10.EntityType.SKELETON).index(12).handler((event, data) -> {
if ((int) data.getValue() == 2) {
data.setValue(0); // Change to default skeleton
filter().type(EntityTypes1_10.EntityType.SKELETON).index(12).handler((event, meta) -> {
if ((int) meta.getValue() == 2) {
meta.setValue(0); // Change to default skeleton
}
});
// Added index from incorrect entity data hierarchy, where potions add to item entities
filter().type(EntityTypes1_10.EntityType.POTION).addIndex(6);
// Handle the missing NoGravity tag for every entity data
// Handle the missing NoGravity tag for every metadata
filter().removeIndex(5);
}
@Override
public EntityType typeFromId(int typeId) {
return EntityTypes1_10.EntityType.findById(typeId);
return EntityTypes1_10.getTypeFromId(typeId, false);
}
@Override
public EntityType objectTypeFromId(int typeId, int data) {
return EntityTypes1_10.ObjectType.getEntityType(typeId, data);
public EntityType objectTypeFromId(int typeId) {
return EntityTypes1_10.getTypeFromId(typeId, true);
}
}
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -39,8 +39,11 @@ public class Protocol1_11_1To1_11 extends BackwardsProtocol<ClientboundPackets1_
@Override
public void init(UserConnection user) {
if (!user.has(ClientWorld.class)) {
user.put(new ClientWorld());
}
user.addEntityTracker(this.getClass(), new EntityTrackerBase(user, EntityTypes1_11.EntityType.PLAYER));
user.addClientWorld(this.getClass(), new ClientWorld());
}
@Override
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -23,7 +23,9 @@ import com.viaversion.viabackwards.protocol.v1_11_1to1_11.Protocol1_11_1To1_11;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_11;
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.version.Types1_9;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ClientboundPackets1_9_3;
public class EntityPacketRewriter1_11_1 extends LegacyEntityRewriter<ClientboundPackets1_9_3, Protocol1_11_1To1_11> {
@@ -71,13 +73,13 @@ public class EntityPacketRewriter1_11_1 extends LegacyEntityRewriter<Clientbound
map(Types.SHORT); // 9 - Velocity X
map(Types.SHORT); // 10 - Velocity Y
map(Types.SHORT); // 11 - Velocity Z
map(Types.ENTITY_DATA_LIST1_9); // 12 - Entity data
map(Types1_9.ENTITY_DATA_LIST); // 12 - Metadata
// Track entity
handler(getTrackerHandler());
// Rewrite entity type / data
handler(getMobSpawnRewriter1_11(Types.ENTITY_DATA_LIST1_9));
// Rewrite entity type / metadata
handler(getMobSpawnRewriter1_11(Types1_9.ENTITY_DATA_LIST));
}
});
@@ -95,32 +97,32 @@ public class EntityPacketRewriter1_11_1 extends LegacyEntityRewriter<Clientbound
map(Types.DOUBLE); // 4 - Z
map(Types.BYTE); // 5 - Yaw
map(Types.BYTE); // 6 - Pitch
map(Types.ENTITY_DATA_LIST1_9); // 7 - Entity data list
map(Types1_9.ENTITY_DATA_LIST); // 7 - Metadata list
handler(getTrackerAndDataHandler(Types.ENTITY_DATA_LIST1_9, EntityTypes1_11.EntityType.PLAYER));
handler(getTrackerAndMetaHandler(Types1_9.ENTITY_DATA_LIST, EntityTypes1_11.EntityType.PLAYER));
}
});
registerRemoveEntities(ClientboundPackets1_9_3.REMOVE_ENTITIES);
registerSetEntityData(ClientboundPackets1_9_3.SET_ENTITY_DATA, Types.ENTITY_DATA_LIST1_9);
registerSetEntityData(ClientboundPackets1_9_3.SET_ENTITY_DATA, Types1_9.ENTITY_DATA_LIST);
}
@Override
protected void registerRewrites() {
// Handle non-existing firework entity data (index 7 entity id for boosting)
// Handle non-existing firework metadata (index 7 entity id for boosting)
filter().type(EntityTypes1_11.EntityType.FIREWORK_ROCKET).cancel(7);
// Handle non-existing pig entity data (index 14 - boost time)
// Handle non-existing pig metadata (index 14 - boost time)
filter().type(EntityTypes1_11.EntityType.PIG).cancel(14);
}
@Override
public EntityType typeFromId(int typeId) {
return EntityTypes1_11.EntityType.findById(typeId);
return EntityTypes1_11.getTypeFromId(typeId, false);
}
@Override
public EntityType objectTypeFromId(int typeId, int data) {
return EntityTypes1_11.ObjectType.getEntityType(typeId, data);
public EntityType objectTypeFromId(int typeId) {
return EntityTypes1_11.getTypeFromId(typeId, true);
}
}
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -23,6 +23,8 @@ import com.viaversion.viabackwards.api.rewriters.LegacyEnchantmentRewriter;
import com.viaversion.viabackwards.protocol.v1_11_1to1_11.Protocol1_11_1To1_11;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ClientboundPackets1_9_3;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ServerboundPackets1_9_3;
@@ -40,15 +42,43 @@ public class ItemPacketRewriter1_11_1 extends LegacyBlockItemRewriter<Clientboun
registerSetSlot(ClientboundPackets1_9_3.CONTAINER_SET_SLOT);
registerSetContent(ClientboundPackets1_9_3.CONTAINER_SET_CONTENT);
registerSetEquippedItem(ClientboundPackets1_9_3.SET_EQUIPPED_ITEM);
registerCustomPayloadTradeList(ClientboundPackets1_9_3.CUSTOM_PAYLOAD);
// Plugin message Packet -> Trading
protocol.registerClientbound(ClientboundPackets1_9_3.CUSTOM_PAYLOAD, new PacketHandlers() {
@Override
public void register() {
map(Types.STRING); // 0 - Channel
handler(wrapper -> {
if (wrapper.get(Types.STRING, 0).equals("MC|TrList")) {
wrapper.passthrough(Types.INT); // Passthrough Window ID
int size = wrapper.passthrough(Types.UNSIGNED_BYTE);
for (int i = 0; i < size; i++) {
wrapper.write(Types.ITEM1_8, handleItemToClient(wrapper.user(), wrapper.read(Types.ITEM1_8))); // Input Item
wrapper.write(Types.ITEM1_8, handleItemToClient(wrapper.user(), wrapper.read(Types.ITEM1_8))); // Output Item
boolean secondItem = wrapper.passthrough(Types.BOOLEAN); // Has second item
if (secondItem) {
wrapper.write(Types.ITEM1_8, handleItemToClient(wrapper.user(), wrapper.read(Types.ITEM1_8))); // Second Item
}
wrapper.passthrough(Types.BOOLEAN); // Trade disabled
wrapper.passthrough(Types.INT); // Number of tools uses
wrapper.passthrough(Types.INT); // Maximum number of trade uses
}
}
});
}
});
registerContainerClick(ServerboundPackets1_9_3.CONTAINER_CLICK);
registerSetCreativeModeSlot(ServerboundPackets1_9_3.SET_CREATIVE_MODE_SLOT);
// Handle item entity data
protocol.getEntityRewriter().filter().handler((event, data) -> {
if (data.dataType().type().equals(Types.ITEM1_8)) { // Is Item
data.setValue(handleItemToClient(event.user(), (Item) data.getValue()));
// Handle item metadata
protocol.getEntityRewriter().filter().handler((event, meta) -> {
if (meta.dataType().type().equals(Types.ITEM1_8)) { // Is Item
meta.setValue(handleItemToClient(event.user(), (Item) meta.getValue()));
}
});
}
@@ -71,7 +101,7 @@ public class ItemPacketRewriter1_11_1 extends LegacyBlockItemRewriter<Clientboun
@Override
public Item handleItemToServer(UserConnection connection, Item item) {
if (item == null) return null;
item = super.handleItemToServer(connection, item);
super.handleItemToServer(connection, item);
enchantmentRewriter.handleToServer(item);
return item;
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -20,7 +20,8 @@ package com.viaversion.viabackwards.protocol.v1_11to1_10;
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.api.rewriters.SoundRewriter;
import com.viaversion.viabackwards.api.rewriters.TranslatableRewriter;
import com.viaversion.viabackwards.protocol.v1_11to1_10.rewriter.BlockItemPacketRewriter1_11;
import com.viaversion.viabackwards.protocol.v1_11to1_10.rewriter.EntityPacketRewriter1_11;
import com.viaversion.viabackwards.protocol.v1_11to1_10.rewriter.PlayerPacketRewriter1_11;
@@ -29,16 +30,17 @@ import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_11;
import com.viaversion.viaversion.data.entity.EntityTrackerBase;
import com.viaversion.viaversion.protocols.v1_11_1to1_12.packet.ClientboundPackets1_12;
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.rewriter.text.ComponentRewriterBase;
import com.viaversion.viaversion.rewriter.ComponentRewriter;
public class Protocol1_11To1_10 extends BackwardsProtocol<ClientboundPackets1_9_3, ClientboundPackets1_9_3, ServerboundPackets1_9_3, ServerboundPackets1_9_3> {
public static final BackwardsMappingData MAPPINGS = new BackwardsMappingData("1.11", "1.10");
private final EntityPacketRewriter1_11 entityRewriter = new EntityPacketRewriter1_11(this);
private final BlockItemPacketRewriter1_11 itemRewriter = new BlockItemPacketRewriter1_11(this);
private JsonNBTComponentRewriter<ClientboundPackets1_9_3> componentRewriter;
private TranslatableRewriter<ClientboundPackets1_9_3> componentRewriter;
public Protocol1_11To1_10() {
super(ClientboundPackets1_9_3.class, ClientboundPackets1_9_3.class, ServerboundPackets1_9_3.class, ServerboundPackets1_9_3.class);
@@ -50,14 +52,21 @@ public class Protocol1_11To1_10 extends BackwardsProtocol<ClientboundPackets1_9_
itemRewriter.register();
PlayerPacketRewriter1_11.register(this);
componentRewriter = new JsonNBTComponentRewriter<>(this, ComponentRewriterBase.ReadType.JSON);
SoundRewriter<ClientboundPackets1_9_3> soundRewriter = new SoundRewriter<>(this);
soundRewriter.registerNamedSound(ClientboundPackets1_9_3.CUSTOM_SOUND);
soundRewriter.registerSound(ClientboundPackets1_9_3.SOUND);
componentRewriter = new TranslatableRewriter<>(this, ComponentRewriter.ReadType.JSON);
componentRewriter.registerComponentPacket(ClientboundPackets1_9_3.CHAT);
}
@Override
public void init(UserConnection user) {
if (!user.has(ClientWorld.class)) {
user.put(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());
@@ -79,8 +88,12 @@ public class Protocol1_11To1_10 extends BackwardsProtocol<ClientboundPackets1_9_
return itemRewriter;
}
@Override
public JsonNBTComponentRewriter<ClientboundPackets1_9_3> getComponentRewriter() {
public TranslatableRewriter<ClientboundPackets1_9_3> getComponentRewriter() {
return componentRewriter;
}
@Override
public boolean hasMappingDataToLoad() {
return true;
}
}
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -18,8 +18,6 @@
package com.viaversion.viabackwards.protocol.v1_11to1_10.rewriter;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viabackwards.api.data.MappedLegacyBlockItem;
import com.viaversion.viabackwards.api.rewriters.LegacyBlockItemRewriter;
import com.viaversion.viabackwards.api.rewriters.LegacyEnchantmentRewriter;
@@ -37,6 +35,8 @@ import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_9_3;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viaversion.protocols.v1_10to1_11.data.EntityMappings1_11;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ClientboundPackets1_9_3;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ServerboundPackets1_9_3;
@@ -60,7 +60,7 @@ public class BlockItemPacketRewriter1_11 extends LegacyBlockItemRewriter<Clientb
protocol.registerClientbound(ClientboundPackets1_9_3.CONTAINER_SET_SLOT, new PacketHandlers() {
@Override
public void register() {
map(Types.BYTE); // 0 - Window ID
map(Types.UNSIGNED_BYTE); // 0 - Window ID
map(Types.SHORT); // 1 - Slot ID
map(Types.ITEM1_8); // 2 - Slot Value
@@ -113,12 +113,40 @@ public class BlockItemPacketRewriter1_11 extends LegacyBlockItemRewriter<Clientb
});
registerSetEquippedItem(ClientboundPackets1_9_3.SET_EQUIPPED_ITEM);
registerCustomPayloadTradeList(ClientboundPackets1_9_3.CUSTOM_PAYLOAD);
// Plugin message -> Trading
protocol.registerClientbound(ClientboundPackets1_9_3.CUSTOM_PAYLOAD, new PacketHandlers() {
@Override
public void register() {
map(Types.STRING); // 0 - Channel
handler(wrapper -> {
if (wrapper.get(Types.STRING, 0).equals("MC|TrList")) {
wrapper.passthrough(Types.INT); // Passthrough Window ID
int size = wrapper.passthrough(Types.UNSIGNED_BYTE);
for (int i = 0; i < size; i++) {
wrapper.write(Types.ITEM1_8, handleItemToClient(wrapper.user(), wrapper.read(Types.ITEM1_8))); // Input Item
wrapper.write(Types.ITEM1_8, handleItemToClient(wrapper.user(), wrapper.read(Types.ITEM1_8))); // Output Item
boolean secondItem = wrapper.passthrough(Types.BOOLEAN); // Has second item
if (secondItem) {
wrapper.write(Types.ITEM1_8, handleItemToClient(wrapper.user(), wrapper.read(Types.ITEM1_8))); // Second Item
}
wrapper.passthrough(Types.BOOLEAN); // Trade disabled
wrapper.passthrough(Types.INT); // Number of tools uses
wrapper.passthrough(Types.INT); // Maximum number of trade uses
}
}
});
}
});
protocol.registerServerbound(ServerboundPackets1_9_3.CONTAINER_CLICK, new PacketHandlers() {
@Override
public void register() {
map(Types.BYTE); // 0 - Window ID
map(Types.UNSIGNED_BYTE); // 0 - Window ID
map(Types.SHORT); // 1 - Slot
map(Types.BYTE); // 2 - Button
map(Types.SHORT); // 3 - Action number
@@ -147,7 +175,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().getClientWorld(Protocol1_11To1_10.class);
ClientWorld clientWorld = wrapper.user().get(ClientWorld.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);
@@ -243,9 +271,9 @@ public class BlockItemPacketRewriter1_11 extends LegacyBlockItemRewriter<Clientb
}
});
protocol.getEntityRewriter().filter().handler((event, data) -> {
if (data.dataType().type().equals(Types.ITEM1_8)) // Is Item
data.setValue(handleItemToClient(event.user(), (Item) data.getValue()));
protocol.getEntityRewriter().filter().handler((event, meta) -> {
if (meta.dataType().type().equals(Types.ITEM1_8)) // Is Item
meta.setValue(handleItemToClient(event.user(), (Item) meta.getValue()));
});
}
@@ -253,7 +281,10 @@ public class BlockItemPacketRewriter1_11 extends LegacyBlockItemRewriter<Clientb
protected void registerRewrites() {
// Handle spawner block entity (map to itself with custom handler)
MappedLegacyBlockItem data = itemReplacements.computeIfAbsent(IdAndData.toRawData(52), s -> new MappedLegacyBlockItem(52));
data.setBlockEntityHandler((b, tag) -> EntityMappings1_11.toClientSpawner(tag, true));
data.setBlockEntityHandler((b, tag) -> {
EntityMappings1_11.toClientSpawner(tag, true);
return tag;
});
enchantmentRewriter = new LegacyEnchantmentRewriter(nbtTagName());
enchantmentRewriter.registerEnchantment(71, "§cCurse of Vanishing");
@@ -264,7 +295,7 @@ public class BlockItemPacketRewriter1_11 extends LegacyBlockItemRewriter<Clientb
@Override
public Item handleItemToClient(UserConnection connection, Item item) {
if (item == null) return null;
if (item == null || item.isEmpty()) return null;
super.handleItemToClient(connection, item);
CompoundTag tag = item.tag();
@@ -280,7 +311,7 @@ public class BlockItemPacketRewriter1_11 extends LegacyBlockItemRewriter<Clientb
@Override
public Item handleItemToServer(UserConnection connection, Item item) {
if (item == null) return null;
item = super.handleItemToServer(connection, item);
super.handleItemToServer(connection, item);
CompoundTag tag = item.tag();
if (tag == null) return item;
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -18,7 +18,7 @@
package com.viaversion.viabackwards.protocol.v1_11to1_10.rewriter;
import com.viaversion.viabackwards.api.entities.storage.WrappedEntityData;
import com.viaversion.viabackwards.api.entities.storage.WrappedMetadata;
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;
@@ -30,6 +30,7 @@ import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_9;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.version.Types1_9;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ClientboundPackets1_9_3;
import java.util.List;
@@ -103,19 +104,19 @@ public class EntityPacketRewriter1_11 extends LegacyEntityRewriter<ClientboundPa
map(Types.SHORT); // 9 - Velocity X
map(Types.SHORT); // 10 - Velocity Y
map(Types.SHORT); // 11 - Velocity Z
map(Types.ENTITY_DATA_LIST1_9); // 12 - Entity data
map(Types1_9.ENTITY_DATA_LIST); // 12 - Metadata
// Track entity
handler(getTrackerHandler(Types.UNSIGNED_BYTE, 0));
// Rewrite entity type / data
handler(getMobSpawnRewriter(Types.ENTITY_DATA_LIST1_9));
// Rewrite entity type / metadata
handler(getMobSpawnRewriter(Types1_9.ENTITY_DATA_LIST));
// Sub 1.11 clients will error if the list is empty
handler(wrapper -> {
List<EntityData> entityDataList = wrapper.get(Types.ENTITY_DATA_LIST1_9, 0);
if (entityDataList.isEmpty()) {
entityDataList.add(new EntityData(0, EntityDataTypes1_9.BYTE, (byte) 0));
List<EntityData> metadata = wrapper.get(Types1_9.ENTITY_DATA_LIST, 0);
if (metadata.isEmpty()) {
metadata.add(new EntityData(0, EntityDataTypes1_9.BYTE, (byte) 0));
}
});
}
@@ -135,21 +136,21 @@ public class EntityPacketRewriter1_11 extends LegacyEntityRewriter<ClientboundPa
map(Types.DOUBLE); // 4 - Z
map(Types.BYTE); // 5 - Yaw
map(Types.BYTE); // 6 - Pitch
map(Types.ENTITY_DATA_LIST1_9); // 7 - Entity data list
map(Types1_9.ENTITY_DATA_LIST); // 7 - Metadata list
handler(getTrackerAndDataHandler(Types.ENTITY_DATA_LIST1_9, EntityTypes1_11.EntityType.PLAYER));
handler(getTrackerAndMetaHandler(Types1_9.ENTITY_DATA_LIST, EntityTypes1_11.EntityType.PLAYER));
handler(wrapper -> {
// Sub 1.11 clients will cry if the list is empty
List<EntityData> entityDataList = wrapper.get(Types.ENTITY_DATA_LIST1_9, 0);
if (entityDataList.isEmpty()) {
entityDataList.add(new EntityData(0, EntityDataTypes1_9.BYTE, (byte) 0));
List<EntityData> metadata = wrapper.get(Types1_9.ENTITY_DATA_LIST, 0);
if (metadata.isEmpty()) {
metadata.add(new EntityData(0, EntityDataTypes1_9.BYTE, (byte) 0));
}
});
}
});
registerRemoveEntities(ClientboundPackets1_9_3.REMOVE_ENTITIES);
registerSetEntityData(ClientboundPackets1_9_3.SET_ENTITY_DATA, Types.ENTITY_DATA_LIST1_9);
registerSetEntityData(ClientboundPackets1_9_3.SET_ENTITY_DATA, Types1_9.ENTITY_DATA_LIST);
protocol.registerClientbound(ClientboundPackets1_9_3.ENTITY_EVENT, new PacketHandlers() {
@Override
@@ -158,15 +159,9 @@ public class EntityPacketRewriter1_11 extends LegacyEntityRewriter<ClientboundPa
map(Types.BYTE); // 1 - Entity Status
handler(wrapper -> {
final int entityId = wrapper.get(Types.INT, 0);
if (entityId != tracker(wrapper.user()).clientEntityId()) {
// Entity events are sent for all players, but we only want to apply this for the self player
return;
}
byte b = wrapper.get(Types.BYTE, 0);
final byte entityStatus = wrapper.get(Types.BYTE, 0);
if (entityStatus == 35) {
// TODO spawn particles?
if (b == 35) {
wrapper.clearPacket();
wrapper.setPacketType(ClientboundPackets1_9_3.GAME_EVENT);
wrapper.write(Types.UNSIGNED_BYTE, (short) 10); // Play Elder Guardian animation
@@ -182,39 +177,39 @@ public class EntityPacketRewriter1_11 extends LegacyEntityRewriter<ClientboundPa
// Guardian
mapEntityTypeWithData(EntityTypes1_11.EntityType.ELDER_GUARDIAN, EntityTypes1_11.EntityType.GUARDIAN);
// Skeletons
mapEntityTypeWithData(EntityTypes1_11.EntityType.WITHER_SKELETON, EntityTypes1_11.EntityType.SKELETON).spawnEntityData(storage -> storage.add(getSkeletonTypeData(1)));
mapEntityTypeWithData(EntityTypes1_11.EntityType.STRAY, EntityTypes1_11.EntityType.SKELETON).plainName().spawnEntityData(storage -> storage.add(getSkeletonTypeData(2)));
mapEntityTypeWithData(EntityTypes1_11.EntityType.WITHER_SKELETON, EntityTypes1_11.EntityType.SKELETON).spawnMetadata(storage -> storage.add(getSkeletonTypeMeta(1)));
mapEntityTypeWithData(EntityTypes1_11.EntityType.STRAY, EntityTypes1_11.EntityType.SKELETON).plainName().spawnMetadata(storage -> storage.add(getSkeletonTypeMeta(2)));
// Zombies
mapEntityTypeWithData(EntityTypes1_11.EntityType.HUSK, EntityTypes1_11.EntityType.ZOMBIE).plainName().spawnEntityData(storage -> handleZombieType(storage, 6));
mapEntityTypeWithData(EntityTypes1_11.EntityType.ZOMBIE_VILLAGER, EntityTypes1_11.EntityType.ZOMBIE).spawnEntityData(storage -> handleZombieType(storage, 1));
mapEntityTypeWithData(EntityTypes1_11.EntityType.HUSK, EntityTypes1_11.EntityType.ZOMBIE).plainName().spawnMetadata(storage -> handleZombieType(storage, 6));
mapEntityTypeWithData(EntityTypes1_11.EntityType.ZOMBIE_VILLAGER, EntityTypes1_11.EntityType.ZOMBIE).spawnMetadata(storage -> handleZombieType(storage, 1));
// Horses
mapEntityTypeWithData(EntityTypes1_11.EntityType.HORSE, EntityTypes1_11.EntityType.HORSE).spawnEntityData(storage -> storage.add(getHorseDataType(0))); // Nob able to ride the horse without having the EntityDataType sent.
mapEntityTypeWithData(EntityTypes1_11.EntityType.DONKEY, EntityTypes1_11.EntityType.HORSE).spawnEntityData(storage -> storage.add(getHorseDataType(1)));
mapEntityTypeWithData(EntityTypes1_11.EntityType.MULE, EntityTypes1_11.EntityType.HORSE).spawnEntityData(storage -> storage.add(getHorseDataType(2)));
mapEntityTypeWithData(EntityTypes1_11.EntityType.SKELETON_HORSE, EntityTypes1_11.EntityType.HORSE).spawnEntityData(storage -> storage.add(getHorseDataType(4)));
mapEntityTypeWithData(EntityTypes1_11.EntityType.ZOMBIE_HORSE, EntityTypes1_11.EntityType.HORSE).spawnEntityData(storage -> storage.add(getHorseDataType(3)));
mapEntityTypeWithData(EntityTypes1_11.EntityType.HORSE, EntityTypes1_11.EntityType.HORSE).spawnMetadata(storage -> storage.add(getHorseMetaType(0))); // Nob able to ride the horse without having the MetaType sent.
mapEntityTypeWithData(EntityTypes1_11.EntityType.DONKEY, EntityTypes1_11.EntityType.HORSE).spawnMetadata(storage -> storage.add(getHorseMetaType(1)));
mapEntityTypeWithData(EntityTypes1_11.EntityType.MULE, EntityTypes1_11.EntityType.HORSE).spawnMetadata(storage -> storage.add(getHorseMetaType(2)));
mapEntityTypeWithData(EntityTypes1_11.EntityType.SKELETON_HORSE, EntityTypes1_11.EntityType.HORSE).spawnMetadata(storage -> storage.add(getHorseMetaType(4)));
mapEntityTypeWithData(EntityTypes1_11.EntityType.ZOMBIE_HORSE, EntityTypes1_11.EntityType.HORSE).spawnMetadata(storage -> storage.add(getHorseMetaType(3)));
// New mobs
mapEntityTypeWithData(EntityTypes1_11.EntityType.EVOKER_FANGS, EntityTypes1_11.EntityType.SHULKER);
mapEntityTypeWithData(EntityTypes1_11.EntityType.EVOKER, EntityTypes1_11.EntityType.VILLAGER).plainName();
mapEntityTypeWithData(EntityTypes1_11.EntityType.VEX, EntityTypes1_11.EntityType.BAT).plainName();
mapEntityTypeWithData(EntityTypes1_11.EntityType.VINDICATOR, EntityTypes1_11.EntityType.VILLAGER).plainName().spawnEntityData(storage -> storage.add(new EntityData(13, EntityDataTypes1_9.VAR_INT, 4))); // Base Profession
mapEntityTypeWithData(EntityTypes1_11.EntityType.LLAMA, EntityTypes1_11.EntityType.HORSE).plainName().spawnEntityData(storage -> storage.add(getHorseDataType(1)));
mapEntityTypeWithData(EntityTypes1_11.EntityType.VINDICATOR, EntityTypes1_11.EntityType.VILLAGER).plainName().spawnMetadata(storage -> storage.add(new EntityData(13, EntityDataTypes1_9.VAR_INT, 4))); // Base Profession
mapEntityTypeWithData(EntityTypes1_11.EntityType.LLAMA, EntityTypes1_11.EntityType.HORSE).plainName().spawnMetadata(storage -> storage.add(getHorseMetaType(1)));
mapEntityTypeWithData(EntityTypes1_11.EntityType.LLAMA_SPIT, EntityTypes1_11.EntityType.SNOWBALL);
mapObjectType(EntityTypes1_11.ObjectType.LLAMA_SPIT, EntityTypes1_11.ObjectType.SNOWBALL, -1);
// Replace with endertorchthingies
mapObjectType(EntityTypes1_11.ObjectType.EVOKER_FANGS, EntityTypes1_11.ObjectType.FALLING_BLOCK, 198 | 1 << 12);
// Handle ElderGuardian & target entity data
filter().type(EntityTypes1_11.EntityType.GUARDIAN).index(12).handler((event, data) -> {
boolean b = (boolean) data.getValue();
// Handle ElderGuardian & target metadata
filter().type(EntityTypes1_11.EntityType.GUARDIAN).index(12).handler((event, meta) -> {
boolean b = (boolean) meta.getValue();
int bitmask = b ? 0x02 : 0;
if (event.entityType() == EntityTypes1_11.EntityType.ELDER_GUARDIAN) {
bitmask |= 0x04;
}
data.setTypeAndValue(EntityDataTypes1_9.BYTE, (byte) bitmask);
meta.setTypeAndValue(EntityDataTypes1_9.BYTE, (byte) bitmask);
});
// Handle skeleton swing
@@ -223,34 +218,34 @@ public class EntityPacketRewriter1_11 extends LegacyEntityRewriter<ClientboundPa
/*
ZOMBIE CHANGES
*/
filter().type(EntityTypes1_11.EntityType.ZOMBIE).handler((event, data) -> {
switch (data.id()) {
filter().type(EntityTypes1_11.EntityType.ZOMBIE).handler((event, meta) -> {
switch (meta.id()) {
case 13 -> event.cancel();
case 14 -> event.setIndex(15);
case 15 -> event.setIndex(14);
case 16 -> {
// Profession
event.setIndex(13);
data.setValue(1 + (int) data.getValue());
meta.setValue(1 + (int) meta.getValue());
}
}
});
// Handle Evocation Illager
filter().type(EntityTypes1_11.EntityType.EVOKER).index(12).handler((event, data) -> {
filter().type(EntityTypes1_11.EntityType.EVOKER).index(12).handler((event, meta) -> {
event.setIndex(13);
data.setTypeAndValue(EntityDataTypes1_9.VAR_INT, ((Byte) data.getValue()).intValue()); // Change the profession for the states
meta.setTypeAndValue(EntityDataTypes1_9.VAR_INT, ((Byte) meta.getValue()).intValue()); // Change the profession for the states
});
// Handle Vex (Remove this field completely since the position is not updated correctly when idling for bats. Sad ):
filter().type(EntityTypes1_11.EntityType.VEX).index(12).handler((event, data) -> {
data.setValue((byte) 0x00);
filter().type(EntityTypes1_11.EntityType.VEX).index(12).handler((event, meta) -> {
meta.setValue((byte) 0x00);
});
// Handle VindicationIllager
filter().type(EntityTypes1_11.EntityType.VINDICATOR).index(12).handler((event, data) -> {
filter().type(EntityTypes1_11.EntityType.VINDICATOR).index(12).handler((event, meta) -> {
event.setIndex(13);
data.setTypeAndValue(EntityDataTypes1_9.VAR_INT, ((Number) data.getValue()).intValue() == 1 ? 2 : 4);
meta.setTypeAndValue(EntityDataTypes1_9.VAR_INT, ((Number) meta.getValue()).intValue() == 1 ? 2 : 4);
});
/*
@@ -258,20 +253,20 @@ 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();
if (entityData.has(ChestedHorseStorage.class) && entityData.get(ChestedHorseStorage.class).isChested()) {
filter().type(EntityTypes1_11.EntityType.ABSTRACT_HORSE).index(13).handler((event, meta) -> {
StoredEntityData data = storedEntityData(event);
byte b = (byte) meta.getValue();
if (data.has(ChestedHorseStorage.class) && data.get(ChestedHorseStorage.class).isChested()) {
b |= 0x08; // Chested
data.setValue(b);
meta.setValue(b);
}
});
// Create chested horse storage
filter().type(EntityTypes1_11.EntityType.CHESTED_HORSE).handler((event, data) -> {
StoredEntityData entityData = storedEntityData(event);
if (!entityData.has(ChestedHorseStorage.class)) {
entityData.put(new ChestedHorseStorage());
filter().type(EntityTypes1_11.EntityType.CHESTED_HORSE).handler((event, meta) -> {
StoredEntityData data = storedEntityData(event);
if (!data.has(ChestedHorseStorage.class)) {
data.put(new ChestedHorseStorage());
}
});
@@ -279,32 +274,32 @@ public class EntityPacketRewriter1_11 extends LegacyEntityRewriter<ClientboundPa
filter().type(EntityTypes1_11.EntityType.HORSE).index(16).toIndex(17);
// Handle chested horse
filter().type(EntityTypes1_11.EntityType.CHESTED_HORSE).index(15).handler((event, data) -> {
StoredEntityData entityData = storedEntityData(event);
ChestedHorseStorage storage = entityData.get(ChestedHorseStorage.class);
boolean b = (boolean) data.getValue();
filter().type(EntityTypes1_11.EntityType.CHESTED_HORSE).index(15).handler((event, meta) -> {
StoredEntityData data = storedEntityData(event);
ChestedHorseStorage storage = data.get(ChestedHorseStorage.class);
boolean b = (boolean) meta.getValue();
storage.setChested(b);
event.cancel();
});
// Get rid of Liama entity data
filter().type(EntityTypes1_11.EntityType.LLAMA).handler((event, data) -> {
StoredEntityData entityData = storedEntityData(event);
ChestedHorseStorage storage = entityData.get(ChestedHorseStorage.class);
// Get rid of Liama metadata
filter().type(EntityTypes1_11.EntityType.LLAMA).handler((event, meta) -> {
StoredEntityData data = storedEntityData(event);
ChestedHorseStorage storage = data.get(ChestedHorseStorage.class);
int index = event.index();
// Store them for later (:
switch (index) {
case 16 -> {
storage.setLiamaStrength((int) data.getValue());
storage.setLiamaStrength((int) meta.getValue());
event.cancel();
}
case 17 -> {
storage.setLiamaCarpetColor((int) data.getValue());
storage.setLiamaCarpetColor((int) meta.getValue());
event.cancel();
}
case 18 -> {
storage.setLiamaVariant((int) data.getValue());
storage.setLiamaVariant((int) meta.getValue());
event.cancel();
}
}
@@ -314,13 +309,13 @@ public class EntityPacketRewriter1_11 extends LegacyEntityRewriter<ClientboundPa
filter().type(EntityTypes1_11.EntityType.ABSTRACT_HORSE).index(14).toIndex(16);
// Handle villager - Change non-existing profession
filter().type(EntityTypes1_11.EntityType.VILLAGER).index(13).handler((event, data) -> {
if ((int) data.getValue() == 5) {
data.setValue(0);
filter().type(EntityTypes1_11.EntityType.VILLAGER).index(13).handler((event, meta) -> {
if ((int) meta.getValue() == 5) {
meta.setValue(0);
}
});
// handle new Shulker color data
// handle new Shulker color meta
filter().type(EntityTypes1_11.EntityType.SHULKER).cancel(15);
}
@@ -330,7 +325,7 @@ public class EntityPacketRewriter1_11 extends LegacyEntityRewriter<ClientboundPa
2 - Stray
*/
private EntityData getSkeletonTypeData(int type) {
private EntityData getSkeletonTypeMeta(int type) {
return new EntityData(12, EntityDataTypes1_9.VAR_INT, type);
}
@@ -339,14 +334,14 @@ public class EntityPacketRewriter1_11 extends LegacyEntityRewriter<ClientboundPa
1-5 - Villager with profession
6 - Husk
*/
private EntityData getZombieTypeData(int type) {
private EntityData getZombieTypeMeta(int type) {
return new EntityData(13, EntityDataTypes1_9.VAR_INT, type);
}
private void handleZombieType(WrappedEntityData storage, int type) {
private void handleZombieType(WrappedMetadata storage, int type) {
EntityData meta = storage.get(13);
if (meta == null) {
storage.add(getZombieTypeData(type));
storage.add(getZombieTypeMeta(type));
}
}
@@ -357,17 +352,17 @@ public class EntityPacketRewriter1_11 extends LegacyEntityRewriter<ClientboundPa
Zombie horse 3
Skeleton horse 4
*/
private EntityData getHorseDataType(int type) {
private EntityData getHorseMetaType(int type) {
return new EntityData(14, EntityDataTypes1_9.VAR_INT, type);
}
@Override
public EntityType typeFromId(int typeId) {
return EntityTypes1_11.EntityType.findById(typeId);
return EntityTypes1_11.getTypeFromId(typeId, false);
}
@Override
public EntityType objectTypeFromId(int typeId, int data) {
return EntityTypes1_11.ObjectType.getEntityType(typeId, data);
public EntityType objectTypeFromId(int typeId) {
return EntityTypes1_11.getTypeFromId(typeId, true);
}
}
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -21,6 +21,7 @@ package com.viaversion.viabackwards.protocol.v1_12_2to1_12_1;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.protocol.v1_12_2to1_12_1.storage.KeepAliveTracker;
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.protocols.v1_12to1_12_1.packet.ClientboundPackets1_12_1;
import com.viaversion.viaversion.protocols.v1_12to1_12_1.packet.ServerboundPackets1_12_1;
@@ -33,20 +34,32 @@ public class Protocol1_12_2To1_12_1 extends BackwardsProtocol<ClientboundPackets
@Override
protected void registerPackets() {
registerClientbound(ClientboundPackets1_12_1.KEEP_ALIVE, wrapper -> {
long keepAlive = wrapper.read(Types.LONG);
int id = wrapper.user().get(KeepAliveTracker.class).track(keepAlive);
wrapper.write(Types.VAR_INT, id);
registerClientbound(ClientboundPackets1_12_1.KEEP_ALIVE, new PacketHandlers() {
@Override
public void register() {
handler(packetWrapper -> {
Long keepAlive = packetWrapper.read(Types.LONG);
packetWrapper.user().get(KeepAliveTracker.class).setKeepAlive(keepAlive);
packetWrapper.write(Types.VAR_INT, keepAlive.hashCode());
});
}
});
registerServerbound(ServerboundPackets1_12_1.KEEP_ALIVE, wrapper -> {
int keepAlive = wrapper.read(Types.VAR_INT);
Long realKeepAlive = wrapper.user().get(KeepAliveTracker.class).consume(keepAlive);
if (realKeepAlive == null) {
wrapper.cancel(); // stale/bad
return;
registerServerbound(ServerboundPackets1_12_1.KEEP_ALIVE, new PacketHandlers() {
@Override
public void register() {
handler(packetWrapper -> {
int keepAlive = packetWrapper.read(Types.VAR_INT);
long realKeepAlive = packetWrapper.user().get(KeepAliveTracker.class).getKeepAlive();
if (keepAlive != Long.hashCode(realKeepAlive)) {
packetWrapper.cancel(); // Wrong data, cancel packet
return;
}
packetWrapper.write(Types.LONG, realKeepAlive);
// Reset KeepAliveTracker (to prevent sending same valid value in a row causing a timeout)
packetWrapper.user().get(KeepAliveTracker.class).setKeepAlive(Integer.MAX_VALUE);
});
}
wrapper.write(Types.LONG, realKeepAlive);
});
}
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -19,22 +19,20 @@
package com.viaversion.viabackwards.protocol.v1_12_2to1_12_1.storage;
import com.viaversion.viaversion.api.connection.StorableObject;
import java.util.HashMap;
import java.util.Map;
import org.checkerframework.checker.nullness.qual.Nullable;
public class KeepAliveTracker implements StorableObject {
private long keepAlive = Integer.MAX_VALUE;
private final Map<Integer, Long> pending = new HashMap<>();
private int nextId;
public int track(long original) {
int id = nextId++;
pending.put(id, original);
return id;
public long getKeepAlive() {
return keepAlive;
}
public @Nullable Long consume(int id) {
return pending.remove(id);
public void setKeepAlive(long keepAlive) {
this.keepAlive = keepAlive;
}
@Override
public String toString() {
return "KeepAliveTracker{" + "keepAlive=" + keepAlive + '}';
}
}
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -20,11 +20,11 @@ package com.viaversion.viabackwards.protocol.v1_12to1_11_1;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.data.BackwardsMappingData;
import com.viaversion.viabackwards.protocol.v1_12to1_11_1.storage.ShoulderTracker;
import com.viaversion.viabackwards.protocol.v1_12to1_11_1.rewriter.BlockItemPacketRewriter1_12;
import com.viaversion.viabackwards.protocol.v1_12to1_11_1.rewriter.ComponentRewriter1_12;
import com.viaversion.viabackwards.protocol.v1_12to1_11_1.rewriter.EntityPacketRewriter1_12;
import com.viaversion.viabackwards.protocol.v1_12to1_11_1.rewriter.SoundPacketRewriter1_12;
import com.viaversion.viabackwards.protocol.v1_12to1_11_1.storage.ShoulderTracker;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_12;
@@ -50,8 +50,8 @@ public class Protocol1_12To1_11_1 extends BackwardsProtocol<ClientboundPackets1_
@Override
protected void registerPackets() {
super.registerPackets();
itemRewriter.register();
entityRewriter.register();
componentRewriter.registerComponentPacket(ClientboundPackets1_12.CHAT);
new SoundPacketRewriter1_12(this).register();
@@ -71,8 +71,11 @@ public class Protocol1_12To1_11_1 extends BackwardsProtocol<ClientboundPackets1_
@Override
public void init(UserConnection user) {
if (!user.has(ClientWorld.class)) {
user.put(new ClientWorld());
}
user.addEntityTracker(this.getClass(), new EntityTrackerBase(user, EntityTypes1_12.EntityType.PLAYER));
user.addClientWorld(this.getClass(), new ClientWorld());
user.put(new ShoulderTracker(user));
}
@@ -92,8 +95,12 @@ public class Protocol1_12To1_11_1 extends BackwardsProtocol<ClientboundPackets1_
return itemRewriter;
}
@Override
public ComponentRewriter1_12 getComponentRewriter() {
return componentRewriter;
}
@Override
public boolean hasMappingDataToLoad() {
return true;
}
}
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -18,11 +18,6 @@
package com.viaversion.viabackwards.protocol.v1_12to1_11_1.rewriter;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.IntArrayTag;
import com.viaversion.nbt.tag.LongArrayTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viabackwards.api.rewriters.LegacyBlockItemRewriter;
import com.viaversion.viabackwards.protocol.v1_12to1_11_1.Protocol1_12To1_11_1;
import com.viaversion.viabackwards.protocol.v1_12to1_11_1.data.MapColorMappings1_11_1;
@@ -34,12 +29,13 @@ import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_9_3;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.IntArrayTag;
import com.viaversion.nbt.tag.LongArrayTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.protocols.v1_11_1to1_12.packet.ClientboundPackets1_12;
import com.viaversion.viaversion.protocols.v1_11_1to1_12.packet.ServerboundPackets1_12;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ServerboundPackets1_9_3;
import com.viaversion.viaversion.util.ComponentUtil;
import com.viaversion.viaversion.util.Key;
import com.viaversion.viaversion.util.SerializerVersion;
import java.util.Iterator;
import java.util.Map;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -90,12 +86,39 @@ public class BlockItemPacketRewriter1_12 extends LegacyBlockItemRewriter<Clientb
registerSetSlot(ClientboundPackets1_12.CONTAINER_SET_SLOT);
registerSetContent(ClientboundPackets1_12.CONTAINER_SET_CONTENT);
registerSetEquippedItem(ClientboundPackets1_12.SET_EQUIPPED_ITEM);
registerCustomPayloadTradeList(ClientboundPackets1_12.CUSTOM_PAYLOAD);
// Plugin message Packet -> Trading
protocol.registerClientbound(ClientboundPackets1_12.CUSTOM_PAYLOAD, new PacketHandlers() {
@Override
public void register() {
map(Types.STRING); // 0 - Channel
handler(wrapper -> {
if (wrapper.get(Types.STRING, 0).equals("MC|TrList")) {
wrapper.passthrough(Types.INT); // Passthrough Window ID
int size = wrapper.passthrough(Types.UNSIGNED_BYTE);
for (int i = 0; i < size; i++) {
wrapper.write(Types.ITEM1_8, handleItemToClient(wrapper.user(), wrapper.read(Types.ITEM1_8))); // Input Item
wrapper.write(Types.ITEM1_8, handleItemToClient(wrapper.user(), wrapper.read(Types.ITEM1_8))); // Output Item
boolean secondItem = wrapper.passthrough(Types.BOOLEAN); // Has second item
if (secondItem)
wrapper.write(Types.ITEM1_8, handleItemToClient(wrapper.user(), wrapper.read(Types.ITEM1_8))); // Second Item
wrapper.passthrough(Types.BOOLEAN); // Trade disabled
wrapper.passthrough(Types.INT); // Number of tools uses
wrapper.passthrough(Types.INT); // Maximum number of trade uses
}
}
});
}
});
protocol.registerServerbound(ServerboundPackets1_9_3.CONTAINER_CLICK, new PacketHandlers() {
@Override
public void register() {
map(Types.BYTE); // 0 - Window ID
map(Types.UNSIGNED_BYTE); // 0 - Window ID
map(Types.SHORT); // 1 - Slot
map(Types.BYTE); // 2 - Button
map(Types.SHORT); // 3 - Action number
@@ -112,9 +135,9 @@ public class BlockItemPacketRewriter1_12 extends LegacyBlockItemRewriter<Clientb
// Apologize (may happen in some cases, maybe if inventory is full?)
PacketWrapper confirm = wrapper.create(ServerboundPackets1_12.CONTAINER_ACK);
confirm.write(Types.BYTE, wrapper.get(Types.BYTE, 0));
confirm.write(Types.UNSIGNED_BYTE, wrapper.get(Types.UNSIGNED_BYTE, 0));
confirm.write(Types.SHORT, wrapper.get(Types.SHORT, 1));
confirm.write(Types.BOOLEAN, true); // Success - not used
confirm.write(Types.BOOLEAN, false); // Success - not used
wrapper.sendToServer(Protocol1_12To1_11_1.class);
wrapper.cancel();
@@ -131,21 +154,12 @@ 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().getClientWorld(Protocol1_12To1_11_1.class);
ClientWorld clientWorld = wrapper.user().get(ClientWorld.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);
handleChunk(chunk);
for (final CompoundTag tag : chunk.getBlockEntities()) {
final String id = tag.getString("id");
if (id == null) {
continue;
}
if (Key.stripMinecraftNamespace(id).equals("sign")) {
handleSignText(tag);
}
}
});
protocol.registerClientbound(ClientboundPackets1_12.BLOCK_ENTITY_DATA, new PacketHandlers() {
@@ -156,21 +170,16 @@ public class BlockItemPacketRewriter1_12 extends LegacyBlockItemRewriter<Clientb
map(Types.NAMED_COMPOUND_TAG); // 2 - NBT
handler(wrapper -> {
final short type = wrapper.get(Types.UNSIGNED_BYTE, 0);
if (type == 9) {
final CompoundTag tag = wrapper.get(Types.NAMED_COMPOUND_TAG, 0);
handleSignText(tag);
} else if (type == 11) {
// Remove bed color
// Remove bed color
if (wrapper.get(Types.UNSIGNED_BYTE, 0) == 11)
wrapper.cancel();
}
});
}
});
protocol.getEntityRewriter().filter().handler((event, data) -> {
if (data.dataType().type().equals(Types.ITEM1_8)) // Is Item
data.setValue(handleItemToClient(event.user(), (Item) data.getValue()));
protocol.getEntityRewriter().filter().handler((event, meta) -> {
if (meta.dataType().type().equals(Types.ITEM1_8)) // Is Item
meta.setValue(handleItemToClient(event.user(), (Item) meta.getValue()));
});
protocol.registerServerbound(ServerboundPackets1_9_3.CLIENT_COMMAND, new PacketHandlers() {
@@ -188,18 +197,6 @@ public class BlockItemPacketRewriter1_12 extends LegacyBlockItemRewriter<Clientb
});
}
private void handleSignText(final CompoundTag tag) {
// Push signs through component conversion, fixes https://github.com/ViaVersion/ViaBackwards/issues/835
for (int i = 0; i < 4; i++) {
final StringTag lineTag = tag.getStringTag("Text" + (i + 1));
if (lineTag == null) {
continue;
}
lineTag.setValue(ComponentUtil.convertJsonOrEmpty(lineTag.getValue(), SerializerVersion.V1_12, SerializerVersion.V1_9).toString());
}
}
@Override
public @Nullable Item handleItemToClient(UserConnection connection, Item item) {
if (item == null) return null;
@@ -238,7 +235,7 @@ public class BlockItemPacketRewriter1_12 extends LegacyBlockItemRewriter<Clientb
@Override
public @Nullable Item handleItemToServer(UserConnection connection, Item item) {
if (item == null) return null;
item = super.handleItemToServer(connection, item);
super.handleItemToServer(connection, item);
if (item.tag() != null) {
if (item.tag().remove("Via|LongArrayTags") instanceof CompoundTag tag) {
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -18,18 +18,18 @@
package com.viaversion.viabackwards.protocol.v1_12to1_11_1.rewriter;
import com.viaversion.viabackwards.api.rewriters.text.JsonNBTComponentRewriter;
import com.viaversion.viabackwards.api.rewriters.TranslatableRewriter;
import com.viaversion.viabackwards.protocol.v1_12to1_11_1.Protocol1_12To1_11_1;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.libs.gson.JsonObject;
import com.viaversion.viaversion.protocols.v1_11_1to1_12.packet.ClientboundPackets1_12;
import com.viaversion.viaversion.rewriter.text.ComponentRewriterBase;
import com.viaversion.viaversion.rewriter.ComponentRewriter;
public class ComponentRewriter1_12 extends JsonNBTComponentRewriter<ClientboundPackets1_12> {
public class ComponentRewriter1_12 extends TranslatableRewriter<ClientboundPackets1_12> {
public ComponentRewriter1_12(Protocol1_12To1_11_1 protocol) {
super(protocol, ComponentRewriterBase.ReadType.JSON);
super(protocol, ComponentRewriter.ReadType.JSON);
}
@Override
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -18,7 +18,6 @@
package com.viaversion.viabackwards.protocol.v1_12to1_11_1.rewriter;
import com.viaversion.nbt.tag.CompoundTag;
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;
@@ -31,9 +30,11 @@ import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.version.Types1_12;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.protocols.v1_11_1to1_12.packet.ClientboundPackets1_12;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ClientboundPackets1_9_3;
import com.viaversion.nbt.tag.CompoundTag;
public class EntityPacketRewriter1_12 extends LegacyEntityRewriter<ClientboundPackets1_12, Protocol1_12To1_11_1> {
@@ -82,13 +83,13 @@ public class EntityPacketRewriter1_12 extends LegacyEntityRewriter<ClientboundPa
map(Types.SHORT); // 9 - Velocity X
map(Types.SHORT); // 10 - Velocity Y
map(Types.SHORT); // 11 - Velocity Z
map(Types.ENTITY_DATA_LIST1_12, Types.ENTITY_DATA_LIST1_9); // 12 - Entity data
map(Types1_12.ENTITY_DATA_LIST); // 12 - Metadata
// Track entity
handler(getTrackerHandler());
// Rewrite entity type / data
handler(getMobSpawnRewriter1_11(Types.ENTITY_DATA_LIST1_9));
// Rewrite entity type / metadata
handler(getMobSpawnRewriter1_11(Types1_12.ENTITY_DATA_LIST));
}
});
@@ -104,9 +105,9 @@ public class EntityPacketRewriter1_12 extends LegacyEntityRewriter<ClientboundPa
map(Types.DOUBLE); // 4 - Z
map(Types.BYTE); // 5 - Yaw
map(Types.BYTE); // 6 - Pitch
map(Types.ENTITY_DATA_LIST1_12, Types.ENTITY_DATA_LIST1_9); // 7 - Entity data list
map(Types1_12.ENTITY_DATA_LIST); // 7 - Metadata list
handler(getTrackerAndDataHandler(Types.ENTITY_DATA_LIST1_9, EntityTypes1_12.EntityType.PLAYER));
handler(getTrackerAndMetaHandler(Types1_12.ENTITY_DATA_LIST, EntityTypes1_12.EntityType.PLAYER));
}
});
@@ -117,8 +118,9 @@ public class EntityPacketRewriter1_12 extends LegacyEntityRewriter<ClientboundPa
map(Types.UNSIGNED_BYTE); // 1 - Gamemode
map(Types.INT); // 2 - Dimension
handler(getTrackerHandler(EntityTypes1_12.EntityType.PLAYER, Types.INT));
handler(getDimensionHandler(1));
handler(getPlayerTrackerHandler());
handler(wrapper -> {
ShoulderTracker tracker = wrapper.user().get(ShoulderTracker.class);
@@ -140,7 +142,7 @@ public class EntityPacketRewriter1_12 extends LegacyEntityRewriter<ClientboundPa
registerRespawn(ClientboundPackets1_12.RESPAWN);
registerRemoveEntities(ClientboundPackets1_12.REMOVE_ENTITIES);
registerSetEntityData(ClientboundPackets1_12.SET_ENTITY_DATA, Types.ENTITY_DATA_LIST1_12, Types.ENTITY_DATA_LIST1_9);
registerSetEntityData(ClientboundPackets1_12.SET_ENTITY_DATA, Types1_12.ENTITY_DATA_LIST);
protocol.registerClientbound(ClientboundPackets1_12.UPDATE_ATTRIBUTES, new PacketHandlers() {
@Override
@@ -184,42 +186,42 @@ public class EntityPacketRewriter1_12 extends LegacyEntityRewriter<ClientboundPa
@Override
protected void registerRewrites() {
mapEntityTypeWithData(EntityTypes1_12.EntityType.PARROT, EntityTypes1_12.EntityType.BAT).plainName().spawnEntityData(storage -> storage.add(new EntityData(12, EntityDataTypes1_12.BYTE, (byte) 0x00)));
mapEntityTypeWithData(EntityTypes1_12.EntityType.PARROT, EntityTypes1_12.EntityType.BAT).plainName().spawnMetadata(storage -> storage.add(new EntityData(12, EntityDataTypes1_12.BYTE, (byte) 0x00)));
mapEntityTypeWithData(EntityTypes1_12.EntityType.ILLUSIONER, EntityTypes1_12.EntityType.EVOKER).plainName();
filter().handler((event, data) -> {
if (data.dataType() == EntityDataTypes1_12.COMPONENT) {
protocol.getComponentRewriter().processText(event.user(), (JsonElement) data.getValue());
filter().handler((event, meta) -> {
if (meta.dataType() == EntityDataTypes1_12.COMPONENT) {
protocol.getComponentRewriter().processText(event.user(), (JsonElement) meta.getValue());
}
});
// Handle Illager
filter().type(EntityTypes1_12.EntityType.EVOKER).removeIndex(12);
filter().type(EntityTypes1_12.EntityType.ILLUSIONER).index(0).handler((event, data) -> {
byte mask = (byte) data.getValue();
filter().type(EntityTypes1_12.EntityType.ILLUSIONER).index(0).handler((event, meta) -> {
byte mask = (byte) meta.getValue();
if ((mask & 0x20) == 0x20) {
mask &= ~0x20;
}
data.setValue(mask);
meta.setValue(mask);
});
// Create Parrot storage
filter().type(EntityTypes1_12.EntityType.PARROT).handler((event, data) -> {
StoredEntityData entityData = storedEntityData(event);
if (!entityData.has(ParrotStorage.class)) {
entityData.put(new ParrotStorage());
filter().type(EntityTypes1_12.EntityType.PARROT).handler((event, meta) -> {
StoredEntityData data = storedEntityData(event);
if (!data.has(ParrotStorage.class)) {
data.put(new ParrotStorage());
}
});
// Parrot remove animal entity data
// Parrot remove animal metadata
filter().type(EntityTypes1_12.EntityType.PARROT).cancel(12); // Is baby
filter().type(EntityTypes1_12.EntityType.PARROT).index(13).handler((event, data) -> {
StoredEntityData entityData = storedEntityData(event);
ParrotStorage storage = entityData.get(ParrotStorage.class);
boolean isSitting = (((byte) data.getValue()) & 0x01) == 0x01;
boolean isTamed = (((byte) data.getValue()) & 0x04) == 0x04;
filter().type(EntityTypes1_12.EntityType.PARROT).index(13).handler((event, meta) -> {
StoredEntityData data = storedEntityData(event);
ParrotStorage storage = data.get(ParrotStorage.class);
boolean isSitting = (((byte) meta.getValue()) & 0x01) == 0x01;
boolean isTamed = (((byte) meta.getValue()) & 0x04) == 0x04;
if (!storage.isTamed() && isTamed) {
// TODO do something to let the user know it's done
@@ -229,11 +231,11 @@ public class EntityPacketRewriter1_12 extends LegacyEntityRewriter<ClientboundPa
if (isSitting) {
event.setIndex(12);
data.setValue((byte) 0x01);
meta.setValue((byte) 0x01);
storage.setSitting(true);
} else if (storage.isSitting()) {
event.setIndex(12);
data.setValue((byte) 0x00);
meta.setValue((byte) 0x00);
storage.setSitting(false);
} else {
event.cancel();
@@ -243,8 +245,8 @@ public class EntityPacketRewriter1_12 extends LegacyEntityRewriter<ClientboundPa
filter().type(EntityTypes1_12.EntityType.PARROT).cancel(15); // Variant
// Left shoulder entity data
filter().type(EntityTypes1_12.EntityType.PLAYER).index(15).handler((event, data) -> {
CompoundTag tag = (CompoundTag) data.getValue();
filter().type(EntityTypes1_12.EntityType.PLAYER).index(15).handler((event, meta) -> {
CompoundTag tag = (CompoundTag) meta.getValue();
ShoulderTracker tracker = event.user().get(ShoulderTracker.class);
if (tag.isEmpty() && tracker.getLeftShoulder() != null) {
@@ -262,7 +264,7 @@ public class EntityPacketRewriter1_12 extends LegacyEntityRewriter<ClientboundPa
});
// Right shoulder entity data
filter().type(EntityTypes1_12.EntityType.PLAYER).index(16).handler((event, data) -> {
filter().type(EntityTypes1_12.EntityType.PLAYER).index(16).handler((event, meta) -> {
CompoundTag tag = (CompoundTag) event.data().getValue();
ShoulderTracker tracker = event.user().get(ShoulderTracker.class);
@@ -283,11 +285,11 @@ public class EntityPacketRewriter1_12 extends LegacyEntityRewriter<ClientboundPa
@Override
public EntityType typeFromId(int typeId) {
return EntityTypes1_12.EntityType.findById(typeId);
return EntityTypes1_12.getTypeFromId(typeId, false);
}
@Override
public EntityType objectTypeFromId(int typeId, int data) {
return EntityTypes1_12.ObjectType.getEntityType(typeId, data);
public EntityType objectTypeFromId(int typeId) {
return EntityTypes1_12.getTypeFromId(typeId, true);
}
}
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -21,6 +21,7 @@ package com.viaversion.viabackwards.protocol.v1_12to1_11_1.rewriter;
import com.viaversion.viabackwards.api.rewriters.LegacySoundRewriter;
import com.viaversion.viabackwards.protocol.v1_12to1_11_1.Protocol1_12To1_11_1;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_11_1to1_12.packet.ClientboundPackets1_12;
@@ -32,7 +33,20 @@ public class SoundPacketRewriter1_12 extends LegacySoundRewriter<Protocol1_12To1
@Override
protected void registerPackets() {
protocol.replaceClientbound(ClientboundPackets1_12.SOUND, new PacketHandlers() {
protocol.registerClientbound(ClientboundPackets1_12.CUSTOM_SOUND, new PacketHandlers() {
@Override
public void register() {
map(Types.STRING); // 0 - Sound name
map(Types.VAR_INT); // 1 - Sound Category
map(Types.INT); // 2 - x
map(Types.INT); // 3 - y
map(Types.INT); // 4 - z
map(Types.FLOAT); // 5 - Volume
map(Types.FLOAT); // 6 - Pitch
}
});
protocol.registerClientbound(ClientboundPackets1_12.SOUND, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // 0 - Sound name
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -1,6 +1,6 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 ViaVersion and contributors
* Copyright (C) 2016-2024 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
@@ -20,7 +20,7 @@ package com.viaversion.viabackwards.protocol.v1_13_1to1_13;
import com.viaversion.viabackwards.ViaBackwards;
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.api.rewriters.TranslatableRewriter;
import com.viaversion.viabackwards.protocol.v1_13_1to1_13.rewriter.CommandRewriter1_13_1;
import com.viaversion.viabackwards.protocol.v1_13_1to1_13.rewriter.EntityPacketRewriter1_13_1;
import com.viaversion.viabackwards.protocol.v1_13_1to1_13.rewriter.ItemPacketRewriter1_13_1;
@@ -40,9 +40,9 @@ import com.viaversion.viaversion.libs.gson.JsonObject;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.packet.ClientboundPackets1_13;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.packet.ServerboundPackets1_13;
import com.viaversion.viaversion.protocols.v1_13to1_13_1.Protocol1_13To1_13_1;
import com.viaversion.viaversion.rewriter.ParticleRewriter;
import com.viaversion.viaversion.rewriter.ComponentRewriter;
import com.viaversion.viaversion.rewriter.StatisticsRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
import com.viaversion.viaversion.rewriter.text.ComponentRewriterBase;
import com.viaversion.viaversion.util.ComponentUtil;
public class Protocol1_13_1To1_13 extends BackwardsProtocol<ClientboundPackets1_13, ClientboundPackets1_13, ServerboundPackets1_13, ServerboundPackets1_13> {
@@ -50,8 +50,7 @@ public class Protocol1_13_1To1_13 extends BackwardsProtocol<ClientboundPackets1_
public static final BackwardsMappingData MAPPINGS = new BackwardsMappingData("1.13.2", "1.13", Protocol1_13To1_13_1.class);
private final EntityPacketRewriter1_13_1 entityRewriter = new EntityPacketRewriter1_13_1(this);
private final ItemPacketRewriter1_13_1 itemRewriter = new ItemPacketRewriter1_13_1(this);
private final ParticleRewriter<ClientboundPackets1_13> particleRewriter = new ParticleRewriter<>(this);
private final JsonNBTComponentRewriter<ClientboundPackets1_13> translatableRewriter = new JsonNBTComponentRewriter<>(this, ComponentRewriterBase.ReadType.JSON);
private final TranslatableRewriter<ClientboundPackets1_13> translatableRewriter = new TranslatableRewriter<>(this, ComponentRewriter.ReadType.JSON);
private final TagRewriter<ClientboundPackets1_13> tagRewriter = new TagRewriter<>(this);
public Protocol1_13_1To1_13() {
@@ -64,6 +63,13 @@ public class Protocol1_13_1To1_13 extends BackwardsProtocol<ClientboundPackets1_
WorldPacketRewriter1_13_1.register(this);
translatableRewriter.registerComponentPacket(ClientboundPackets1_13.CHAT);
translatableRewriter.registerPlayerCombat(ClientboundPackets1_13.PLAYER_COMBAT);
translatableRewriter.registerComponentPacket(ClientboundPackets1_13.DISCONNECT);
translatableRewriter.registerTabList(ClientboundPackets1_13.TAB_LIST);
translatableRewriter.registerTitle(ClientboundPackets1_13.SET_TITLES);
translatableRewriter.registerPing();
new CommandRewriter1_13_1(this).registerDeclareCommands(ClientboundPackets1_13.COMMANDS);
registerServerbound(ServerboundPackets1_13.COMMAND_SUGGESTION, new PacketHandlers() {
@@ -80,11 +86,16 @@ public class Protocol1_13_1To1_13 extends BackwardsProtocol<ClientboundPackets1_
}
});
registerServerbound(ServerboundPackets1_13.EDIT_BOOK, wrapper -> {
final Item item = itemRewriter.handleItemToServer(wrapper.user(), wrapper.read(Types.ITEM1_13));
wrapper.write(Types.ITEM1_13, item);
wrapper.passthrough(Types.BOOLEAN);
wrapper.write(Types.VAR_INT, 0);
registerServerbound(ServerboundPackets1_13.EDIT_BOOK, new PacketHandlers() {
@Override
public void register() {
map(Types.ITEM1_13);
map(Types.BOOLEAN);
handler(wrapper -> {
itemRewriter.handleItemToServer(wrapper.user(), wrapper.get(Types.ITEM1_13, 0));
wrapper.write(Types.VAR_INT, 0);
});
}
});
registerClientbound(ClientboundPackets1_13.OPEN_SCREEN, new PacketHandlers() {
@@ -132,7 +143,7 @@ public class Protocol1_13_1To1_13 extends BackwardsProtocol<ClientboundPackets1_
}
});
replaceClientbound(ClientboundPackets1_13.BOSS_EVENT, new PacketHandlers() {
registerClientbound(ClientboundPackets1_13.BOSS_EVENT, new PacketHandlers() {
@Override
public void register() {
map(Types.UUID);
@@ -154,13 +165,48 @@ public class Protocol1_13_1To1_13 extends BackwardsProtocol<ClientboundPackets1_
}
});
registerClientbound(ClientboundPackets1_13.UPDATE_ADVANCEMENTS, wrapper -> {
wrapper.passthrough(Types.BOOLEAN); // Reset/clear
int size = wrapper.passthrough(Types.VAR_INT); // Mapping size
for (int i = 0; i < size; i++) {
wrapper.passthrough(Types.STRING); // Identifier
wrapper.passthrough(Types.OPTIONAL_STRING); // Parent
// Display data
if (wrapper.passthrough(Types.BOOLEAN)) {
wrapper.passthrough(Types.COMPONENT); // Title
wrapper.passthrough(Types.COMPONENT); // Description
Item icon = wrapper.passthrough(Types.ITEM1_13);
itemRewriter.handleItemToClient(wrapper.user(), icon);
wrapper.passthrough(Types.VAR_INT); // Frame type
int flags = wrapper.passthrough(Types.INT); // Flags
if ((flags & 1) != 0)
wrapper.passthrough(Types.STRING); // Background texture
wrapper.passthrough(Types.FLOAT); // X
wrapper.passthrough(Types.FLOAT); // Y
}
wrapper.passthrough(Types.STRING_ARRAY); // Criteria
int arrayLength = wrapper.passthrough(Types.VAR_INT);
for (int array = 0; array < arrayLength; array++) {
wrapper.passthrough(Types.STRING_ARRAY); // String array
}
}
});
tagRewriter.register(ClientboundPackets1_13.UPDATE_TAGS, RegistryType.ITEM);
new StatisticsRewriter<>(this).register(ClientboundPackets1_13.AWARD_STATS);
}
@Override
public void init(UserConnection user) {
user.addEntityTracker(getClass(), new EntityTrackerBase(user, EntityTypes1_13.EntityType.PLAYER));
user.addClientWorld(getClass(), new ClientWorld());
if (!user.has(ClientWorld.class)) {
user.put(new ClientWorld());
}
}
@Override
@@ -178,17 +224,7 @@ public class Protocol1_13_1To1_13 extends BackwardsProtocol<ClientboundPackets1_
return itemRewriter;
}
@Override
public ParticleRewriter<ClientboundPackets1_13> getParticleRewriter() {
return particleRewriter;
}
@Override
public JsonNBTComponentRewriter<ClientboundPackets1_13> getComponentRewriter() {
return translatableRewriter;
}
public JsonNBTComponentRewriter<ClientboundPackets1_13> translatableRewriter() {
public TranslatableRewriter<ClientboundPackets1_13> translatableRewriter() {
return translatableRewriter;
}
Loaded 100 of 376 files, more files were not shown because too many files have changed in this diff. Show more