Compare commits

...
102 Commits
Author SHA1 Message Date
Nassim Jahnke 76b98eb396 5.7.0 Release 2025-12-29 12:48:01 +01:00
Nassim Jahnke b33221b95c Don't throw on bad entity data in 1.14->1.13 2025-12-28 10:33:03 +01:00
Nassim Jahnke 8ce26b1353 Bump to 5.7.0-SNAPSHOT and update VV usage 2025-12-26 21:57:06 +01:00
9a79f9e217 Delay mannequin spawning for proper skin application (#1158)
Co-authored-by: FlorianMichael <git@florianmichael.de>
Co-authored-by: Nassim Jahnke <nassim@njahnke.dev>
2025-12-26 21:50:10 +01:00
Nassim Jahnke 44476f2468 Replace toIntExact with clamp
Fixes #1159
2025-12-25 09:10:09 +01:00
David Lüdtke 54655e34e7 Fix world border lerp size set in ticks instead of millis (#1156) 2025-12-23 09:55:03 +01:00
Nassim Jahnke 863258df4e Correct overworld fog color 2025-12-21 16:55:01 +01:00
Nassim Jahnke 8a5fce2d2e Put set_objective and set_score packets through component rewriter
Fixes #1155
2025-12-21 15:53:03 +01:00
Nassim Jahnke 5374c3b626 Fix avatar arm handling in 1.21.11->1.21.9 2025-12-20 22:53:24 +01:00
FlorianMichael 96e0d85bc0 Map pale oak shelf to pale oak planks in 1.21.9->1.21.7 (#1154) 2025-12-20 16:38:29 +01:00
Kichura 84576d1d95 [ci skip] Set CI timeout to 30 mins (#1153) 2025-12-20 15:46:05 +01:00
Nassim Jahnke c6f0717ad5 Convert compact sound list to single entry in registry data 2025-12-20 12:00:16 +01:00
Nassim Jahnke 395bebac62 Remove tamable entity data from nautilus
Fixes #1152
2025-12-14 09:25:07 +01:00
FlorianMichael 6d19ad3b81 [ci skip] Include the newest ViaProxy version from 3.0.0 to 4.0.0 (#1151) 2025-12-13 19:59:23 +01:00
Nassim Jahnke 38080fc5cc Remove 1.21.11 registries 2025-12-13 12:04:12 +01:00
FlorianMichael 285dcdd81f Add ViaBackwardsPlatform#init with config instance (#1149) 2025-12-13 11:30:04 +01:00
Nassim Jahnke 1f5fd88fef 5.6.0 Release 2025-12-12 16:00:57 +01:00
Nassim Jahnke 531f7d078e Remove nautilus variant in 1.21.11 component rewriter 2025-12-12 16:00:57 +01:00
Nassim Jahnke 2806671813 Add translatables 2025-12-12 16:00:56 +01:00
Nassim Jahnke 7634a7ec7a Add fog effects to dimensions and biomes 2025-12-12 16:00:56 +01:00
Nassim Jahnke 8cd5bd3368 1.21.11-pre4 2025-12-12 16:00:56 +01:00
Nassim Jahnke 0735e4afb5 Handle biome color type changes 2025-12-12 16:00:56 +01:00
Nassim Jahnke 3568eee8f2 Back up new item data 2025-12-12 16:00:55 +01:00
Nassim Jahnke e694b3532a 1.21.11-pre1 2025-12-12 16:00:55 +01:00
Nassim Jahnke 2bcf79c501 25w46a 2025-12-12 16:00:55 +01:00
Nassim Jahnke 7ded34c55e 25w45a 2025-12-12 16:00:55 +01:00
Nassim Jahnke 3bdeed8a9f 25w43a 2025-12-12 16:00:54 +01:00
Nassim Jahnke 30df707369 WIP 25w42a 2025-12-12 16:00:54 +01:00
github-actions[bot]andgradle-update-robot cf8058016c Update Gradle Wrapper from 9.2.0 to 9.2.1 (#1141)
Signed-off-by: gradle-update-robot <gradle-update-robot@regolo.cc>
Co-authored-by: gradle-update-robot <gradle-update-robot@regolo.cc>
2025-12-12 15:58:35 +01:00
Kichura 3468b0a785 Update workflow configs (#1144) 2025-12-06 20:34:00 +01:00
tmpod d273b06e05 Fix text components in signs not being rewritten in 1.21.9→1.21.7 (#1147) 2025-12-06 20:14:36 +01:00
dependabot[bot] 4f561ba4a7 Bump actions/checkout from 5 to 6 (#1142)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-24 21:58:08 +01:00
Nanashi.andFlorianMichael 0a5035d209 More dialog emulation fixes (#1131)
Co-authored-by: FlorianMichael <florian.michael07@gmail.com>
2025-11-24 21:57:46 +01:00
Nassim Jahnke 609b657c68 Handle set_player_team text component changes 2025-11-23 19:47:05 +01:00
Nassim Jahnke 5885074fcd [ci skip] Update issue template 2025-11-18 19:50:03 +01:00
Nassim Jahnke d499918e4b Don't cancel full equipment containing saddle in 1.21.5->1.21.4
Plugins manually sending equipment packets may include saddles for entities that shouldn't have saddle equipment, though the client will ignore them
Closes #1140
2025-11-18 19:33:34 +01:00
FlorianMichael 17d7b4873f Set accepted = true in 1.12->1.11.1 shift click fix (#1139) 2025-11-16 19:04:17 +01:00
FlorianMichael 38243bad78 [ci skip] Update ViaFabricPlus jars path (#1133) 2025-11-12 16:58:40 +01:00
Nassim Jahnke 50577abbb5 Fix jukebox_playable backup
Fixes #1130
2025-11-08 10:45:51 +01:00
github-actions[bot]andgradle-update-robot 277de42948 Update Gradle Wrapper from 9.1.0 to 9.2.0 (#1129)
Signed-off-by: gradle-update-robot <gradle-update-robot@regolo.cc>
Co-authored-by: gradle-update-robot <gradle-update-robot@regolo.cc>
2025-11-03 16:52:13 +01:00
FlorianMichael 4c26915fdf Fix text display y offset in 1.19.4->1.19.3 (#1128) 2025-11-01 15:07:36 +01:00
FlorianMichael 7c98b75543 Cancel sign editor open packet for invalid positions in 1.21.2->1.21 (#1099) 2025-11-01 14:59:13 +01:00
Nassim Jahnke 7d39bcc365 Fix regression in cancelling new 1.21.5 registries 2025-10-28 21:11:26 +01:00
Nassim Jahnke 85688beba8 Go through normal registry handling for removed registries in 1.21.5->1.21.4 2025-10-20 14:28:26 +02:00
FlorianMichael fd16c4469c Add option to disable dialog handling in 1.21.6->1.21.5 (#1116) 2025-10-18 18:34:23 +02:00
Nassim Jahnke a37605e920 Update VV usage 2025-10-14 17:59:53 +02:00
FlorianMichael 1d4e41f867 Fix custom action button in notice dialogs not added in 1.21.6->1.21.5 (#1117) 2025-10-13 20:30:47 +02:00
Nassim Jahnke 1f4acbbc60 5.5.1 Release 2025-10-12 18:43:52 +02:00
Nassim Jahnke eff547019c Remove instrument and jukebox playable in show_item hovers in 1.21.5->1.21.4 2025-10-12 18:43:17 +02:00
Nassim Jahnke bbb52f575a Add --refresh-dependencies to publish workflow 2025-10-07 16:14:10 +02:00
Nassim Jahnke 74ad2d15fb Update VV usage again 2025-10-07 15:39:19 +02:00
Nassim Jahnke 024fe774f4 Update VV usage 2025-10-07 15:26:05 +02:00
dependabot[bot] 0df9c50251 Bump gradle/actions from 4 to 5 (#1115)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-06 23:37:26 +02:00
Nassim Jahnke e8637e5753 Update sound mapping format
VV now includes full sound name mappings, so VB can map them via registry indexes and doesn't need the extra sound file anymore
2025-10-06 20:44:10 +02:00
Nassim Jahnke 64b454de6f Fix world border scale in 1.21.9->1.21.7 2025-10-05 22:20:44 +02:00
FlorianMichael 433f46e34e Handle DEBUG_SAMPLE_SUBSCRIPTION structure change in 1.21.9 ->1.21.7 (#1111) 2025-10-05 08:49:11 +02:00
Nassim Jahnke fbe6a67750 Fix inverted hidden components checks in 1.21.5->1.21.4
Fixes #1110
2025-10-04 11:02:49 +02:00
Nassim Jahnke 454e97c844 Don't remove font
Closes #1109
2025-10-04 10:08:01 +02:00
FlorianMichael fccea9b55d Throw out object components in 1.21.9->1.21.7 (#1108) 2025-10-03 21:42:31 +02:00
Nassim Jahnke 917427c940 5.5.0 Release 2025-10-03 13:48:04 +02:00
Nassim Jahnke b7ddc108f5 Prepare for the release later 2025-10-03 08:18:06 +02:00
FlorianMichael db65302112 Write empty tag if no shoulder data is present 2025-10-02 18:13:42 +02:00
FlorianMichael 795b195690 Use translation keys for code of conduct dialog 2025-10-02 14:25:23 +02:00
Nassim Jahnke b7c42f9b2e Cancel mannequin data from unknown entities 2025-09-30 18:29:04 +02:00
Nassim Jahnke 1a0c79c46a Add 1.21.9 translations 2025-09-30 18:05:04 +02:00
Nassim Jahnke 95d809f53a Update item_model use 2025-09-30 14:37:36 +02:00
FlorianMichael f8c249f2c2 Only register open screen translatable rewriter 2025-09-26 20:41:01 +02:00
FlorianMichael fe890fa59e Handle relative player rotations 2025-09-25 17:03:31 +02:00
Nassim Jahnke 9806afed99 Handle SET_DEFAULT_SPAW_POSITION change 2025-09-25 16:59:57 +02:00
Nassim Jahnke 432c669daf 1.21.9-pre1 2025-09-25 16:59:57 +02:00
Nassim Jahnke 838d83897b Start emulating mannequins via players 2025-09-25 16:59:57 +02:00
Nassim Jahnke e10c73138d 25w37a 2025-09-25 16:59:57 +02:00
FlorianMichael e0892faf13 Show server code of conduct as dialog screen 2025-09-25 16:59:57 +02:00
Nassim Jahnke c03cb66bbd wip 25w36a/b 2025-09-25 16:59:56 +02:00
Nassim Jahnke ea1d86642e 25w35a 2025-09-25 16:59:56 +02:00
Nassim Jahnke 6c9c7288c4 25w34b 2025-09-25 16:59:56 +02:00
Nassim Jahnke 8dab7f7284 25w33a 2025-09-25 16:59:56 +02:00
Nassim Jahnke f0c16003e0 25w32a 2025-09-25 16:59:56 +02:00
Nassim Jahnke 4d4b18b80e 25w31a 2025-09-25 16:59:56 +02:00
Nassim Jahnke 99abab0d62 Update dependencies 2025-09-20 22:39:48 +02:00
EnZaXD f7656fb45f Always remap show_dialog/custom click events (#1104) 2025-09-18 20:03:13 +02:00
EnZaXD 6a440aaeda Handle signed chat commands as well for custom click events (#1103) 2025-09-18 20:02:42 +02:00
EnZaXD 075ca7044d Make some functions protected in ChestDialogViewProvider (#1101) 2025-09-16 21:31:56 +02:00
EnZaXD a8cd653a7a Remove serialize versions from item hasher (#1102) 2025-09-16 21:31:51 +02:00
EnZaXD 191dd24117 Add missing sound name handlers for biomes (#1098) 2025-09-13 10:08:02 +02:00
EnZaXD 6ad05d8bc2 Null check chest dialog storage in ChestDialogViewProvider#closeDialog (#1097) 2025-09-12 21:14:54 +02:00
Nassim Jahnke c5a2a6ae6e Reset player position storage on respawn 2025-09-03 17:11:41 +02:00
EnZaXD 31f7f4edc1 Rename ProtocolRunnable, always submit tick logic into event loop (#1093) 2025-09-03 17:08:08 +02:00
purpurcof b2a2712949 Fix reading any NBT type for SERVER_LINKS (#1092) 2025-09-01 17:31:05 +02:00
EnZaXD 7bd6a849a3 Fix SOUND_ENTITY remap not working for the player in 1.14->1.13.2 (#1086) 2025-09-01 16:30:33 +02:00
riku6460 473b4af0d0 Add missing check whether the player is set in client tick emulation 1.21.2->1.21 (#1090) 2025-08-29 17:16:07 +02:00
dependabot[bot] b7c8891497 Bump actions/setup-java from 4 to 5 (#1089)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-26 15:36:00 +02:00
Nassim Jahnke be5344b3e4 Reassign item on handleItemToClient calls
Needed in rewriters before 1.20 with a recent change; the rest weren't technically necessary
2025-08-22 20:10:10 +02:00
Nassim Jahnke cc4ea71722 Fix custom name in banners etc. in 1.21.5->1.21.4 2025-08-17 16:37:16 +02:00
EnZaXD f288f2d716 Add dialog styling options (#1072) 2025-08-17 08:16:42 +02:00
dependabot[bot] 61a4cead72 [ci skip] Bump actions/checkout from 4 to 5 (#1080)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-12 08:22:46 +02:00
EnZaXDandNassim Jahnke b9ead8109f [ci skip] Gradle & Shadow 9.0.0; Rewrite .gitignore file (#1075)
Co-authored-by: Nassim Jahnke <nassim@njahnke.dev>
2025-08-09 14:17:40 +02:00
EnZaXD 12cde18a3d Use ViaBackwardsPlatform#getLogger for protocol logger creation (#1078) 2025-08-08 16:03:40 +02:00
EnZaXD b8adbde876 Add statistic mappings for 1.21.6->1.21.5 (#1077) 2025-08-03 09:34:06 +02:00
EnZaXD 6faf407cc9 Use SerializerVersion.V1_21_6 in 1.21.6->1.21.5 (#1073) 2025-07-31 13:05:01 +02:00
EnZaXD f3f19dfd4e Pass dialog title through component conversion in 1.21.6->.5 (#1074) 2025-07-31 13:04:53 +02:00
EnZaXD 80ed7e1e75 Handle HIDE_ADDITIONAL_TOOLTIP in chat items in 1.21.5->1.21.4 (#1068) 2025-07-31 13:04:42 +02:00
145 changed files with 3579 additions and 1986 deletions

No files matched your search

+2 -11
View File
@@ -48,21 +48,12 @@ 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
2. Place a sign
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."
3. The sign text disappears
validations:
required: true
+3 -1
View File
@@ -1,6 +1,8 @@
version: 2
updates:
- package-ecosystem: "github-actions"
cooldown:
default-days: 7
directory: "/"
schedule:
interval: "weekly"
interval: "monthly"
+9 -8
View File
@@ -1,22 +1,23 @@
name: Java CI with Gradle
on: [push, pull_request]
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@v4
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # 6.0.0
with:
persist-credentials: false
- name: Set up Gradle
uses: gradle/actions/setup-gradle@v4
uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # 5.0.0
- name: Set up JDK 17
uses: actions/setup-java@v4
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # 5.0.0
with:
distribution: 'temurin'
java-version: 17
+9 -5
View File
@@ -6,25 +6,29 @@ on:
- dev
workflow_dispatch:
permissions:
contents: read
jobs:
publish:
if: github.repository_owner == 'ViaVersion'
runs-on: ubuntu-24.04
timeout-minutes: 30
steps:
- name: Checkout Repository
uses: actions/checkout@v4
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # 6.0.0
with:
persist-credentials: false
- name: Set up Gradle
uses: gradle/actions/setup-gradle@v4
uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # 5.0.0
- name: Set up JDK 17
uses: actions/setup-java@v4
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # 5.0.0
with:
distribution: 'temurin'
java-version: 17
check-latest: true
- name: Build
run: ./gradlew build
- name: Build with Gradle
run: ./gradlew build --refresh-dependencies
- name: Publish to Hangar
env:
HANGAR_TOKEN: ${{ secrets.HANGAR_TOKEN }}
+8 -2
View File
@@ -4,13 +4,19 @@ on:
schedule:
- cron: "0 0 * * 0"
permissions:
contents: write
pull-requests: write
jobs:
update-gradle-wrapper:
runs-on: ubuntu-24.04
timeout-minutes: 30
steps:
- name: Checkout Repository
uses: actions/checkout@v4
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # 6.0.0
with:
fetch-depth: 0
persist-credentials: false
- name: Update Gradle Wrapper
uses: gradle-update/update-gradle-wrapper-action@v2
uses: gradle-update/update-gradle-wrapper-action@512b1875f3b6270828abfe77b247d5895a2da1e5 # 2.1.0
+19 -98
View File
@@ -1,115 +1,36 @@
### Java files ###
*.class
# Gradle
# Package Files
#*.jar
*.war
*.ear
.gradle/
build/
out/
classes/
.kotlin/
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
# Eclipse
*.launch
# Idea
### Intellij ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm
# Ignore project files
*.iml
# Ignore IDEA directory
.idea/*
.idea/
!.idea/copyright/*
!.idea/scopes/*
# Include the project's dictionary
!.idea/dictionaries/
!.idea/dictionaries/*
# File-based project format:
*.iml
*.ipr
*.iws
### Plugin-specific files: ###
# IntelliJ
/out/
# 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/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.settings/
.loadpath
# Eclipse Core
.vscode/
bin/
.classpath
.project
# External tool builders
.externalToolBuilders/
# macOS
# Locally stored "Eclipse launch configurations"
*.launch
# CDT-specific
.cproject
# 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/
### MacOS ###
.DS_Store
### Run Folder (ViaProxy) ###
common/run/
# Misc
run/
+1 -1
View File
@@ -12,7 +12,7 @@ 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 `ViaFabricPlus/jars` folder
- in **ViaFabricPlus**, put ViaBackwards into the `config/viafabriclus/jars` folder
See [HERE](https://viaversion.com) for an overview of the different Via* projects.
+3 -1
View File
@@ -8,5 +8,7 @@ repositories {
dependencies {
// version must be manually kept in sync with the one in root project settings.gradle.kts
implementation("com.gradleup.shadow", "shadow-gradle-plugin", "8.3.8")
implementation("com.gradleup.shadow:shadow-gradle-plugin:9.1.0")
// A nice no-conflict comment for patching in downgrading
}
@@ -8,7 +8,7 @@ tasks {
val ver = project.version.toString()
val desc = project.description
filesMatching(listOf("plugin.yml", "META-INF/sponge_plugins.json", "fabric.mod.json")) {
expand("version" to ver, "description" to desc)
expand(mapOf("version" to ver, "description" to desc))
}
}
javadoc {
@@ -18,6 +18,7 @@ tasks {
compileJava {
options.encoding = Charsets.UTF_8.name()
options.compilerArgs.addAll(listOf("-nowarn", "-Xlint:-unchecked", "-Xlint:-deprecation"))
options.isFork = true
}
}
@@ -14,6 +14,7 @@ tasks {
from(project.rootProject.file("LICENSE"))
}
val shadowJar = named<ShadowJar>("shadowJar") {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
archiveClassifier.set("")
configureRelocations()
}
+1 -1
View File
@@ -30,7 +30,7 @@ java {
val prepareViaProxyFiles by tasks.registering(Copy::class) {
dependsOn(project.tasks.shadowJar)
from(project.tasks.shadowJar.get().archiveFile.get().asFile)
from(project.tasks.shadowJar.map { it.archiveFile.get().asFile })
into(layout.projectDirectory.dir("run/jars"))
val projectName = project.name
@@ -17,7 +17,10 @@
*/
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;
@@ -41,6 +44,8 @@ public class ViaBackwardsConfig extends Config implements com.viaversion.viaback
private boolean mapCustomModelData;
private boolean mapDisplayEntities;
private boolean suppressEmulationWarnings;
private boolean dialogsViaChests;
private DialogStyleConfig dialogStyleConfig;
public ViaBackwardsConfig(File configFile, Logger logger) {
super(configFile, logger);
@@ -66,6 +71,30 @@ public class ViaBackwardsConfig extends Config implements com.viaversion.viaback
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"));
}
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
@@ -133,6 +162,16 @@ public class ViaBackwardsConfig extends Config implements com.viaversion.viaback
return suppressEmulationWarnings;
}
@Override
public boolean dialogsViaChests() {
return dialogsViaChests;
}
@Override
public DialogStyleConfig dialogStyleConfig() {
return dialogStyleConfig;
}
@Override
public URL getDefaultConfigURL() {
return getClass().getClassLoader().getResource("assets/viabackwards/config.yml");
@@ -19,11 +19,13 @@ package com.viaversion.viabackwards.api;
import com.viaversion.viabackwards.api.data.BackwardsMappingData;
import com.viaversion.viabackwards.api.rewriters.text.TranslatableRewriter;
import com.viaversion.viabackwards.utils.BackwardsProtocolLogger;
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>
@@ -54,6 +56,11 @@ public abstract class BackwardsProtocol<CU extends ClientboundPacketType, CM ext
}
}
@Override
protected ProtocolLogger createLogger() {
return new BackwardsProtocolLogger(getClass());
}
@Override
public boolean hasMappingDataToLoad() {
// Manually load them later, since they depend on VV's mappings
@@ -0,0 +1,25 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viabackwards.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) {
}
@@ -112,4 +112,18 @@ public interface ViaBackwardsConfig extends Config {
* @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();
}
@@ -55,6 +55,7 @@ import com.viaversion.viabackwards.protocol.v1_20_2to1_20.Protocol1_20_2To1_20;
import com.viaversion.viabackwards.protocol.v1_20_3to1_20_2.Protocol1_20_3To1_20_2;
import com.viaversion.viabackwards.protocol.v1_20_5to1_20_3.Protocol1_20_5To1_20_3;
import com.viaversion.viabackwards.protocol.v1_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;
@@ -62,6 +63,7 @@ import com.viaversion.viabackwards.protocol.v1_21_5to1_21_4.Protocol1_21_5To1_21
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_9_3to1_9_1.Protocol1_9_3To1_9_1;
@@ -76,13 +78,16 @@ import java.util.logging.Logger;
public interface ViaBackwardsPlatform {
String MINIMUM_VV_VERSION = "5.4.0";
String MINIMUM_VV_VERSION = "5.7.0";
default void init(final File configFile) {
init(new ViaBackwardsConfig(configFile, getLogger()));
}
/**
* Initialize ViaBackwards.
*/
default void init(final File configFile) {
ViaBackwardsConfig config = new ViaBackwardsConfig(configFile, getLogger());
default void init(final ViaBackwardsConfig config) {
config.reload();
Via.getManager().getConfigurationProvider().register(config);
@@ -154,6 +159,8 @@ public interface ViaBackwardsPlatform {
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);
}
default void enable() {
@@ -34,7 +34,6 @@ import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectArrayMap;
import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectMap;
import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectOpenHashMap;
import com.viaversion.viaversion.util.Key;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
@@ -45,7 +44,6 @@ 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;
@@ -83,7 +81,6 @@ 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) {
@@ -161,10 +158,7 @@ public class BackwardsMappingData extends MappingDataBase {
}
public @Nullable String getMappedNamedSound(final String id) {
if (backwardsSoundMappings == null) {
return null;
}
return backwardsSoundMappings.get(Key.stripMinecraftNamespace(id));
return getFullSoundMappings().mappedIdentifier(id);
}
public @Nullable String mappedEntityName(final String entityName) {
@@ -187,10 +181,6 @@ public class BackwardsMappingData extends MappingDataBase {
return backwardsItemMappings;
}
public @Nullable Map<String, String> getBackwardsSoundMappings() {
return backwardsSoundMappings;
}
public @Nullable Class<? extends Protocol<?, ?, ?, ?>> getViaVersionProtocolClass() {
return vvProtocolClass;
}
@@ -47,7 +47,10 @@ public class EntityPositionHandler {
}
public void cacheEntityPosition(PacketWrapper wrapper, double x, double y, double z, boolean create, boolean relative) {
int entityId = wrapper.get(Types.VAR_INT, 0);
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) {
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! :>
@@ -132,7 +132,7 @@ public class BackwardsItemRewriter<C extends ClientboundPacketType, S extends Se
public @Nullable Item handleItemToServer(UserConnection connection, @Nullable Item item) {
if (item == null) return null;
super.handleItemToServer(connection, item);
item = super.handleItemToServer(connection, item);
if (item.tag() != null) {
Tag originalId = item.tag().remove(nbtTagName("id"));
if (originalId instanceof IntTag) {
@@ -47,7 +47,7 @@ public abstract class BackwardsItemRewriterBase<C extends ClientboundPacketType,
@Override
public @Nullable Item handleItemToServer(UserConnection connection, @Nullable Item item) {
if (item == null) return null;
super.handleItemToServer(connection, item);
item = super.handleItemToServer(connection, item);
restoreDisplayTag(item);
return item;
@@ -18,10 +18,11 @@
package com.viaversion.viabackwards.api.rewriters;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.StringTag;
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 {
@@ -32,6 +33,22 @@ public class BackwardsRegistryRewriter extends RegistryDataRewriter {
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) {
@@ -39,13 +56,36 @@ public class BackwardsRegistryRewriter extends RegistryDataRewriter {
continue;
}
final StringTag soundEvent = ((CompoundTag) entry.tag()).getStringTag("sound_event");
if (soundEvent != null) {
final String mappedNamedSound = protocol.getMappingData().getMappedNamedSound(soundEvent.getValue());
if (mappedNamedSound != null) {
soundEvent.setValue(mappedNamedSound);
}
}
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);
}
}
}
@@ -300,7 +300,11 @@ public class BackwardsStructuredItemRewriter<C extends ClientboundPacketType, S
}
protected Holder<SoundEvent> restoreSoundEventHolder(final CompoundTag tag) {
return restoreHolder(tag, "sound_event", soundEventTag -> {
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);
@@ -208,9 +208,9 @@ public abstract class LegacyBlockItemRewriter<C extends ClientboundPacketType, S
}
@Override
public @Nullable Item handleItemToServer(UserConnection connection, @Nullable final Item item) {
public @Nullable Item handleItemToServer(UserConnection connection, @Nullable Item item) {
if (item == null) return null;
super.handleItemToServer(connection, item);
item = super.handleItemToServer(connection, item);
if (item.tag() != null) {
Tag originalId = item.tag().remove(nbtTagName("id"));
if (originalId instanceof IntTag) {
@@ -86,7 +86,7 @@ public abstract class LegacyEntityRewriter<C extends ClientboundPacketType, T ex
clientWorld.setEnvironment(wrapper.get(Types.INT, 1));
final int entityId = wrapper.get(Types.INT, 0);
addTrackedEntity(wrapper, entityId, playerType);
tracker(wrapper.user()).addEntity(entityId, playerType);
tracker(wrapper.user()).setClientEntityId(entityId);
});
}
@@ -131,13 +131,13 @@ public abstract class LegacyEntityRewriter<C extends ClientboundPacketType, T ex
return;
}
addTrackedEntity(wrapper, wrapper.get(Types.VAR_INT, 0), type);
tracker(wrapper.user()).addEntity(wrapper.get(Types.VAR_INT, 0), type);
};
}
protected PacketHandler getTrackerAndDataHandler(Type<List<EntityData>> dataType, EntityType entityType) {
return wrapper -> {
addTrackedEntity(wrapper, wrapper.get(Types.VAR_INT, 0), entityType);
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());
};
@@ -162,11 +162,6 @@ public abstract class LegacyEntityRewriter<C extends ClientboundPacketType, T ex
};
}
@Deprecated
protected void addTrackedEntity(PacketWrapper wrapper, int entityId, EntityType type) {
tracker(wrapper.user()).addEntity(entityId, type);
}
@FunctionalInterface
protected interface IdSetter {
@@ -17,16 +17,13 @@
*/
package com.viaversion.viabackwards.protocol.template;
import com.viaversion.viabackwards.api.rewriters.BackwardsRegistryRewriter;
import com.viaversion.viabackwards.api.rewriters.EntityRewriter;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_21_4;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_21_2;
import com.viaversion.viaversion.api.type.types.version.VersionedTypes;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundConfigurationPackets1_21;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPacket1_21_2;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPackets1_21_2;
import com.viaversion.viaversion.rewriter.RegistryDataRewriter;
// Replace if needed
// VersionedTypes
@@ -38,16 +35,13 @@ final class EntityPacketRewriter1_99 extends EntityRewriter<ClientboundPacket1_2
@Override
public void registerPackets() {
registerTrackerWithData1_19(ClientboundPackets1_21_2.ADD_ENTITY, EntityTypes1_21_4.FALLING_BLOCK);
registerTrackerWithData1_21_9(ClientboundPackets1_21_2.ADD_ENTITY, EntityTypes1_21_4.FALLING_BLOCK);
registerSetEntityData(ClientboundPackets1_21_2.SET_ENTITY_DATA);
registerRemoveEntities(ClientboundPackets1_21_2.REMOVE_ENTITIES);
registerPlayerAbilities(ClientboundPackets1_21_2.PLAYER_ABILITIES);
registerGameEvent(ClientboundPackets1_21_2.GAME_EVENT);
registerLogin1_20_5(ClientboundPackets1_21_2.LOGIN);
registerRespawn1_20_5(ClientboundPackets1_21_2.RESPAWN);
final RegistryDataRewriter registryDataRewriter = new BackwardsRegistryRewriter(protocol);
protocol.registerClientbound(ClientboundConfigurationPackets1_21.REGISTRY_DATA, registryDataRewriter::handle);
}
@Override
@@ -19,6 +19,7 @@ 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.SoundRewriter;
import com.viaversion.viabackwards.api.rewriters.text.NBTComponentRewriter;
import com.viaversion.viaversion.api.connection.UserConnection;
@@ -37,9 +38,9 @@ import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.packet.ServerboundPac
import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPacket1_21_2;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPackets1_21_2;
import com.viaversion.viaversion.rewriter.ParticleRewriter;
import com.viaversion.viaversion.rewriter.RegistryDataRewriter;
import com.viaversion.viaversion.rewriter.StatisticsRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
import com.viaversion.viaversion.util.SerializerVersion;
import static com.viaversion.viaversion.util.ProtocolUtil.packetTypeMap;
@@ -52,7 +53,6 @@ import static com.viaversion.viaversion.util.ProtocolUtil.packetTypeMap;
// ServerboundConfigurationPackets1_20_5
// EntityTypes1_21_4 (UNMAPPED type)
// VersionedTypes.V1_21_5
// SerializerVersion.V1_21_5
// 1.99, 1.98
final class Protocol1_99To1_98 extends BackwardsProtocol<ClientboundPacket1_21_2, ClientboundPacket1_21_2, ServerboundPacket1_21_4, ServerboundPacket1_21_4> {
@@ -63,6 +63,7 @@ final class Protocol1_99To1_98 extends BackwardsProtocol<ClientboundPacket1_21_2
private final ParticleRewriter<ClientboundPacket1_21_2> particleRewriter = new ParticleRewriter<>(this);
private final NBTComponentRewriter<ClientboundPacket1_21_2> translatableRewriter = new ComponentRewriter1_99(this);
private final TagRewriter<ClientboundPacket1_21_2> tagRewriter = new TagRewriter<>(this);
private final RegistryDataRewriter registryDataRewriter = new BackwardsRegistryRewriter(this);
public Protocol1_99To1_98() {
super(ClientboundPacket1_21_2.class, ClientboundPacket1_21_2.class, ServerboundPacket1_21_4.class, ServerboundPacket1_21_4.class);
@@ -72,6 +73,8 @@ final class Protocol1_99To1_98 extends BackwardsProtocol<ClientboundPacket1_21_2
protected void registerPackets() {
super.registerPackets();
registerClientbound(ClientboundConfigurationPackets1_21.REGISTRY_DATA, registryDataRewriter::handle);
tagRewriter.registerGeneric(ClientboundPackets1_21_2.UPDATE_TAGS);
tagRewriter.registerGeneric(ClientboundConfigurationPackets1_21.UPDATE_TAGS);
@@ -90,23 +93,27 @@ final class Protocol1_99To1_98 extends BackwardsProtocol<ClientboundPacket1_21_2
translatableRewriter.registerComponentPacket(ClientboundPackets1_21_2.SET_SUBTITLE_TEXT);
translatableRewriter.registerBossEvent(ClientboundPackets1_21_2.BOSS_EVENT);
translatableRewriter.registerComponentPacket(ClientboundPackets1_21_2.DISCONNECT);
translatableRewriter.registerComponentPacket(ClientboundConfigurationPackets1_21.DISCONNECT);
translatableRewriter.registerTabList(ClientboundPackets1_21_2.TAB_LIST);
translatableRewriter.registerSetPlayerTeam1_21_5(ClientboundPackets1_21_2.SET_PLAYER_TEAM);
translatableRewriter.registerPlayerCombatKill1_20(ClientboundPackets1_21_2.PLAYER_COMBAT_KILL);
translatableRewriter.registerPlayerInfoUpdate1_21_4(ClientboundPackets1_21_2.PLAYER_INFO_UPDATE);
translatableRewriter.registerComponentPacket(ClientboundPackets1_21_2.SYSTEM_CHAT);
translatableRewriter.registerDisguisedChat(ClientboundPackets1_21_2.DISGUISED_CHAT);
translatableRewriter.registerPlayerChat1_21_5(ClientboundPackets1_21_2.PLAYER_CHAT);
translatableRewriter.registerSetObjective(ClientboundPackets1_21_2.SET_OBJECTIVE);
translatableRewriter.registerSetScore1_20_3(ClientboundPackets1_21_2.SET_SCORE);
translatableRewriter.registerPing();
// If needed for any particle, item, or block changes. Extend ParticleRewriter for particle serializer changes
particleRewriter.registerLevelParticles1_21_4(ClientboundPackets1_21_2.LEVEL_PARTICLES);
particleRewriter.registerExplode1_21_2(ClientboundPackets1_21_2.EXPLODE);
particleRewriter.registerExplode1_21_9(ClientboundPackets1_21_2.EXPLODE);
}
@Override
public void init(final UserConnection connection) {
addEntityTracker(connection, new EntityTrackerBase(connection, EntityTypes1_21_4.PLAYER));
addItemHasher(connection, new ItemHasherBase(this, connection, SerializerVersion.V1_21_5, SerializerVersion.V1_21_5));
addItemHasher(connection, new ItemHasherBase(this, connection));
}
@Override
@@ -124,6 +131,11 @@ final class Protocol1_99To1_98 extends BackwardsProtocol<ClientboundPacket1_21_2
return itemRewriter;
}
@Override
public RegistryDataRewriter getRegistryDataRewriter() {
return registryDataRewriter;
}
@Override
public ParticleRewriter<ClientboundPacket1_21_2> getParticleRewriter() {
return particleRewriter;
@@ -71,7 +71,7 @@ public class ItemPacketRewriter1_11_1 extends LegacyBlockItemRewriter<Clientboun
@Override
public Item handleItemToServer(UserConnection connection, Item item) {
if (item == null) return null;
super.handleItemToServer(connection, item);
item = super.handleItemToServer(connection, item);
enchantmentRewriter.handleToServer(item);
return item;
@@ -280,7 +280,7 @@ public class BlockItemPacketRewriter1_11 extends LegacyBlockItemRewriter<Clientb
@Override
public Item handleItemToServer(UserConnection connection, Item item) {
if (item == null) return null;
super.handleItemToServer(connection, item);
item = super.handleItemToServer(connection, item);
CompoundTag tag = item.tag();
if (tag == null) return item;
@@ -114,7 +114,7 @@ public class BlockItemPacketRewriter1_12 extends LegacyBlockItemRewriter<Clientb
PacketWrapper confirm = wrapper.create(ServerboundPackets1_12.CONTAINER_ACK);
confirm.write(Types.BYTE, wrapper.get(Types.BYTE, 0));
confirm.write(Types.SHORT, wrapper.get(Types.SHORT, 1));
confirm.write(Types.BOOLEAN, false); // Success - not used
confirm.write(Types.BOOLEAN, true); // Success - not used
wrapper.sendToServer(Protocol1_12To1_11_1.class);
wrapper.cancel();
@@ -238,7 +238,7 @@ public class BlockItemPacketRewriter1_12 extends LegacyBlockItemRewriter<Clientb
@Override
public @Nullable Item handleItemToServer(UserConnection connection, Item item) {
if (item == null) return null;
super.handleItemToServer(connection, item);
item = super.handleItemToServer(connection, item);
if (item.tag() != null) {
if (item.tag().remove("Via|LongArrayTags") instanceof CompoundTag tag) {
@@ -69,7 +69,9 @@ public class Protocol1_13_1To1_13 extends BackwardsProtocol<ClientboundPackets1_
translatableRewriter.registerPlayerCombat(ClientboundPackets1_13.PLAYER_COMBAT);
translatableRewriter.registerComponentPacket(ClientboundPackets1_13.DISCONNECT);
translatableRewriter.registerTabList(ClientboundPackets1_13.TAB_LIST);
translatableRewriter.registerSetPlayerTeam1_13(ClientboundPackets1_13.SET_PLAYER_TEAM);
translatableRewriter.registerTitle(ClientboundPackets1_13.SET_TITLES);
translatableRewriter.registerSetObjective(ClientboundPackets1_13.SET_OBJECTIVE);
translatableRewriter.registerPing();
new CommandRewriter1_13_1(this).registerDeclareCommands(ClientboundPackets1_13.COMMANDS);
@@ -90,16 +92,11 @@ public class Protocol1_13_1To1_13 extends BackwardsProtocol<ClientboundPackets1_
}
});
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);
});
}
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);
});
registerClientbound(ClientboundPackets1_13.OPEN_SCREEN, new PacketHandlers() {
@@ -181,8 +178,8 @@ public class Protocol1_13_1To1_13 extends BackwardsProtocol<ClientboundPackets1_
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);
Item icon = itemRewriter.handleItemToClient(wrapper.user(), wrapper.read(Types.ITEM1_13));
wrapper.write(Types.ITEM1_13, icon);
wrapper.passthrough(Types.VAR_INT); // Frame type
int flags = wrapper.passthrough(Types.INT); // Flags
if ((flags & 1) != 0)
@@ -201,7 +198,9 @@ public class Protocol1_13_1To1_13 extends BackwardsProtocol<ClientboundPackets1_
});
tagRewriter.register(ClientboundPackets1_13.UPDATE_TAGS, RegistryType.ITEM);
new StatisticsRewriter<>(this).register(ClientboundPackets1_13.AWARD_STATS);
new StatisticsRewriter<>(this).
register(ClientboundPackets1_13.AWARD_STATS);
}
@Override
@@ -43,18 +43,12 @@ public class ItemPacketRewriter1_13_1 extends ItemRewriter<ClientboundPackets1_1
int size = wrapper.passthrough(Types.UNSIGNED_BYTE);
for (int i = 0; i < size; i++) {
//Input Item
Item input = wrapper.passthrough(Types.ITEM1_13);
handleItemToClient(wrapper.user(), input);
//Output Item
Item output = wrapper.passthrough(Types.ITEM1_13);
handleItemToClient(wrapper.user(), output);
passthroughClientboundItem(wrapper); // Input
passthroughClientboundItem(wrapper); // Output
boolean secondItem = wrapper.passthrough(Types.BOOLEAN); //Has second item
if (secondItem) {
//Second Item
Item second = wrapper.passthrough(Types.ITEM1_13);
handleItemToClient(wrapper.user(), second);
passthroughClientboundItem(wrapper); // Second item
}
wrapper.passthrough(Types.BOOLEAN); //Trade disabled
@@ -32,6 +32,7 @@ import com.viaversion.viabackwards.protocol.v1_13to1_12_2.storage.BackwardsBlock
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.storage.NoteBlockStorage;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.storage.PlayerPositionStorage1_13;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.storage.TabCompleteStorage;
import com.viaversion.viabackwards.utils.BackwardsProtocolLogger;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
@@ -53,7 +54,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
public class Protocol1_13To1_12_2 extends BackwardsProtocol<ClientboundPackets1_13, ClientboundPackets1_12_1, ServerboundPackets1_13, ServerboundPackets1_12_1> {
public static final BackwardsMappingData1_13 MAPPINGS = new BackwardsMappingData1_13();
public static final ProtocolLogger LOGGER = new ProtocolLogger(Protocol1_13To1_12_2.class);
public static final ProtocolLogger LOGGER = new BackwardsProtocolLogger(Protocol1_13To1_12_2.class);
private final EntityPacketRewriter1_13 entityRewriter = new EntityPacketRewriter1_13(this);
private final BlockItemPacketRewriter1_13 blockItemPackets = new BlockItemPacketRewriter1_13(this);
private final JsonNBTComponentRewriter<ClientboundPackets1_13> translatableRewriter = new JsonNBTComponentRewriter<>(this, ComponentRewriterBase.ReadType.JSON) {
@@ -260,8 +260,8 @@ public class BlockItemPacketRewriter1_13 extends BackwardsItemRewriter<Clientbou
handler(wrapper -> {
final Item[] items = wrapper.get(Types.ITEM1_8_SHORT_ARRAY, 0);
for (Item item : items) {
handleItemToClient(wrapper.user(), item);
for (int i = 0; i < items.length; i++) {
items[i] = handleItemToClient(wrapper.user(), items[i]);
}
});
}
@@ -272,9 +272,7 @@ public class BlockItemPacketRewriter1_13 extends BackwardsItemRewriter<Clientbou
public void register() {
map(Types.BYTE);
map(Types.SHORT);
map(Types.ITEM1_13, Types.ITEM1_8);
handler(wrapper -> handleItemToClient(wrapper.user(), wrapper.get(Types.ITEM1_8, 0)));
handler(wrapper -> passthroughClientboundItem(wrapper));
}
});
@@ -427,9 +425,7 @@ public class BlockItemPacketRewriter1_13 extends BackwardsItemRewriter<Clientbou
public void register() {
map(Types.VAR_INT);
map(Types.VAR_INT);
map(Types.ITEM1_13, Types.ITEM1_8);
handler(wrapper -> handleItemToClient(wrapper.user(), wrapper.get(Types.ITEM1_8, 0)));
handler(wrapper -> passthroughClientboundItem(wrapper));
}
});
@@ -505,14 +501,14 @@ public class BlockItemPacketRewriter1_13 extends BackwardsItemRewriter<Clientbou
if (rawId == null) {
// Look for custom mappings
super.handleItemToClient(connection, item);
item = super.handleItemToClient(connection, item);
// Handle one-way special case
if (item.identifier() == -1) {
if (originalId == 362) { // base/colorless shulker box
rawId = 0xe50000; // purple shulker box
} else {
if (!Via.getConfig().isSuppressConversionWarnings()) {
if (Via.getConfig().logOtherConversionWarnings()) {
protocol.getLogger().warning("Failed to get new item for " + originalId);
}
@@ -798,7 +794,7 @@ public class BlockItemPacketRewriter1_13 extends BackwardsItemRewriter<Clientbou
// Handle custom mappings
int identifier = item.identifier();
item.setIdentifier(rawId);
super.handleItemToServer(connection, item);
item = super.handleItemToServer(connection, item);
// Mapped with original data, we can return here
if (item.identifier() != rawId && item.identifier() != -1) return item;
@@ -822,7 +818,7 @@ public class BlockItemPacketRewriter1_13 extends BackwardsItemRewriter<Clientbou
} else if (protocol.getMappingData().getItemMappings().inverse().getNewId(rawId & ~0xF) != -1) {
rawId &= ~0xF; // Remove data
} else {
if (!Via.getConfig().isSuppressConversionWarnings()) {
if (Via.getConfig().logOtherConversionWarnings()) {
protocol.getLogger().warning("Failed to get old item for " + item.identifier());
}
rawId = 16; // Stone
@@ -81,7 +81,7 @@ public class PlayerPacketRewriter1_13 extends RewriterBase<Protocol1_13To1_12_2>
} else {
String oldChannel = ItemPacketRewriter1_13.getOldPluginChannelId(channel);
if (oldChannel == null) {
if (!Via.getConfig().isSuppressConversionWarnings()) {
if (Via.getConfig().logOtherConversionWarnings()) {
protocol.getLogger().warning("Ignoring clientbound plugin message with channel: " + channel);
}
wrapper.cancel();
@@ -96,7 +96,7 @@ public class PlayerPacketRewriter1_13 extends RewriterBase<Protocol1_13To1_12_2>
String rewritten = ItemPacketRewriter1_13.getOldPluginChannelId(s);
if (rewritten != null) {
rewrittenChannels.add(rewritten);
} else if (!Via.getConfig().isSuppressConversionWarnings()) {
} else if (Via.getConfig().logOtherConversionWarnings()) {
protocol.getLogger().warning("Ignoring plugin channel in clientbound " + oldChannel + ": " + s);
}
}
@@ -367,7 +367,7 @@ public class PlayerPacketRewriter1_13 extends RewriterBase<Protocol1_13To1_12_2>
//Maybe older versions used this and we need to implement this? The issue is that we would have to save the command block types
wrapper.setPacketType(ServerboundPackets1_13.SET_COMMAND_BLOCK);
wrapper.cancel();
if (!Via.getConfig().isSuppressConversionWarnings()) {
if (Via.getConfig().logOtherConversionWarnings()) {
protocol.getLogger().warning("Client send MC|AdvCmd custom payload to update command block, weird!");
}
} else if (type == 1) {
@@ -457,7 +457,7 @@ public class PlayerPacketRewriter1_13 extends RewriterBase<Protocol1_13To1_12_2>
default -> {
String newChannel = ItemPacketRewriter1_13.getNewPluginChannelId(channel);
if (newChannel == null) {
if (!Via.getConfig().isSuppressConversionWarnings()) {
if (Via.getConfig().logOtherConversionWarnings()) {
protocol.getLogger().warning("Ignoring serverbound plugin message with channel: " + channel);
}
wrapper.cancel();
@@ -472,7 +472,7 @@ public class PlayerPacketRewriter1_13 extends RewriterBase<Protocol1_13To1_12_2>
String rewritten = ItemPacketRewriter1_13.getNewPluginChannelId(s);
if (rewritten != null) {
rewrittenChannels.add(rewritten);
} else if (!Via.getConfig().isSuppressConversionWarnings()) {
} else if (Via.getConfig().logOtherConversionWarnings()) {
protocol.getLogger().warning("Ignoring plugin channel in serverbound " + Key.stripMinecraftNamespace(newChannel).toUpperCase(Locale.ROOT) + ": " + s);
}
}
@@ -62,7 +62,9 @@ public class Protocol1_14To1_13_2 extends BackwardsProtocol<ClientboundPackets1_
translatableRewriter.registerPlayerCombat(ClientboundPackets1_14.PLAYER_COMBAT);
translatableRewriter.registerComponentPacket(ClientboundPackets1_14.DISCONNECT);
translatableRewriter.registerTabList(ClientboundPackets1_14.TAB_LIST);
translatableRewriter.registerSetPlayerTeam1_13(ClientboundPackets1_14.SET_PLAYER_TEAM);
translatableRewriter.registerTitle(ClientboundPackets1_14.SET_TITLES);
translatableRewriter.registerSetObjective(ClientboundPackets1_14.SET_OBJECTIVE);
translatableRewriter.registerPing();
particleRewriter.registerLevelParticles1_13(ClientboundPackets1_14.LEVEL_PARTICLES, Types.FLOAT);
@@ -223,9 +223,8 @@ public class BlockItemPacketRewriter1_14 extends BackwardsItemRewriter<Clientbou
public void register() {
map(Types.VAR_INT); // 0 - Entity ID
map(Types.VAR_INT); // 1 - Slot ID
map(Types.ITEM1_13_2); // 2 - Item
handler(wrapper -> handleItemToClient(wrapper.user(), wrapper.get(Types.ITEM1_13_2, 0)));
handler(wrapper -> passthroughClientboundItem(wrapper));
handler(wrapper -> {
int entityId = wrapper.get(Types.VAR_INT, 0);
@@ -460,7 +459,7 @@ public class BlockItemPacketRewriter1_14 extends BackwardsItemRewriter<Clientbou
@Override
public Item handleItemToClient(UserConnection connection, Item item) {
if (item == null) return null;
super.handleItemToClient(connection, item);
item = super.handleItemToClient(connection, item);
// Lore now uses JSON
final CompoundTag display = item.tag() != null ? item.tag().getCompoundTag("display") : null;
@@ -516,7 +515,7 @@ public class BlockItemPacketRewriter1_14 extends BackwardsItemRewriter<Clientbou
enchantmentRewriter.handleToServer(item);
// Call this last to check for the backup lore above
super.handleItemToServer(connection, item);
item = super.handleItemToServer(connection, item);
return item;
}
}
@@ -25,6 +25,7 @@ import com.viaversion.viabackwards.protocol.v1_14to1_13_2.storage.ChunkLightStor
import com.viaversion.viabackwards.protocol.v1_14to1_13_2.storage.DifficultyStorage;
import com.viaversion.viabackwards.protocol.v1_14to1_13_2.storage.EntityPositionStorage1_14;
import com.viaversion.viaversion.api.data.entity.EntityTracker;
import com.viaversion.viaversion.api.data.entity.StoredEntityData;
import com.viaversion.viaversion.api.minecraft.BlockPosition;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.Particle;
@@ -34,11 +35,13 @@ import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_13;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_14;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
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;
import com.viaversion.viaversion.api.type.types.version.Types1_13_2;
import com.viaversion.viaversion.api.type.types.version.Types1_14;
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_13_2to1_14.packet.ClientboundPackets1_14;
import com.viaversion.viaversion.rewriter.entitydata.EntityDataHandler;
@@ -50,20 +53,6 @@ public class EntityPacketRewriter1_14 extends LegacyEntityRewriter<ClientboundPa
super(protocol, Types1_13_2.ENTITY_DATA_TYPES.optionalComponentType, Types1_13_2.ENTITY_DATA_TYPES.booleanType);
}
//TODO work the method into this class alone
@Override
protected void addTrackedEntity(PacketWrapper wrapper, int entityId, EntityType type) {
super.addTrackedEntity(wrapper, entityId, type);
// Cache the position for every newly tracked entity
if (type == EntityTypes1_14.PAINTING) {
final BlockPosition position = wrapper.get(Types.BLOCK_POSITION1_8, 0);
positionHandler.cacheEntityPosition(wrapper, position.x(), position.y(), position.z(), true, false);
} else if (wrapper.getId() != ClientboundPackets1_14.LOGIN.getId()) { // ignore join game
positionHandler.cacheEntityPosition(wrapper, true, false);
}
}
@Override
protected void registerPackets() {
positionHandler = new EntityPositionHandler(this, EntityPositionStorage1_14.class, EntityPositionStorage1_14::new);
@@ -133,7 +122,17 @@ public class EntityPacketRewriter1_14 extends LegacyEntityRewriter<ClientboundPa
map(Types.SHORT); // 10 - Velocity Y
map(Types.SHORT); // 11 - Velocity Z
handler(getObjectTrackerHandler());
handler(wrapper -> {
final int type = wrapper.get(Types.BYTE, 0);
final int data = wrapper.get(Types.INT, 0);
final EntityType entityType = objectTypeFromId(type, data);
if (entityType == null) {
return;
}
trackAndCacheEntityPosition(wrapper, entityType);
});
handler(wrapper -> {
int id = wrapper.get(Types.BYTE, 0);
@@ -224,7 +223,7 @@ public class EntityPacketRewriter1_14 extends LegacyEntityRewriter<ClientboundPa
handler(wrapper -> {
int type = wrapper.get(Types.VAR_INT, 1);
EntityType entityType = EntityTypes1_14.getTypeFromId(type);
addTrackedEntity(wrapper, wrapper.get(Types.VAR_INT, 0), entityType);
trackAndCacheEntityPosition(wrapper, entityType);
int oldId = newEntityId(type);
if (oldId == -1) {
@@ -252,7 +251,7 @@ public class EntityPacketRewriter1_14 extends LegacyEntityRewriter<ClientboundPa
map(Types.DOUBLE); // Needs to be mapped for the position cache
map(Types.DOUBLE);
map(Types.DOUBLE);
handler(wrapper -> addTrackedEntity(wrapper, wrapper.get(Types.VAR_INT, 0), EntityTypes1_14.EXPERIENCE_ORB));
handler(wrapper -> trackAndCacheEntityPosition(wrapper, EntityTypes1_14.EXPERIENCE_ORB));
}
});
@@ -264,7 +263,7 @@ public class EntityPacketRewriter1_14 extends LegacyEntityRewriter<ClientboundPa
map(Types.DOUBLE); // Needs to be mapped for the position cache
map(Types.DOUBLE);
map(Types.DOUBLE);
handler(wrapper -> addTrackedEntity(wrapper, wrapper.get(Types.VAR_INT, 0), EntityTypes1_14.LIGHTNING_BOLT));
handler(wrapper -> trackAndCacheEntityPosition(wrapper, EntityTypes1_14.LIGHTNING_BOLT));
}
});
@@ -278,7 +277,7 @@ public class EntityPacketRewriter1_14 extends LegacyEntityRewriter<ClientboundPa
map(Types.BYTE);
// Track entity
handler(wrapper -> addTrackedEntity(wrapper, wrapper.get(Types.VAR_INT, 0), EntityTypes1_14.PAINTING));
handler(wrapper -> trackAndCacheEntityPosition(wrapper, EntityTypes1_14.PAINTING));
}
});
@@ -319,11 +318,10 @@ public class EntityPacketRewriter1_14 extends LegacyEntityRewriter<ClientboundPa
wrapper.passthrough(Types.STRING); // Level Type
wrapper.read(Types.VAR_INT); // Read View Distance
//TODO Track client position
// Manually add position storage
/*int entitiyId = wrapper.get(Type.INT, 0);
StoredEntityData storedEntity = protocol.getEntityRewriter().tracker(wrapper.user()).entityData(entitiyId);
storedEntity.put(new EntityPositionStorage1_14());*/
final int entityId = wrapper.get(Types.INT, 0);
final StoredEntityData storedEntity = tracker(wrapper.user()).entityData(entityId);
storedEntity.put(new EntityPositionStorage1_14());
});
}
});
@@ -338,8 +336,10 @@ public class EntityPacketRewriter1_14 extends LegacyEntityRewriter<ClientboundPa
int dimensionId = wrapper.get(Types.INT, 0);
if (clientWorld.setEnvironment(dimensionId)) {
tracker(wrapper.user()).clearEntities();
EntityTracker tracker = tracker(wrapper.user());
tracker.clearEntities();
wrapper.user().get(ChunkLightStorage.class).clear();
tracker.entityData(tracker.clientEntityId()).put(new EntityPositionStorage1_14());
}
short difficulty = wrapper.user().get(DifficultyStorage.class).getDifficulty();
@@ -347,6 +347,27 @@ public class EntityPacketRewriter1_14 extends LegacyEntityRewriter<ClientboundPa
});
}
});
PacketHandler absoluteMoveHandler = wrapper -> {
final double x = wrapper.passthrough(Types.DOUBLE);
final double y = wrapper.passthrough(Types.DOUBLE);
final double z = wrapper.passthrough(Types.DOUBLE);
positionHandler.cacheEntityPosition(wrapper, tracker(wrapper.user()).clientEntityId(), x, y, z, false, false);
};
protocol.registerServerbound(ServerboundPackets1_13.MOVE_PLAYER_POS, absoluteMoveHandler);
protocol.registerServerbound(ServerboundPackets1_13.MOVE_PLAYER_POS_ROT, absoluteMoveHandler);
}
private void trackAndCacheEntityPosition(PacketWrapper wrapper, EntityType type) {
// Tracks the entity + cache the position for the entity
tracker(wrapper.user()).addEntity(wrapper.get(Types.VAR_INT, 0), type);
if (type == EntityTypes1_14.PAINTING) {
final BlockPosition position = wrapper.get(Types.BLOCK_POSITION1_8, 0);
positionHandler.cacheEntityPosition(wrapper, position.x(), position.y(), position.z(), true, false);
} else {
positionHandler.cacheEntityPosition(wrapper, true, false);
}
}
@Override
@@ -466,7 +487,7 @@ public class EntityPacketRewriter1_14 extends LegacyEntityRewriter<ClientboundPa
filter().handler((event, data) -> {
if (data.dataType().typeId() > 15) {
throw new IllegalArgumentException("Unhandled entity data: " + data);
event.cancel(); // Cancel bad data (generally from plugins sending data for despawned entities)
}
});
}
@@ -64,7 +64,9 @@ public class Protocol1_15To1_14_4 extends BackwardsProtocol<ClientboundPackets1_
translatableRewriter.registerComponentPacket(ClientboundPackets1_15.DISCONNECT);
translatableRewriter.registerOpenScreen1_14(ClientboundPackets1_15.OPEN_SCREEN);
translatableRewriter.registerTabList(ClientboundPackets1_15.TAB_LIST);
translatableRewriter.registerSetPlayerTeam1_13(ClientboundPackets1_15.SET_PLAYER_TEAM);
translatableRewriter.registerTitle(ClientboundPackets1_15.SET_TITLES);
translatableRewriter.registerSetObjective(ClientboundPackets1_15.SET_OBJECTIVE);
translatableRewriter.registerPing();
SoundRewriter<ClientboundPackets1_15> soundRewriter = new SoundRewriter<>(this);
@@ -25,6 +25,7 @@ import com.viaversion.viabackwards.protocol.v1_16_2to1_16_1.rewriter.BlockItemPa
import com.viaversion.viabackwards.protocol.v1_16_2to1_16_1.rewriter.CommandRewriter1_16_2;
import com.viaversion.viabackwards.protocol.v1_16_2to1_16_1.rewriter.EntityPacketRewriter1_16_2;
import com.viaversion.viabackwards.protocol.v1_16_2to1_16_1.storage.BiomeStorage;
import com.viaversion.viabackwards.utils.BackwardsProtocolLogger;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.RegistryType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_16_2;
@@ -46,7 +47,7 @@ import com.viaversion.viaversion.util.ProtocolLogger;
public class Protocol1_16_2To1_16_1 extends BackwardsProtocol<ClientboundPackets1_16_2, ClientboundPackets1_16, ServerboundPackets1_16_2, ServerboundPackets1_16> {
public static final BackwardsMappingData MAPPINGS = new BackwardsMappingData("1.16.2", "1.16", Protocol1_16_1To1_16_2.class);
public static final ProtocolLogger LOGGER = new ProtocolLogger(Protocol1_16_2To1_16_1.class);
public static final ProtocolLogger LOGGER = new BackwardsProtocolLogger(Protocol1_16_2To1_16_1.class);
private final EntityPacketRewriter1_16_2 entityRewriter = new EntityPacketRewriter1_16_2(this);
private final BlockItemPacketRewriter1_16_2 blockItemPackets = new BlockItemPacketRewriter1_16_2(this);
private final ParticleRewriter<ClientboundPackets1_16_2> particleRewriter = new ParticleRewriter<>(this);
@@ -66,7 +67,9 @@ public class Protocol1_16_2To1_16_1 extends BackwardsProtocol<ClientboundPackets
translatableRewriter.registerComponentPacket(ClientboundPackets1_16_2.DISCONNECT);
translatableRewriter.registerTabList(ClientboundPackets1_16_2.TAB_LIST);
translatableRewriter.registerTitle(ClientboundPackets1_16_2.SET_TITLES);
translatableRewriter.registerSetPlayerTeam1_13(ClientboundPackets1_16_2.SET_PLAYER_TEAM);
translatableRewriter.registerOpenScreen1_14(ClientboundPackets1_16_2.OPEN_SCREEN);
translatableRewriter.registerSetObjective(ClientboundPackets1_16_2.SET_OBJECTIVE);
translatableRewriter.registerPing();
particleRewriter.registerLevelParticles1_13(ClientboundPackets1_16_2.LEVEL_PARTICLES, Types.DOUBLE);
@@ -136,7 +136,7 @@ public final class BiomeMappings1_16_1 {
public static int toLegacyBiome(String biome) {
final int legacyBiome = MODERN_TO_LEGACY_ID.getInt(Key.stripMinecraftNamespace(biome));
if (legacyBiome == -1) {
if (!Via.getConfig().isSuppressConversionWarnings()) {
if (Via.getConfig().logOtherConversionWarnings()) {
Protocol1_16_2To1_16_1.LOGGER.warning("Biome with id " + biome + " has no legacy biome mapping (custom datapack?)");
}
return 1; // Plains
@@ -70,7 +70,9 @@ public class Protocol1_16To1_15_2 extends BackwardsProtocol<ClientboundPackets1_
translatableRewriter.registerPlayerCombat(ClientboundPackets1_16.PLAYER_COMBAT);
translatableRewriter.registerComponentPacket(ClientboundPackets1_16.DISCONNECT);
translatableRewriter.registerTabList(ClientboundPackets1_16.TAB_LIST);
translatableRewriter.registerSetPlayerTeam1_13(ClientboundPackets1_16.SET_PLAYER_TEAM);
translatableRewriter.registerTitle(ClientboundPackets1_16.SET_TITLES);
translatableRewriter.registerSetObjective(ClientboundPackets1_16.SET_OBJECTIVE);
translatableRewriter.registerPing();
particleRewriter.registerLevelParticles1_13(ClientboundPackets1_16.LEVEL_PARTICLES, Types.DOUBLE);
@@ -262,7 +262,7 @@ public class BlockItemPacketRewriter1_16 extends BackwardsItemRewriter<Clientbou
public Item handleItemToClient(UserConnection connection, Item item) {
if (item == null) return null;
super.handleItemToClient(connection, item);
item = super.handleItemToClient(connection, item);
CompoundTag tag = item.tag();
if (item.identifier() == 771 && tag != null) {
@@ -297,7 +297,7 @@ public class BlockItemPacketRewriter1_16 extends BackwardsItemRewriter<Clientbou
if (item == null) return null;
int identifier = item.identifier();
super.handleItemToServer(connection, item);
item = super.handleItemToServer(connection, item);
CompoundTag tag = item.tag();
if (identifier == 771 && tag != null) {
@@ -74,7 +74,9 @@ public final class Protocol1_17To1_16_4 extends BackwardsProtocol<ClientboundPac
translatableRewriter.registerBossEvent(ClientboundPackets1_17.BOSS_EVENT);
translatableRewriter.registerComponentPacket(ClientboundPackets1_17.DISCONNECT);
translatableRewriter.registerTabList(ClientboundPackets1_17.TAB_LIST);
translatableRewriter.registerSetPlayerTeam1_13(ClientboundPackets1_17.SET_PLAYER_TEAM);
translatableRewriter.registerOpenScreen1_14(ClientboundPackets1_17.OPEN_SCREEN);
translatableRewriter.registerSetObjective(ClientboundPackets1_17.SET_OBJECTIVE);
translatableRewriter.registerPing();
SoundRewriter<ClientboundPackets1_17> soundRewriter = new SoundRewriter<>(this);
@@ -102,7 +104,7 @@ public final class Protocol1_17To1_16_4 extends BackwardsProtocol<ClientboundPac
// Put them into the hardcoded order of Vanilla tags (and only those), rewrite ids
for (RegistryType type : TAG_REGISTRY_TYPES) {
List<TagData> tagList = tags.get(type.resourceLocation());
List<TagData> tagList = tags.get(type.identifier());
if (tagList == null) {
// Higher versions may not send the otherwise expected tags
wrapper.write(Types.VAR_INT, 0);
@@ -43,7 +43,7 @@ public final class Protocol1_18_2To1_18 extends BackwardsProtocol<ClientboundPac
final PacketHandler entityEffectIdHandler = wrapper -> {
final int id = wrapper.read(Types.VAR_INT);
if ((byte) id != id) {
if (!Via.getConfig().isSuppressConversionWarnings()) {
if (Via.getConfig().logOtherConversionWarnings()) {
getLogger().warning("Cannot send entity effect id " + id + " to old client");
}
wrapper.cancel();
@@ -112,7 +112,7 @@ public final class BlockItemPacketRewriter1_18 extends BackwardsItemRewriter<Cli
int data = wrapper.passthrough(Types.VAR_INT);
wrapper.set(Types.VAR_INT, 0, protocol.getMappingData().getNewBlockStateId(data));
} else if (mappings.isItemParticle(id)) {
handleItemToClient(wrapper.user(), wrapper.passthrough(Types.ITEM1_13_2));
passthroughClientboundItem(wrapper);
}
int newId = protocol.getMappingData().getNewParticleId(id);
@@ -82,8 +82,10 @@ public final class Protocol1_19_1To1_19 extends BackwardsProtocol<ClientboundPac
translatableRewriter.registerBossEvent(ClientboundPackets1_19_1.BOSS_EVENT);
translatableRewriter.registerComponentPacket(ClientboundPackets1_19_1.DISCONNECT);
translatableRewriter.registerTabList(ClientboundPackets1_19_1.TAB_LIST);
translatableRewriter.registerSetPlayerTeam1_13(ClientboundPackets1_19_1.SET_PLAYER_TEAM);
translatableRewriter.registerOpenScreen1_14(ClientboundPackets1_19_1.OPEN_SCREEN);
translatableRewriter.registerPlayerCombatKill(ClientboundPackets1_19_1.PLAYER_COMBAT_KILL);
translatableRewriter.registerSetObjective(ClientboundPackets1_19_1.SET_OBJECTIVE);
translatableRewriter.registerPing();
entityRewriter.register();
@@ -19,10 +19,10 @@ package com.viaversion.viabackwards.protocol.v1_19_3to1_19_1;
import com.google.common.base.Preconditions;
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.protocol.v1_19_1to1_19.Protocol1_19_1To1_19;
import com.viaversion.viabackwards.protocol.v1_19_3to1_19_1.data.BackwardsMappingData1_19_3;
import com.viaversion.viabackwards.protocol.v1_19_3to1_19_1.rewriter.BlockItemPacketRewriter1_19_3;
import com.viaversion.viabackwards.protocol.v1_19_3to1_19_1.rewriter.EntityPacketRewriter1_19_3;
import com.viaversion.viabackwards.protocol.v1_19_3to1_19_1.storage.ChatSessionStorage;
@@ -49,6 +49,7 @@ import com.viaversion.viaversion.data.entity.EntityTrackerBase;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.protocols.base.ClientboundLoginPackets;
import com.viaversion.viaversion.protocols.base.ServerboundLoginPackets;
import com.viaversion.viaversion.protocols.v1_19_1to1_19_3.Protocol1_19_1To1_19_3;
import com.viaversion.viaversion.protocols.v1_19_1to1_19_3.packet.ClientboundPackets1_19_3;
import com.viaversion.viaversion.protocols.v1_19_1to1_19_3.packet.ServerboundPackets1_19_3;
import com.viaversion.viaversion.protocols.v1_19to1_19_1.packet.ClientboundPackets1_19_1;
@@ -68,7 +69,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
public final class Protocol1_19_3To1_19_1 extends BackwardsProtocol<ClientboundPackets1_19_3, ClientboundPackets1_19_1, ServerboundPackets1_19_3, ServerboundPackets1_19_1> {
public static final BackwardsMappingData1_19_3 MAPPINGS = new BackwardsMappingData1_19_3();
public static final BackwardsMappingData MAPPINGS = new BackwardsMappingData("1.19.3", "1.19", Protocol1_19_1To1_19_3.class);
public static final ByteArrayType.OptionalByteArrayType OPTIONAL_SIGNATURE_BYTES_TYPE = new ByteArrayType.OptionalByteArrayType(256);
public static final ByteArrayType SIGNATURE_BYTES_TYPE = new ByteArrayType(256);
private final EntityPacketRewriter1_19_3 entityRewriter = new EntityPacketRewriter1_19_3(this);
@@ -92,8 +93,10 @@ public final class Protocol1_19_3To1_19_1 extends BackwardsProtocol<ClientboundP
translatableRewriter.registerBossEvent(ClientboundPackets1_19_3.BOSS_EVENT);
translatableRewriter.registerComponentPacket(ClientboundPackets1_19_3.DISCONNECT);
translatableRewriter.registerTabList(ClientboundPackets1_19_3.TAB_LIST);
translatableRewriter.registerSetPlayerTeam1_13(ClientboundPackets1_19_3.SET_PLAYER_TEAM);
translatableRewriter.registerOpenScreen1_14(ClientboundPackets1_19_3.OPEN_SCREEN);
translatableRewriter.registerPlayerCombatKill(ClientboundPackets1_19_3.PLAYER_COMBAT_KILL);
translatableRewriter.registerSetObjective(ClientboundPackets1_19_3.SET_OBJECTIVE);
translatableRewriter.registerPing();
particleRewriter.registerLevelParticles1_19(ClientboundPackets1_19_3.LEVEL_PARTICLES);
@@ -113,7 +116,7 @@ public final class Protocol1_19_3To1_19_1 extends BackwardsProtocol<ClientboundP
return;
}
final int mappedId = MAPPINGS.mappedSound(mappedIdentifier);
final int mappedId = MAPPINGS.getFullSoundMappings().mappedId(mappedIdentifier);
if (mappedId == -1) {
wrapper.cancel();
return;
@@ -401,7 +404,7 @@ public final class Protocol1_19_3To1_19_1 extends BackwardsProtocol<ClientboundP
}
@Override
public BackwardsMappingData1_19_3 getMappingData() {
public BackwardsMappingData getMappingData() {
return MAPPINGS;
}
@@ -1,53 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viabackwards.protocol.v1_19_3to1_19_1.data;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viabackwards.api.data.BackwardsMappingData;
import com.viaversion.viabackwards.api.data.BackwardsMappingDataLoader;
import com.viaversion.viaversion.libs.fastutil.objects.Object2IntMap;
import com.viaversion.viaversion.libs.fastutil.objects.Object2IntOpenHashMap;
import com.viaversion.viaversion.libs.gson.JsonArray;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.protocols.v1_19_1to1_19_3.Protocol1_19_1To1_19_3;
import com.viaversion.viaversion.util.Key;
public final class BackwardsMappingData1_19_3 extends BackwardsMappingData {
private final Object2IntMap<String> mappedSounds = new Object2IntOpenHashMap<>();
public BackwardsMappingData1_19_3() {
super("1.19.3", "1.19", Protocol1_19_1To1_19_3.class);
mappedSounds.defaultReturnValue(-1);
}
@Override
protected void loadExtras(final CompoundTag data) {
super.loadExtras(data);
final JsonArray sounds = BackwardsMappingDataLoader.INSTANCE.loadData("sounds-1.19.json").getAsJsonArray("sounds");
int i = 0;
for (final JsonElement sound : sounds) {
mappedSounds.put(sound.getAsString(), i++);
}
}
public int mappedSound(final String sound) {
return mappedSounds.getInt(Key.stripMinecraftNamespace(sound));
}
}
@@ -77,11 +77,11 @@ public final class BlockItemPacketRewriter1_19_3 extends BackwardsItemRewriter<C
final int ingredients = wrapper.passthrough(Types.VAR_INT);
for (int j = 0; j < ingredients; j++) {
final Item[] items = wrapper.passthrough(Types.ITEM1_13_2_ARRAY); // Ingredients
for (final Item item : items) {
handleItemToClient(wrapper.user(), item);
for (int k = 0; k < items.length; k++) {
items[k] = handleItemToClient(wrapper.user(), items[k]);
}
}
handleItemToClient(wrapper.user(), wrapper.passthrough(Types.ITEM1_13_2)); // Result
passthroughClientboundItem(wrapper); // Result
}
case "crafting_shaped" -> {
final int ingredients = wrapper.passthrough(Types.VAR_INT) * wrapper.passthrough(Types.VAR_INT);
@@ -89,20 +89,20 @@ public final class BlockItemPacketRewriter1_19_3 extends BackwardsItemRewriter<C
wrapper.read(Types.VAR_INT); // Crafting book category
for (int j = 0; j < ingredients; j++) {
final Item[] items = wrapper.passthrough(Types.ITEM1_13_2_ARRAY); // Ingredients
for (final Item item : items) {
handleItemToClient(wrapper.user(), item);
for (int k = 0; k < items.length; k++) {
items[k] = handleItemToClient(wrapper.user(), items[k]);
}
}
handleItemToClient(wrapper.user(), wrapper.passthrough(Types.ITEM1_13_2)); // Result
passthroughClientboundItem(wrapper); // Result
}
case "smelting", "campfire_cooking", "blasting", "smoking" -> {
wrapper.passthrough(Types.STRING); // Group
wrapper.read(Types.VAR_INT); // Crafting book category
final Item[] items = wrapper.passthrough(Types.ITEM1_13_2_ARRAY); // Ingredients
for (final Item item : items) {
handleItemToClient(wrapper.user(), item);
for (int j = 0; j < items.length; j++) {
items[j] = handleItemToClient(wrapper.user(), items[j]);
}
handleItemToClient(wrapper.user(), wrapper.passthrough(Types.ITEM1_13_2)); // Result
passthroughClientboundItem(wrapper); // Result
wrapper.passthrough(Types.FLOAT); // EXP
wrapper.passthrough(Types.VAR_INT); // Cooking time
}
@@ -71,8 +71,10 @@ public final class Protocol1_19_4To1_19_3 extends BackwardsProtocol<ClientboundP
translatableRewriter.registerComponentPacket(ClientboundPackets1_19_4.DISCONNECT);
translatableRewriter.registerTabList(ClientboundPackets1_19_4.TAB_LIST);
translatableRewriter.registerPlayerCombatKill(ClientboundPackets1_19_4.PLAYER_COMBAT_KILL);
translatableRewriter.registerSetPlayerTeam1_13(ClientboundPackets1_19_4.SET_PLAYER_TEAM);
translatableRewriter.registerComponentPacket(ClientboundPackets1_19_4.SYSTEM_CHAT);
translatableRewriter.registerComponentPacket(ClientboundPackets1_19_4.DISGUISED_CHAT);
translatableRewriter.registerSetObjective(ClientboundPackets1_19_4.SET_OBJECTIVE);
translatableRewriter.registerPing();
particleRewriter.registerLevelParticles1_19(ClientboundPackets1_19_4.LEVEL_PARTICLES);
@@ -45,6 +45,8 @@ import com.viaversion.viaversion.util.TagUtil;
public final class EntityPacketRewriter1_19_4 extends EntityRewriter<ClientboundPackets1_19_4, Protocol1_19_4To1_19_3> {
private static final double TEXT_DISPLAY_Y_OFFSET = -0.25; // Move emulated armor stands down to match text display height offsets
public EntityPacketRewriter1_19_4(final Protocol1_19_4To1_19_3 protocol) {
super(protocol, Types1_19_3.ENTITY_DATA_TYPES.optionalComponentType, Types1_19_3.ENTITY_DATA_TYPES.booleanType);
}
@@ -78,6 +80,11 @@ public final class EntityPacketRewriter1_19_4 extends EntityRewriter<Clientbound
}
}
final double y = wrapper.get(Types.DOUBLE, 1);
if (entityType == EntityTypes1_19_4.TEXT_DISPLAY.getId()) {
wrapper.set(Types.DOUBLE, 1, y + TEXT_DISPLAY_Y_OFFSET);
}
// First track (and remap) entity, then put storage for block display entity
getSpawnTrackerWithDataHandler1_19(EntityTypes1_19_4.FALLING_BLOCK).handle(wrapper);
if (entityType != EntityTypes1_19_4.BLOCK_DISPLAY.getId()) {
@@ -88,7 +95,6 @@ public final class EntityPacketRewriter1_19_4 extends EntityRewriter<Clientbound
if (data != null) {
final LinkedEntityStorage storage = new LinkedEntityStorage();
final double x = wrapper.get(Types.DOUBLE, 0);
final double y = wrapper.get(Types.DOUBLE, 1);
final double z = wrapper.get(Types.DOUBLE, 2);
storage.setPosition(x, y, z);
data.put(storage);
@@ -183,7 +189,7 @@ public final class EntityPacketRewriter1_19_4 extends EntityRewriter<Clientbound
wrapper.passthrough(Types.VAR_INT); // Effect id
wrapper.passthrough(Types.BYTE); // Amplifier
// Handle inifinite duration. Use a value the client still accepts without bugging out the display while still being practically infinite
// Handle infinite duration. Use a value the client still accepts without bugging out the display while still being practically infinite
final int duration = wrapper.read(Types.VAR_INT);
wrapper.write(Types.VAR_INT, duration == -1 ? 999999 : duration);
});
@@ -198,11 +204,14 @@ public final class EntityPacketRewriter1_19_4 extends EntityRewriter<Clientbound
final double z = wrapper.passthrough(Types.DOUBLE);
final EntityTracker1_19_4 tracker = tracker(wrapper.user());
final LinkedEntityStorage storage = tracker.linkedEntityStorage(entityId);
if (storage == null) {
return;
if (tracker.entityType(entityId) == EntityTypes1_19_4.TEXT_DISPLAY) {
wrapper.set(Types.DOUBLE, 1, y + TEXT_DISPLAY_Y_OFFSET);
}
final LinkedEntityStorage storage = tracker.linkedEntityStorage(entityId);
if (storage != null) {
storage.setPosition(x, y, z);
}
storage.setPosition(x, y, z);
});
final PacketHandler entityPositionHandler = wrapper -> {
@@ -213,10 +222,9 @@ public final class EntityPacketRewriter1_19_4 extends EntityRewriter<Clientbound
final EntityTracker1_19_4 tracker = tracker(wrapper.user());
final LinkedEntityStorage storage = tracker.linkedEntityStorage(entityId);
if (storage == null) {
return;
if (storage != null) {
storage.addRelativePosition(x, y, z);
}
storage.addRelativePosition(x, y, z);
};
protocol.registerClientbound(ClientboundPackets1_19_4.MOVE_ENTITY_POS, entityPositionHandler);
@@ -86,8 +86,10 @@ public final class Protocol1_19To1_18_2 extends BackwardsProtocol<ClientboundPac
translatableRewriter.registerBossEvent(ClientboundPackets1_19.BOSS_EVENT);
translatableRewriter.registerComponentPacket(ClientboundPackets1_19.DISCONNECT);
translatableRewriter.registerTabList(ClientboundPackets1_19.TAB_LIST);
translatableRewriter.registerSetPlayerTeam1_13(ClientboundPackets1_19.SET_PLAYER_TEAM);
translatableRewriter.registerOpenScreen1_14(ClientboundPackets1_19.OPEN_SCREEN);
translatableRewriter.registerPlayerCombatKill(ClientboundPackets1_19.PLAYER_COMBAT_KILL);
translatableRewriter.registerSetObjective(ClientboundPackets1_19.SET_OBJECTIVE);
translatableRewriter.registerPing();
final SoundRewriter<ClientboundPackets1_19> soundRewriter = new SoundRewriter<>(this);
@@ -77,12 +77,12 @@ public final class BlockItemPacketRewriter1_19 extends BackwardsItemRewriter<Cli
final int size = wrapper.read(Types.VAR_INT);
wrapper.write(Types.UNSIGNED_BYTE, (short) size);
for (int i = 0; i < size; i++) {
handleItemToClient(wrapper.user(), wrapper.passthrough(Types.ITEM1_13_2)); // First item
handleItemToClient(wrapper.user(), wrapper.passthrough(Types.ITEM1_13_2)); // Result
passthroughClientboundItem(wrapper); // First item
passthroughClientboundItem(wrapper); // Result
final Item secondItem = wrapper.read(Types.ITEM1_13_2);
Item secondItem = wrapper.read(Types.ITEM1_13_2);
if (secondItem != null) {
handleItemToClient(wrapper.user(), secondItem);
secondItem = handleItemToClient(wrapper.user(), secondItem);
wrapper.write(Types.BOOLEAN, true);
wrapper.write(Types.ITEM1_13_2, secondItem);
} else {
@@ -217,11 +217,11 @@ public final class BlockItemPacketRewriter1_19 extends BackwardsItemRewriter<Cli
}
@Override
public Item handleItemToClient(final UserConnection connection, final Item item) {
public Item handleItemToClient(final UserConnection connection, Item item) {
if (item == null) return null;
final int identifier = item.identifier();
super.handleItemToClient(connection, item);
item = super.handleItemToClient(connection, item);
if (identifier != 834) {
return item;
@@ -246,10 +246,10 @@ public final class BlockItemPacketRewriter1_19 extends BackwardsItemRewriter<Cli
}
@Override
public Item handleItemToServer(final UserConnection connection, final Item item) {
public Item handleItemToServer(final UserConnection connection, Item item) {
if (item == null) return null;
super.handleItemToServer(connection, item);
item = super.handleItemToServer(connection, item);
CompoundTag tag = item.tag();
if (item.identifier() == 834 && tag != null) {
@@ -161,7 +161,7 @@ public final class BlockItemPacketRewriter1_20_2 extends BackwardsItemRewriter<C
if (wrapper.passthrough(Types.BOOLEAN)) {
wrapper.passthrough(Types.COMPONENT); // Title
wrapper.passthrough(Types.COMPONENT); // Description
wrapper.write(Types.ITEM1_13_2, handleItemToClient(wrapper.user(), wrapper.read(Types.ITEM1_20_2))); // Icon
passthroughClientboundItem(wrapper); // Icon
wrapper.passthrough(Types.VAR_INT); // Frame type
final int flags = wrapper.passthrough(Types.INT); // Flags
if ((flags & 1) != 0) {
@@ -29,6 +29,7 @@ import com.viaversion.viabackwards.protocol.v1_20_3to1_20_2.storage.SpawnPositio
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.BlockPosition;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_20_3;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.packet.provider.PacketTypesProvider;
import com.viaversion.viaversion.api.protocol.packet.provider.SimplePacketTypesProvider;
@@ -151,7 +152,8 @@ public final class Protocol1_20_3To1_20_2 extends BackwardsProtocol<ClientboundP
if (wrapper.passthrough(Types.BOOLEAN)) {
convertComponent(wrapper); // Title
convertComponent(wrapper); // Description
itemRewriter.handleItemToClient(wrapper.user(), wrapper.passthrough(Types.ITEM1_20_2)); // Icon
final Item icon = itemRewriter.handleItemToClient(wrapper.user(), wrapper.read(Types.ITEM1_20_2));
wrapper.write(Types.ITEM1_20_2, icon);
wrapper.passthrough(Types.VAR_INT); // Frame type
final int flags = wrapper.passthrough(Types.INT);
if ((flags & 1) != 0) {
@@ -110,12 +110,16 @@ public final class Protocol1_20_5To1_20_3 extends BackwardsProtocol<ClientboundP
translatableRewriter.registerComponentPacket(ClientboundPackets1_20_5.SET_SUBTITLE_TEXT);
translatableRewriter.registerBossEvent(ClientboundPackets1_20_5.BOSS_EVENT);
translatableRewriter.registerComponentPacket(ClientboundPackets1_20_5.DISCONNECT);
translatableRewriter.registerComponentPacket(ClientboundConfigurationPackets1_20_5.DISCONNECT);
translatableRewriter.registerTabList(ClientboundPackets1_20_5.TAB_LIST);
translatableRewriter.registerSetPlayerTeam1_13(ClientboundPackets1_20_5.SET_PLAYER_TEAM);
translatableRewriter.registerPlayerCombatKill1_20(ClientboundPackets1_20_5.PLAYER_COMBAT_KILL);
translatableRewriter.registerComponentPacket(ClientboundPackets1_20_5.SYSTEM_CHAT);
translatableRewriter.registerComponentPacket(ClientboundPackets1_20_5.DISGUISED_CHAT);
translatableRewriter.registerPlayerChat(ClientboundPackets1_20_5.PLAYER_CHAT, Types.VAR_INT);
translatableRewriter.registerPlayerInfoUpdate1_20_3(ClientboundPackets1_20_5.PLAYER_INFO_UPDATE);
translatableRewriter.registerSetObjective(ClientboundPackets1_20_5.SET_OBJECTIVE);
translatableRewriter.registerSetScore1_20_3(ClientboundPackets1_20_5.SET_SCORE);
translatableRewriter.registerPing();
registerClientbound(State.LOGIN, ClientboundLoginPackets.HELLO, wrapper -> {
@@ -348,7 +348,7 @@ public final class BlockItemPacketRewriter1_20_5 extends BackwardsStructuredItem
}
@Override
public @Nullable Item handleItemToClient(final UserConnection connection, final Item item) {
public @Nullable Item handleItemToClient(final UserConnection connection, Item item) {
if (item.isEmpty()) {
// Back to null for the older protocols
return null;
@@ -358,7 +358,7 @@ public final class BlockItemPacketRewriter1_20_5 extends BackwardsStructuredItem
item.dataContainer().setIdLookup(protocol, true);
enchantmentRewriter.handleToClient(item);
super.handleItemToClient(connection, item);
item = super.handleItemToClient(connection, item);
// Text components since we skip the usual rewrite method
updateTextComponent(connection, item, StructuredDataKey.ITEM_NAME, "item_name");
@@ -71,8 +71,10 @@ public final class Protocol1_20To1_19_4 extends BackwardsProtocol<ClientboundPac
translatableRewriter.registerBossEvent(ClientboundPackets1_19_4.BOSS_EVENT);
translatableRewriter.registerComponentPacket(ClientboundPackets1_19_4.DISCONNECT);
translatableRewriter.registerTabList(ClientboundPackets1_19_4.TAB_LIST);
translatableRewriter.registerSetPlayerTeam1_13(ClientboundPackets1_19_4.SET_PLAYER_TEAM);
translatableRewriter.registerComponentPacket(ClientboundPackets1_19_4.SYSTEM_CHAT);
translatableRewriter.registerComponentPacket(ClientboundPackets1_19_4.DISGUISED_CHAT);
translatableRewriter.registerSetObjective(ClientboundPackets1_19_4.SET_OBJECTIVE);
translatableRewriter.registerPing();
registerClientbound(ClientboundPackets1_19_4.UPDATE_ENABLED_FEATURES, wrapper -> {
@@ -112,7 +112,7 @@ public final class BlockItemPacketRewriter1_20 extends BackwardsItemRewriter<Cli
if (wrapper.passthrough(Types.BOOLEAN)) {
wrapper.passthrough(Types.COMPONENT); // Title
wrapper.passthrough(Types.COMPONENT); // Description
handleItemToClient(wrapper.user(), wrapper.passthrough(Types.ITEM1_13_2)); // Icon
passthroughClientboundItem(wrapper); // Icon
wrapper.passthrough(Types.VAR_INT); // Frame type
int flags = wrapper.passthrough(Types.INT); // Flags
if ((flags & 1) != 0) {
@@ -153,12 +153,12 @@ public final class BlockItemPacketRewriter1_20 extends BackwardsItemRewriter<Cli
}
@Override
public @Nullable Item handleItemToClient(UserConnection connection, @Nullable final Item item) {
public @Nullable Item handleItemToClient(UserConnection connection, @Nullable Item item) {
if (item == null) {
return null;
}
super.handleItemToClient(connection, item);
item = super.handleItemToClient(connection, item);
// Remove new trim tags
final CompoundTag trimTag;
@@ -177,12 +177,12 @@ public final class BlockItemPacketRewriter1_20 extends BackwardsItemRewriter<Cli
}
@Override
public @Nullable Item handleItemToServer(UserConnection connection, @Nullable final Item item) {
public @Nullable Item handleItemToServer(UserConnection connection, @Nullable Item item) {
if (item == null) {
return null;
}
super.handleItemToServer(connection, item);
item = super.handleItemToServer(connection, item);
// Add back original trim tag
final Tag trimTag;
@@ -0,0 +1,273 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viabackwards.protocol.v1_21_11to1_21_9;
import com.viaversion.nbt.tag.ByteTag;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.IntTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.NumberTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.data.BackwardsMappingData;
import com.viaversion.viabackwards.api.rewriters.BackwardsRegistryRewriter;
import com.viaversion.viabackwards.api.rewriters.SoundRewriter;
import com.viaversion.viabackwards.api.rewriters.text.NBTComponentRewriter;
import com.viaversion.viabackwards.protocol.v1_21_11to1_21_9.rewriter.BlockItemPacketRewriter1_21_11;
import com.viaversion.viabackwards.protocol.v1_21_11to1_21_9.rewriter.ComponentRewriter1_21_11;
import com.viaversion.viabackwards.protocol.v1_21_11to1_21_9.rewriter.EntityPacketRewriter1_21_11;
import com.viaversion.viabackwards.protocol.v1_21_11to1_21_9.storage.GameTimeStorage;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.FullMappings;
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.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_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.ClientboundPacket1_21_9;
import com.viaversion.viaversion.protocols.v1_21_7to1_21_9.packet.ClientboundPackets1_21_9;
import com.viaversion.viaversion.protocols.v1_21_7to1_21_9.packet.ServerboundConfigurationPackets1_21_9;
import com.viaversion.viaversion.protocols.v1_21_7to1_21_9.packet.ServerboundPacket1_21_9;
import com.viaversion.viaversion.protocols.v1_21_9to1_21_11.Protocol1_21_9To1_21_11;
import com.viaversion.viaversion.protocols.v1_21_9to1_21_11.packet.ClientboundPacket1_21_11;
import com.viaversion.viaversion.protocols.v1_21_9to1_21_11.packet.ClientboundPackets1_21_11;
import com.viaversion.viaversion.rewriter.AttributeRewriter;
import com.viaversion.viaversion.rewriter.ParticleRewriter;
import com.viaversion.viaversion.rewriter.RegistryDataRewriter;
import com.viaversion.viaversion.rewriter.StatisticsRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
import com.viaversion.viaversion.util.Key;
import com.viaversion.viaversion.util.TagUtil;
import java.util.function.Function;
import org.checkerframework.checker.nullness.qual.Nullable;
import static com.viaversion.viaversion.util.ProtocolUtil.packetTypeMap;
import static com.viaversion.viaversion.util.TagUtil.getNamespacedTag;
public final class Protocol1_21_11To1_21_9 extends BackwardsProtocol<ClientboundPacket1_21_11, ClientboundPacket1_21_9, ServerboundPacket1_21_9, ServerboundPacket1_21_9> {
public static final BackwardsMappingData MAPPINGS = new BackwardsMappingData("1.21.11", "1.21.9", Protocol1_21_9To1_21_11.class);
private static final int END_FOG_COLOR = 10518688;
private static final int OVERWORLD_FOG_COLOR = -4138753;
private final EntityPacketRewriter1_21_11 entityRewriter = new EntityPacketRewriter1_21_11(this);
private final BlockItemPacketRewriter1_21_11 itemRewriter = new BlockItemPacketRewriter1_21_11(this);
private final ParticleRewriter<ClientboundPacket1_21_11> particleRewriter = new ParticleRewriter<>(this);
private final NBTComponentRewriter<ClientboundPacket1_21_11> translatableRewriter = new ComponentRewriter1_21_11(this);
private final TagRewriter<ClientboundPacket1_21_11> tagRewriter = new TagRewriter<>(this);
private final RegistryDataRewriter registryDataRewriter = new BackwardsRegistryRewriter(this) {
@Override
protected void updateType(final CompoundTag tag, final String key, final FullMappings mappings) {
super.updateType(tag, key, mappings);
if (key.equals("sound") && tag.get(key) instanceof ListTag<?> listTag) {
// From a compact list to a single value
final Tag first;
if (listTag.isEmpty()) {
first = new StringTag(mappings.mappedIdentifier(0)); // Dummy
} else {
first = listTag.get(0);
}
tag.put(key, first);
}
}
};
public Protocol1_21_11To1_21_9() {
super(ClientboundPacket1_21_11.class, ClientboundPacket1_21_9.class, ServerboundPacket1_21_9.class, ServerboundPacket1_21_9.class);
}
private void moveAttribute(final CompoundTag baseTag, @Nullable final CompoundTag attributes, final String key, final String mappedKey, final Function<Tag, Tag> tagMapper, @Nullable final Tag defaultTag) {
final Tag attributeTag;
if (attributes != null && (attributeTag = getNamespacedTag(attributes, key)) != null) {
baseTag.put(mappedKey, tagMapper.apply(attributeTag));
} else if (defaultTag != null) {
baseTag.put(mappedKey, defaultTag);
}
}
private int floatsToARGB(final float r, final float g, final float b) {
return 255 << 24 | (int) (r * 255) << 16 | (int) (g * 255) << 8 | (int) (b * 255);
}
@Override
protected void registerPackets() {
super.registerPackets();
// Add back mandatory fields from attributes, though most don't have any use in the client
registryDataRewriter.addHandler("dimension_type", (key, tag) -> {
if (Key.equals(key, "the_nether")) {
tag.putString("effects", "minecraft:the_nether");
tag.putBoolean("natural", false);
} else if (Key.equals(key, "the_end")) {
tag.putString("effects", "minecraft:the_end");
tag.putBoolean("natural", false);
} else {
tag.putString("effects", "minecraft:overworld");
tag.putBoolean("natural", true);
}
final ByteTag trueTag = new ByteTag((byte) 1);
final CompoundTag attributes = tag.getCompoundTag("attributes");
moveAttribute(tag, attributes, "visual/cloud_height", "cloud_height", Function.identity(), null);
moveAttribute(tag, attributes, "gameplay/can_start_raid", "has_raids", Function.identity(), trueTag);
moveAttribute(tag, attributes, "gameplay/can_start_raid", "has_raids", Function.identity(), trueTag);
moveAttribute(tag, attributes, "gameplay/piglins_zombify", "piglin_safe", attributeTag -> ((NumberTag) attributeTag).asBoolean() ? ByteTag.ZERO : trueTag, ByteTag.ZERO);
moveAttribute(tag, attributes, "gameplay/respawn_anchor_works", "respawn_anchor_works", Function.identity(), trueTag);
moveAttribute(tag, attributes, "gameplay/bed_rule", "bed_works", attributeTag -> {
final CompoundTag bedRule = (CompoundTag) attributeTag;
return bedRule.getBoolean("can_sleep") || bedRule.getBoolean("can_set_spawn") ? trueTag : ByteTag.ZERO;
}, trueTag);
// Many different functions back into one, all have different effects on the client, so pick the most important one...
moveAttribute(tag, attributes, "gameplay/fast_lava", "ultrawarm", Function.identity(), ByteTag.ZERO);
});
registryDataRewriter.addHandler("worldgen/biome", (key, tag) -> {
final CompoundTag effects = tag.getCompoundTag("effects");
final CompoundTag attributes = tag.removeUnchecked("attributes");
moveAttribute(effects, attributes, "visual/sky_color", "sky_color", this::mapColor, new IntTag(0));
moveAttribute(effects, attributes, "visual/water_fog_color", "water_fog_color", this::mapColor, new IntTag(-16448205));
moveAttribute(effects, attributes, "visual/fog_color", "fog_color", this::mapColor, new IntTag(Key.equals(key, "the_end") ? END_FOG_COLOR : OVERWORLD_FOG_COLOR)); // overworld fog color as default
moveAttribute(effects, effects, "water_color", "water_color", this::mapColor, new IntTag(4159204));
moveAttribute(effects, effects, "foliage_color", "foliage_color", this::mapColor, null);
moveAttribute(effects, effects, "dry_foliage_color", "dry_foliage_color", this::mapColor, null);
moveAttribute(effects, effects, "grass_color", "grass_color", this::mapColor, null);
});
registryDataRewriter.addHandler("enchantment", (key, tag) -> {
final CompoundTag effects = tag.getCompoundTag("effects");
if (effects != null) {
TagUtil.removeNamespaced(effects, "post_piercing_attack");
}
});
registryDataRewriter.remove("zombie_nautilus_variant");
registryDataRewriter.remove("timeline");
registerClientbound(ClientboundConfigurationPackets1_21_9.REGISTRY_DATA, registryDataRewriter::handle);
tagRewriter.removeTags("timeline");
tagRewriter.registerGeneric(ClientboundPackets1_21_11.UPDATE_TAGS);
tagRewriter.registerGeneric(ClientboundConfigurationPackets1_21_9.UPDATE_TAGS);
final SoundRewriter<ClientboundPacket1_21_11> soundRewriter = new SoundRewriter<>(this);
soundRewriter.registerSound1_19_3(ClientboundPackets1_21_11.SOUND);
soundRewriter.registerSound1_19_3(ClientboundPackets1_21_11.SOUND_ENTITY);
soundRewriter.registerStopSound(ClientboundPackets1_21_11.STOP_SOUND);
new StatisticsRewriter<>(this).register(ClientboundPackets1_21_11.AWARD_STATS);
new AttributeRewriter<>(this).register1_21(ClientboundPackets1_21_11.UPDATE_ATTRIBUTES);
translatableRewriter.registerOpenScreen1_14(ClientboundPackets1_21_11.OPEN_SCREEN);
translatableRewriter.registerComponentPacket(ClientboundPackets1_21_11.SET_ACTION_BAR_TEXT);
translatableRewriter.registerComponentPacket(ClientboundPackets1_21_11.SET_TITLE_TEXT);
translatableRewriter.registerComponentPacket(ClientboundPackets1_21_11.SET_SUBTITLE_TEXT);
translatableRewriter.registerBossEvent(ClientboundPackets1_21_11.BOSS_EVENT);
translatableRewriter.registerComponentPacket(ClientboundPackets1_21_11.DISCONNECT);
translatableRewriter.registerComponentPacket(ClientboundConfigurationPackets1_21_9.DISCONNECT);
translatableRewriter.registerTabList(ClientboundPackets1_21_11.TAB_LIST);
translatableRewriter.registerPlayerCombatKill1_20(ClientboundPackets1_21_11.PLAYER_COMBAT_KILL);
translatableRewriter.registerPlayerInfoUpdate1_21_4(ClientboundPackets1_21_11.PLAYER_INFO_UPDATE);
translatableRewriter.registerComponentPacket(ClientboundPackets1_21_11.SYSTEM_CHAT);
translatableRewriter.registerDisguisedChat(ClientboundPackets1_21_11.DISGUISED_CHAT);
translatableRewriter.registerPlayerChat1_21_5(ClientboundPackets1_21_11.PLAYER_CHAT);
translatableRewriter.registerSetObjective(ClientboundPackets1_21_11.SET_OBJECTIVE);
translatableRewriter.registerSetScore1_20_3(ClientboundPackets1_21_11.SET_SCORE);
translatableRewriter.registerPing();
particleRewriter.registerLevelParticles1_21_4(ClientboundPackets1_21_11.LEVEL_PARTICLES);
particleRewriter.registerExplode1_21_9(ClientboundPackets1_21_11.EXPLODE);
}
@Override
public void init(final UserConnection connection) {
addEntityTracker(connection, new EntityTrackerBase(connection, EntityTypes1_21_11.PLAYER));
addItemHasher(connection, new ItemHasherBase(this, connection));
connection.put(new GameTimeStorage());
}
@Override
public BackwardsMappingData getMappingData() {
return MAPPINGS;
}
@Override
public EntityPacketRewriter1_21_11 getEntityRewriter() {
return entityRewriter;
}
@Override
public BlockItemPacketRewriter1_21_11 getItemRewriter() {
return itemRewriter;
}
@Override
public RegistryDataRewriter getRegistryDataRewriter() {
return registryDataRewriter;
}
@Override
public ParticleRewriter<ClientboundPacket1_21_11> getParticleRewriter() {
return particleRewriter;
}
@Override
public NBTComponentRewriter<ClientboundPacket1_21_11> getComponentRewriter() {
return translatableRewriter;
}
@Override
public TagRewriter<ClientboundPacket1_21_11> getTagRewriter() {
return tagRewriter;
}
@Override
public VersionedTypesHolder types() {
return VersionedTypes.V1_21_11;
}
@Override
public VersionedTypesHolder mappedTypes() {
return VersionedTypes.V1_21_9;
}
@Override
protected PacketTypesProvider<ClientboundPacket1_21_11, ClientboundPacket1_21_9, ServerboundPacket1_21_9, ServerboundPacket1_21_9> createPacketTypesProvider() {
return new SimplePacketTypesProvider<>(
packetTypeMap(unmappedClientboundPacketType, ClientboundPackets1_21_11.class, ClientboundConfigurationPackets1_21_9.class),
packetTypeMap(mappedClientboundPacketType, ClientboundPackets1_21_9.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)
);
}
private Tag mapColor(final Tag attributeTag) {
if (attributeTag instanceof ListTag<?> listTag) {
final NumberTag r = ((NumberTag) listTag.get(0));
final NumberTag g = ((NumberTag) listTag.get(1));
final NumberTag b = ((NumberTag) listTag.get(2));
return new IntTag(floatsToARGB(r.asFloat(), g.asFloat(), b.asFloat()));
} else if (attributeTag instanceof StringTag stringTag) {
// Remove '#' and parse hex string
return new IntTag(Integer.parseInt(stringTag.getValue().substring(1), 16));
}
return attributeTag;
}
}
@@ -0,0 +1,307 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viabackwards.protocol.v1_21_11to1_21_9.rewriter;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.IntTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viabackwards.api.rewriters.BackwardsStructuredItemRewriter;
import com.viaversion.viabackwards.protocol.v1_21_11to1_21_9.Protocol1_21_11To1_21_9;
import com.viaversion.viabackwards.protocol.v1_21_11to1_21_9.storage.GameTimeStorage;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.Holder;
import com.viaversion.viaversion.api.minecraft.SoundEvent;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataContainer;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.minecraft.item.data.AttackRange;
import com.viaversion.viaversion.api.minecraft.item.data.DamageType;
import com.viaversion.viaversion.api.minecraft.item.data.KineticWeapon;
import com.viaversion.viaversion.api.minecraft.item.data.PiercingWeapon;
import com.viaversion.viaversion.api.minecraft.item.data.SwingAnimation;
import com.viaversion.viaversion.api.minecraft.item.data.UseEffects;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_21_5;
import com.viaversion.viaversion.protocols.v1_21_4to1_21_5.rewriter.RecipeDisplayRewriter1_21_5;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ServerboundPackets1_21_6;
import com.viaversion.viaversion.protocols.v1_21_7to1_21_9.packet.ServerboundPacket1_21_9;
import com.viaversion.viaversion.protocols.v1_21_9to1_21_11.packet.ClientboundPacket1_21_11;
import com.viaversion.viaversion.protocols.v1_21_9to1_21_11.packet.ClientboundPackets1_21_11;
import com.viaversion.viaversion.rewriter.BlockRewriter;
import com.viaversion.viaversion.rewriter.RecipeDisplayRewriter;
import com.viaversion.viaversion.util.Either;
import org.checkerframework.checker.nullness.qual.Nullable;
import static com.viaversion.viaversion.protocols.v1_21_9to1_21_11.rewriter.BlockItemPacketRewriter1_21_11.downgradeData;
import static com.viaversion.viaversion.protocols.v1_21_9to1_21_11.rewriter.BlockItemPacketRewriter1_21_11.upgradeData;
public final class BlockItemPacketRewriter1_21_11 extends BackwardsStructuredItemRewriter<ClientboundPacket1_21_11, ServerboundPacket1_21_9, Protocol1_21_11To1_21_9> {
public BlockItemPacketRewriter1_21_11(final Protocol1_21_11To1_21_9 protocol) {
super(protocol);
}
@Override
public void registerPackets() {
final BlockRewriter<ClientboundPacket1_21_11> blockRewriter = BlockRewriter.for1_20_2(protocol);
blockRewriter.registerBlockEvent(ClientboundPackets1_21_11.BLOCK_EVENT);
blockRewriter.registerBlockUpdate(ClientboundPackets1_21_11.BLOCK_UPDATE);
blockRewriter.registerSectionBlocksUpdate1_20(ClientboundPackets1_21_11.SECTION_BLOCKS_UPDATE);
blockRewriter.registerLevelEvent1_21(ClientboundPackets1_21_11.LEVEL_EVENT, 2001);
blockRewriter.registerLevelChunk1_19(ClientboundPackets1_21_11.LEVEL_CHUNK_WITH_LIGHT, ChunkType1_21_5::new);
blockRewriter.registerBlockEntityData(ClientboundPackets1_21_11.BLOCK_ENTITY_DATA);
registerSetCursorItem(ClientboundPackets1_21_11.SET_CURSOR_ITEM);
registerSetPlayerInventory(ClientboundPackets1_21_11.SET_PLAYER_INVENTORY);
registerCooldown1_21_2(ClientboundPackets1_21_11.COOLDOWN);
registerSetContent1_21_2(ClientboundPackets1_21_11.CONTAINER_SET_CONTENT);
registerSetSlot1_21_2(ClientboundPackets1_21_11.CONTAINER_SET_SLOT);
registerAdvancements1_20_3(ClientboundPackets1_21_11.UPDATE_ADVANCEMENTS);
registerSetEquipment(ClientboundPackets1_21_11.SET_EQUIPMENT);
registerMerchantOffers1_20_5(ClientboundPackets1_21_11.MERCHANT_OFFERS);
registerContainerClick1_21_5(ServerboundPackets1_21_6.CONTAINER_CLICK);
registerSetCreativeModeSlot1_21_5(ServerboundPackets1_21_6.SET_CREATIVE_MODE_SLOT);
final RecipeDisplayRewriter<ClientboundPacket1_21_11> recipeRewriter = new RecipeDisplayRewriter1_21_5<>(protocol);
recipeRewriter.registerUpdateRecipes(ClientboundPackets1_21_11.UPDATE_RECIPES);
recipeRewriter.registerRecipeBookAdd(ClientboundPackets1_21_11.RECIPE_BOOK_ADD);
recipeRewriter.registerPlaceGhostRecipe(ClientboundPackets1_21_11.PLACE_GHOST_RECIPE);
protocol.registerClientbound(ClientboundPackets1_21_11.SET_BORDER_LERP_SIZE, wrapper -> {
wrapper.passthrough(Types.DOUBLE); // oldSize
wrapper.passthrough(Types.DOUBLE); // newSize
wrapper.write(Types.VAR_LONG, wrapper.read(Types.VAR_LONG) * 50); // lerpTime
});
protocol.registerClientbound(ClientboundPackets1_21_11.INITIALIZE_BORDER, wrapper -> {
wrapper.passthrough(Types.DOUBLE); // newCenterX
wrapper.passthrough(Types.DOUBLE); // newCenterZ
wrapper.passthrough(Types.DOUBLE); // oldSize
wrapper.passthrough(Types.DOUBLE); // newSize
wrapper.write(Types.VAR_LONG, wrapper.read(Types.VAR_LONG) * 50); // lerpTime
});
protocol.registerClientbound(ClientboundPackets1_21_11.SET_TIME, wrapper -> {
final long gameTime = wrapper.passthrough(Types.LONG);
wrapper.user().get(GameTimeStorage.class).setGameTime(gameTime);
});
protocol.registerServerbound(ServerboundPackets1_21_6.CLIENT_TICK_END, wrapper -> {
wrapper.user().get(GameTimeStorage.class).incrementGameTime();
});
}
@Override
protected void handleItemDataComponentsToClient(final UserConnection connection, final Item item, final StructuredDataContainer container) {
super.handleItemDataComponentsToClient(connection, item, container);
downgradeData(item, container);
}
@Override
protected void handleItemDataComponentsToServer(final UserConnection connection, final Item item, final StructuredDataContainer container) {
super.handleItemDataComponentsToServer(connection, item, container);
upgradeData(item, container);
}
@Override
protected void restoreBackupData(final Item item, final StructuredDataContainer container, final CompoundTag customData) {
super.restoreBackupData(item, container, customData);
if (!(customData.remove(nbtTagName("backup")) instanceof final CompoundTag backupTag)) {
return;
}
final CompoundTag swingTag = backupTag.getCompoundTag("swing_animation");
if (swingTag != null) {
final int type = swingTag.getInt("type");
final int duration = swingTag.getInt("duration");
container.set(StructuredDataKey.SWING_ANIMATION, new SwingAnimation(type, duration));
}
final CompoundTag kineticTag = backupTag.getCompoundTag("kinetic_weapon");
if (kineticTag != null) {
final int contactCooldownTicks = kineticTag.getInt("contact_cooldown_ticks");
final int delayTicks = kineticTag.getInt("delay_ticks");
final KineticWeapon.Condition damageConditions = loadDamageCondition(kineticTag, "damage_conditions");
final KineticWeapon.Condition dismountConditions = loadDamageCondition(kineticTag, "dismount_conditions");
final KineticWeapon.Condition knockbackConditions = loadDamageCondition(kineticTag, "knockback_conditions");
final float forwardMovement = kineticTag.getFloat("forward_movement");
final float damageMultiplier = kineticTag.getFloat("damage_multiplier");
final Holder<SoundEvent> sound = kineticTag.contains("sound") ? restoreSoundEventHolder(kineticTag, "sound") : null;
final Holder<SoundEvent> hitSound = kineticTag.contains("hit_sound") ? restoreSoundEventHolder(kineticTag, "hit_sound") : null;
container.set(StructuredDataKey.KINETIC_WEAPON, new KineticWeapon(contactCooldownTicks, delayTicks, damageConditions, dismountConditions, knockbackConditions, forwardMovement, damageMultiplier, sound, hitSound));
}
final CompoundTag piercingTag = backupTag.getCompoundTag("piercing_weapon");
if (piercingTag != null) {
final boolean dealsKnockback = piercingTag.getBoolean("deals_knockback");
final boolean dismounts = piercingTag.getBoolean("dismounts");
final Holder<SoundEvent> sound = piercingTag.contains("sound") ? restoreSoundEventHolder(piercingTag, "sound") : null;
final Holder<SoundEvent> hitSound = piercingTag.contains("hit_sound") ? restoreSoundEventHolder(piercingTag, "hit_sound") : null;
container.set(StructuredDataKey.PIERCING_WEAPON, new PiercingWeapon(dealsKnockback, dismounts, sound, hitSound));
}
final Tag damageTypeId = backupTag.get("damage_type_id");
if (damageTypeId != null) {
if (damageTypeId instanceof StringTag stringTag) {
container.set(StructuredDataKey.DAMAGE_TYPE, new DamageType(Either.right(stringTag.getValue())));
} else if (damageTypeId instanceof IntTag intTag) {
container.set(StructuredDataKey.DAMAGE_TYPE, new DamageType(Either.left(intTag.asInt())));
}
}
final CompoundTag useEffectsTag = backupTag.getCompoundTag("use_effects");
if (useEffectsTag != null) {
final boolean canSprint = useEffectsTag.getBoolean("can_sprint");
final boolean interactVibrations = useEffectsTag.getBoolean("interact_vibrations");
final float speedMultiplier = useEffectsTag.getFloat("speed_multiplier");
container.set(StructuredDataKey.USE_EFFECTS, new UseEffects(canSprint, interactVibrations, speedMultiplier));
}
final CompoundTag attackRangeTag = backupTag.getCompoundTag("attack_range");
if (attackRangeTag != null) {
final float minRange = attackRangeTag.getFloat("min_range");
final float maxRange = attackRangeTag.getFloat("max_range");
final float minCreativeRange = attackRangeTag.getFloat("min_creative_reach");
final float maxCreativeRange = attackRangeTag.getFloat("max_creative_reach");
final float hitboxMargin = attackRangeTag.getFloat("hitbox_margin");
final float mobFactor = attackRangeTag.getFloat("mob_factor");
container.set(StructuredDataKey.ATTACK_RANGE, new AttackRange(minRange, maxRange, minCreativeRange, maxCreativeRange, hitboxMargin, mobFactor));
}
final Tag zombieNautilusVariantTag = backupTag.get("zombie_nautilus_variant");
if (zombieNautilusVariantTag != null) {
if (zombieNautilusVariantTag instanceof StringTag stringTag) {
container.set(StructuredDataKey.ZOMBIE_NAUTILUS_VARIANT, Either.right(stringTag.getValue()));
} else if (zombieNautilusVariantTag instanceof IntTag intTag) {
container.set(StructuredDataKey.ZOMBIE_NAUTILUS_VARIANT, Either.left(intTag.asInt()));
}
}
restoreFloatData(StructuredDataKey.MINIMUM_ATTACK_CHARGE, container, backupTag);
}
private KineticWeapon.Condition loadDamageCondition(final CompoundTag tag, final String key) {
final CompoundTag conditionTag = tag.getCompoundTag(key);
if (conditionTag == null) {
return null;
}
final int maxDurationTicks = conditionTag.getInt("max_duration_ticks");
final float minSpeed = conditionTag.getFloat("min_speed");
final float minRelativeSpeed = conditionTag.getFloat("min_relative_speed");
return new KineticWeapon.Condition(maxDurationTicks, minSpeed, minRelativeSpeed);
}
@Override
protected void backupInconvertibleData(final UserConnection connection, final Item item, final StructuredDataContainer dataContainer, final CompoundTag backupTag) {
super.backupInconvertibleData(connection, item, dataContainer, backupTag);
final SwingAnimation swingAnimation = dataContainer.get(StructuredDataKey.SWING_ANIMATION);
if (swingAnimation != null) {
final CompoundTag swingTag = new CompoundTag();
swingTag.putInt("type", swingAnimation.type());
swingTag.putInt("duration", swingAnimation.duration());
backupTag.put("swing_animation", swingTag);
}
final KineticWeapon kineticWeapon = dataContainer.get(StructuredDataKey.KINETIC_WEAPON);
if (kineticWeapon != null) {
final CompoundTag kineticTag = new CompoundTag();
kineticTag.putInt("contact_cooldown_ticks", kineticWeapon.contactCooldownTicks());
kineticTag.putInt("delay_ticks", kineticWeapon.delayTicks());
saveDamageCondition(kineticTag, "damage_conditions", kineticWeapon.damageConditions());
saveDamageCondition(kineticTag, "dismount_conditions", kineticWeapon.dismountConditions());
saveDamageCondition(kineticTag, "knockback_conditions", kineticWeapon.knockbackConditions());
kineticTag.putFloat("forward_movement", kineticWeapon.forwardMovement());
kineticTag.putFloat("damage_multiplier", kineticWeapon.damageMultiplier());
if (kineticWeapon.sound() != null) {
kineticTag.put("sound", holderToTag(kineticWeapon.sound(), this::saveSoundEvent));
}
if (kineticWeapon.hitSound() != null) {
kineticTag.put("hit_sound", holderToTag(kineticWeapon.hitSound(), this::saveSoundEvent));
}
backupTag.put("kinetic_weapon", kineticTag);
}
final PiercingWeapon piercingWeapon = dataContainer.get(StructuredDataKey.PIERCING_WEAPON);
if (piercingWeapon != null) {
final CompoundTag piercingTag = new CompoundTag();
piercingTag.putBoolean("deals_knockback", piercingWeapon.dealsKnockback());
piercingTag.putBoolean("dismounts", piercingWeapon.dismounts());
if (piercingWeapon.sound() != null) {
piercingTag.put("sound", holderToTag(piercingWeapon.sound(), this::saveSoundEvent));
}
if (piercingWeapon.hitSound() != null) {
piercingTag.put("hit_sound", holderToTag(piercingWeapon.hitSound(), this::saveSoundEvent));
}
backupTag.put("piercing_weapon", piercingTag);
}
final DamageType damageType = dataContainer.get(StructuredDataKey.DAMAGE_TYPE);
if (damageType != null) {
if (damageType.id().isLeft()) {
backupTag.putInt("damage_type_id", damageType.id().left());
} else {
backupTag.putString("damage_type_id", damageType.id().right());
}
}
final UseEffects useEffects = dataContainer.get(StructuredDataKey.USE_EFFECTS);
if (useEffects != null) {
final CompoundTag useEffectsTag = new CompoundTag();
useEffectsTag.putBoolean("can_sprint", useEffects.canSprint());
useEffectsTag.putBoolean("interact_vibrations", useEffects.interactVibrations());
useEffectsTag.putFloat("speed_multiplier", useEffects.speedMultiplier());
backupTag.put("use_effects", useEffectsTag);
}
final AttackRange attackRange = dataContainer.get(StructuredDataKey.ATTACK_RANGE);
if (attackRange != null) {
final CompoundTag attackRangeTag = new CompoundTag();
attackRangeTag.putFloat("min_range", attackRange.minRange());
attackRangeTag.putFloat("max_range", attackRange.maxRange());
attackRangeTag.putFloat("min_creative_reach", attackRange.minCreativeRange());
attackRangeTag.putFloat("max_creative_reach", attackRange.maxCreativeRange());
attackRangeTag.putFloat("hitbox_margin", attackRange.hitboxMargin());
attackRangeTag.putFloat("mob_factor", attackRange.mobFactor());
backupTag.put("attack_range", attackRangeTag);
}
final Either<Integer, String> zombieNautilusVariant = dataContainer.get(StructuredDataKey.ZOMBIE_NAUTILUS_VARIANT);
if (zombieNautilusVariant != null) {
if (zombieNautilusVariant.isLeft()) {
backupTag.putInt("zombie_nautilus_variant", zombieNautilusVariant.left());
} else {
backupTag.putString("zombie_nautilus_variant", zombieNautilusVariant.right());
}
}
saveFloatData(StructuredDataKey.MINIMUM_ATTACK_CHARGE, dataContainer, backupTag);
}
private void saveDamageCondition(final CompoundTag tag, final String key, final KineticWeapon.@Nullable Condition condition) {
if (condition == null) {
return;
}
final CompoundTag conditionTag = new CompoundTag();
conditionTag.putInt("max_duration_ticks", condition.maxDurationTicks());
conditionTag.putFloat("min_speed", condition.minSpeed());
conditionTag.putFloat("min_relative_speed", condition.minRelativeSpeed());
tag.put(key, conditionTag);
}
}
@@ -0,0 +1,43 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viabackwards.protocol.v1_21_11to1_21_9.rewriter;
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.api.minecraft.data.StructuredDataKey;
import com.viaversion.viaversion.protocols.v1_21_9to1_21_11.packet.ClientboundPacket1_21_11;
public final class ComponentRewriter1_21_11 extends NBTComponentRewriter<ClientboundPacket1_21_11> {
public ComponentRewriter1_21_11(final BackwardsProtocol<ClientboundPacket1_21_11, ?, ?, ?> 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;
}
removeDataComponents(componentsTag, StructuredDataKey.SWING_ANIMATION, StructuredDataKey.KINETIC_WEAPON, StructuredDataKey.PIERCING_WEAPON,
StructuredDataKey.DAMAGE_TYPE, StructuredDataKey.MINIMUM_ATTACK_CHARGE, StructuredDataKey.USE_EFFECTS, StructuredDataKey.ZOMBIE_NAUTILUS_VARIANT, StructuredDataKey.ATTACK_RANGE);
}
}
@@ -0,0 +1,114 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viabackwards.protocol.v1_21_11to1_21_9.rewriter;
import com.viaversion.viabackwards.api.rewriters.EntityRewriter;
import com.viaversion.viabackwards.protocol.v1_21_11to1_21_9.Protocol1_21_11To1_21_9;
import com.viaversion.viabackwards.protocol.v1_21_11to1_21_9.storage.GameTimeStorage;
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.EntityData;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_21_11;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_21_9;
import com.viaversion.viaversion.api.type.types.version.VersionedTypes;
import com.viaversion.viaversion.protocols.v1_21_7to1_21_9.packet.ClientboundPackets1_21_9;
import com.viaversion.viaversion.protocols.v1_21_9to1_21_11.packet.ClientboundPacket1_21_11;
import com.viaversion.viaversion.protocols.v1_21_9to1_21_11.packet.ClientboundPackets1_21_11;
import com.viaversion.viaversion.rewriter.entitydata.EntityDataHandlerEvent;
import com.viaversion.viaversion.util.MathUtil;
public final class EntityPacketRewriter1_21_11 extends EntityRewriter<ClientboundPacket1_21_11, Protocol1_21_11To1_21_9> {
public EntityPacketRewriter1_21_11(final Protocol1_21_11To1_21_9 protocol) {
super(protocol, VersionedTypes.V1_21_9.entityDataTypes.optionalComponentType, VersionedTypes.V1_21_9.entityDataTypes.booleanType);
}
@Override
public void registerPackets() {
registerTrackerWithData1_21_9(ClientboundPackets1_21_11.ADD_ENTITY, EntityTypes1_21_11.FALLING_BLOCK);
registerSetEntityData(ClientboundPackets1_21_11.SET_ENTITY_DATA);
registerRemoveEntities(ClientboundPackets1_21_11.REMOVE_ENTITIES);
registerPlayerAbilities(ClientboundPackets1_21_11.PLAYER_ABILITIES);
registerGameEvent(ClientboundPackets1_21_11.GAME_EVENT);
registerLogin1_20_5(ClientboundPackets1_21_11.LOGIN);
registerRespawn1_20_5(ClientboundPackets1_21_11.RESPAWN);
protocol.registerClientbound(ClientboundPackets1_21_11.MOUNT_SCREEN_OPEN, ClientboundPackets1_21_9.HORSE_SCREEN_OPEN);
}
@Override
protected void registerRewrites() {
final EntityDataTypes1_21_11 unmappedDataTypes = VersionedTypes.V1_21_11.entityDataTypes;
final EntityDataTypes1_21_9 entityDataTypes = VersionedTypes.V1_21_9.entityDataTypes;
filter().handler((event, data) -> {
if (data.dataType() == unmappedDataTypes.humanoidArmType) {
final int arm = data.value();
data.setTypeAndValue(entityDataTypes.byteType, (byte) arm);
return;
} else if (data.dataType() == unmappedDataTypes.zombieNautilusVariantType) {
event.cancel();
return;
}
int id = data.dataType().typeId();
if (id > unmappedDataTypes.zombieNautilusVariantType.typeId()) {
id--;
}
data.setDataType(entityDataTypes.byId(id));
});
registerEntityDataTypeHandler1_20_3(
entityDataTypes.itemType,
entityDataTypes.blockStateType,
entityDataTypes.optionalBlockStateType,
entityDataTypes.particleType,
entityDataTypes.particlesType,
entityDataTypes.componentType,
entityDataTypes.optionalComponentType
);
filter().type(EntityTypes1_21_11.WOLF).index(21).handler(this::absoluteToRelativeTicks);
filter().type(EntityTypes1_21_11.BEE).index(18).handler(this::absoluteToRelativeTicks);
filter().type(EntityTypes1_21_11.ABSTRACT_NAUTILUS).cancel(17); // Tamable flags
filter().type(EntityTypes1_21_11.ABSTRACT_NAUTILUS).cancel(18); // Owner UUID
filter().type(EntityTypes1_21_11.ABSTRACT_NAUTILUS).cancel(19); // Dashing
filter().type(EntityTypes1_21_11.ZOMBIE_NAUTILUS).cancel(20); // Variant
}
private void absoluteToRelativeTicks(final EntityDataHandlerEvent event, final EntityData data) {
final long currentGameTime = event.user().get(GameTimeStorage.class).gameTime();
final long angerEndTime = data.value();
final int angerEndIn = (int) MathUtil.clamp(angerEndTime - currentGameTime, Integer.MIN_VALUE, Integer.MAX_VALUE);
data.setTypeAndValue(VersionedTypes.V1_21_9.entityDataTypes.varIntType, Math.max(angerEndIn, 0));
}
@Override
public void onMappingDataLoaded() {
mapTypes();
mapEntityTypeWithData(EntityTypes1_21_11.NAUTILUS, EntityTypes1_21_11.SQUID).tagName();
mapEntityTypeWithData(EntityTypes1_21_11.ZOMBIE_NAUTILUS, EntityTypes1_21_11.GLOW_SQUID).tagName();
mapEntityTypeWithData(EntityTypes1_21_11.CAMEL_HUSK, EntityTypes1_21_11.CAMEL).tagName();
mapEntityTypeWithData(EntityTypes1_21_11.PARCHED, EntityTypes1_21_11.SKELETON).tagName();
}
@Override
public EntityType typeFromId(final int type) {
return EntityTypes1_21_11.getTypeFromId(type);
}
}
@@ -0,0 +1,37 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viabackwards.protocol.v1_21_11to1_21_9.storage;
import com.viaversion.viaversion.api.connection.StorableObject;
public final class GameTimeStorage implements StorableObject {
private long gameTime;
public long gameTime() {
return gameTime;
}
public void setGameTime(final long gameTime) {
this.gameTime = gameTime;
}
public void incrementGameTime() {
gameTime++;
}
}
@@ -29,6 +29,7 @@ import com.viaversion.viabackwards.protocol.v1_21_2to1_21.storage.InventoryState
import com.viaversion.viabackwards.protocol.v1_21_2to1_21.storage.ItemTagStorage;
import com.viaversion.viabackwards.protocol.v1_21_2to1_21.storage.PlayerStorage;
import com.viaversion.viabackwards.protocol.v1_21_2to1_21.storage.RecipeStorage;
import com.viaversion.viabackwards.protocol.v1_21_2to1_21.storage.SignStorage;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_20_5;
import com.viaversion.viaversion.api.minecraft.item.data.ChatType;
@@ -94,11 +95,15 @@ public final class Protocol1_21_2To1_21 extends BackwardsProtocol<ClientboundPac
translatableRewriter.registerComponentPacket(ClientboundPackets1_21_2.SET_SUBTITLE_TEXT);
translatableRewriter.registerBossEvent(ClientboundPackets1_21_2.BOSS_EVENT);
translatableRewriter.registerComponentPacket(ClientboundPackets1_21_2.DISCONNECT);
translatableRewriter.registerComponentPacket(ClientboundConfigurationPackets1_21.DISCONNECT);
translatableRewriter.registerTabList(ClientboundPackets1_21_2.TAB_LIST);
translatableRewriter.registerSetPlayerTeam1_13(ClientboundPackets1_21_2.SET_PLAYER_TEAM);
translatableRewriter.registerPlayerCombatKill1_20(ClientboundPackets1_21_2.PLAYER_COMBAT_KILL);
translatableRewriter.registerComponentPacket(ClientboundPackets1_21_2.SYSTEM_CHAT);
translatableRewriter.registerDisguisedChat(ClientboundPackets1_21_2.DISGUISED_CHAT);
translatableRewriter.registerPlayerChat(ClientboundPackets1_21_2.PLAYER_CHAT, ChatType.TYPE);
translatableRewriter.registerSetObjective(ClientboundPackets1_21_2.SET_OBJECTIVE);
translatableRewriter.registerSetScore1_20_3(ClientboundPackets1_21_2.SET_SCORE);
translatableRewriter.registerPing();
registerServerbound(ServerboundPackets1_20_5.CLIENT_INFORMATION, this::clientInformation);
@@ -159,6 +164,7 @@ public final class Protocol1_21_2To1_21 extends BackwardsProtocol<ClientboundPac
user.put(new ItemTagStorage());
user.put(new RecipeStorage(this));
user.put(new PlayerStorage());
user.put(new SignStorage());
}
@Override
@@ -26,12 +26,20 @@ import com.viaversion.viabackwards.api.rewriters.BackwardsStructuredItemRewriter
import com.viaversion.viabackwards.protocol.v1_21_2to1_21.Protocol1_21_2To1_21;
import com.viaversion.viabackwards.protocol.v1_21_2to1_21.storage.InventoryStateIdStorage;
import com.viaversion.viabackwards.protocol.v1_21_2to1_21.storage.RecipeStorage;
import com.viaversion.viabackwards.protocol.v1_21_2to1_21.storage.SignStorage;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.MappingData;
import com.viaversion.viaversion.api.data.entity.EntityTracker;
import com.viaversion.viaversion.api.minecraft.BlockChangeRecord;
import com.viaversion.viaversion.api.minecraft.BlockPosition;
import com.viaversion.viaversion.api.minecraft.Holder;
import com.viaversion.viaversion.api.minecraft.HolderSet;
import com.viaversion.viaversion.api.minecraft.Particle;
import com.viaversion.viaversion.api.minecraft.SoundEvent;
import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
import com.viaversion.viaversion.api.minecraft.chunks.ChunkSection;
import com.viaversion.viaversion.api.minecraft.chunks.DataPalette;
import com.viaversion.viaversion.api.minecraft.chunks.PaletteType;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataContainer;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey;
import com.viaversion.viaversion.api.minecraft.item.Item;
@@ -42,10 +50,13 @@ import com.viaversion.viaversion.api.minecraft.item.data.Enchantments;
import com.viaversion.viaversion.api.minecraft.item.data.Equippable;
import com.viaversion.viaversion.api.minecraft.item.data.FoodProperties1_20_5;
import com.viaversion.viaversion.api.minecraft.item.data.Instrument1_21_2;
import com.viaversion.viaversion.api.minecraft.item.data.ItemModel;
import com.viaversion.viaversion.api.minecraft.item.data.PotionEffect;
import com.viaversion.viaversion.api.minecraft.item.data.PotionEffectData;
import com.viaversion.viaversion.api.minecraft.item.data.Repairable;
import com.viaversion.viaversion.api.minecraft.item.data.UseCooldown;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_20_2;
import com.viaversion.viaversion.api.type.types.version.VersionedTypes;
@@ -73,10 +84,7 @@ public final class BlockItemPacketRewriter1_21_2 extends BackwardsStructuredItem
public void registerPackets() {
final BlockRewriter<ClientboundPacket1_21_2> blockRewriter = BlockRewriter.for1_20_2(protocol);
blockRewriter.registerBlockEvent(ClientboundPackets1_21_2.BLOCK_EVENT);
blockRewriter.registerBlockUpdate(ClientboundPackets1_21_2.BLOCK_UPDATE);
blockRewriter.registerSectionBlocksUpdate1_20(ClientboundPackets1_21_2.SECTION_BLOCKS_UPDATE);
blockRewriter.registerLevelEvent1_21(ClientboundPackets1_21_2.LEVEL_EVENT, 2001);
blockRewriter.registerLevelChunk1_19(ClientboundPackets1_21_2.LEVEL_CHUNK_WITH_LIGHT, ChunkType1_20_2::new);
blockRewriter.registerBlockEntityData(ClientboundPackets1_21_2.BLOCK_ENTITY_DATA);
registerAdvancements1_20_3(ClientboundPackets1_21_2.UPDATE_ADVANCEMENTS);
@@ -84,6 +92,109 @@ public final class BlockItemPacketRewriter1_21_2 extends BackwardsStructuredItem
registerMerchantOffers1_20_5(ClientboundPackets1_21_2.MERCHANT_OFFERS);
registerSetCreativeModeSlot(ServerboundPackets1_20_5.SET_CREATIVE_MODE_SLOT);
protocol.registerClientbound(ClientboundPackets1_21_2.LEVEL_CHUNK_WITH_LIGHT, wrapper -> {
final Chunk chunk = blockRewriter.handleChunk1_19(wrapper, ChunkType1_20_2::new);
blockRewriter.handleBlockEntities(null, chunk, wrapper.user());
if (!wrapper.user().getProtocolInfo().protocolVersion().equalTo(ProtocolVersion.v1_21)) {
return;
}
final EntityTracker tracker = wrapper.user().getEntityTracker(Protocol1_21_2To1_21.class);
final SignStorage storage = wrapper.user().get(SignStorage.class);
storage.removeSigns(chunk.getX(), chunk.getZ());
for (int i = 0; i < chunk.getSections().length; i++) {
final ChunkSection section = chunk.getSections()[i];
final DataPalette blockPalette = section.palette(PaletteType.BLOCKS);
boolean containsSign = false;
for (int idx = 0; idx < blockPalette.size(); idx++) {
if (signBlockState(blockPalette.idByIndex(idx))) {
containsSign = true;
break;
}
}
if (!containsSign) {
continue;
}
for (int idx = 0; idx < ChunkSection.SIZE; idx++) {
if (!signBlockState(blockPalette.idAt(idx))) {
continue;
}
storage.addSign(new BlockPosition(
ChunkSection.xFromIndex(idx) + (chunk.getX() << 4),
ChunkSection.yFromIndex(idx) + tracker.currentMinY() + (i << 4),
ChunkSection.zFromIndex(idx) + (chunk.getZ() << 4)
));
}
}
});
protocol.registerClientbound(ClientboundPackets1_21_2.BLOCK_UPDATE, wrapper -> {
final BlockPosition position = wrapper.passthrough(Types.BLOCK_POSITION1_14);
final int blockId = wrapper.read(Types.VAR_INT);
final int mappedBlockId = protocol.getMappingData().getNewBlockStateId(blockId);
wrapper.write(Types.VAR_INT, mappedBlockId);
if (!wrapper.user().getProtocolInfo().protocolVersion().equalTo(ProtocolVersion.v1_21)) {
return;
}
final SignStorage storage = wrapper.user().get(SignStorage.class);
storage.removeSign(position);
if (signBlockState(mappedBlockId)) {
storage.addSign(position);
}
});
protocol.registerClientbound(ClientboundPackets1_21_2.SECTION_BLOCKS_UPDATE, wrapper -> {
final long position = wrapper.passthrough(Types.LONG);
final int chunkX = (int) (position >> 42);
final int chunkY = (int) (position << 44 >> 44);
final int chunkZ = (int) (position << 22 >> 42);
final SignStorage signStorage = wrapper.user().get(SignStorage.class);
final boolean equalToV1_21 = wrapper.user().getProtocolInfo().protocolVersion().equalTo(ProtocolVersion.v1_21);
for (final BlockChangeRecord record : wrapper.passthrough(Types.VAR_LONG_BLOCK_CHANGE_ARRAY)) {
record.setBlockId(protocol.getMappingData().getNewBlockStateId(record.getBlockId()));
if (!equalToV1_21) {
continue;
}
final int x = record.getSectionX() + (chunkX << 4);
final int y = record.getSectionY() + (chunkY << 4);
final int z = record.getSectionZ() + (chunkZ << 4);
final BlockPosition pos = new BlockPosition(x, y, z);
if (signBlockState(record.getBlockId())) {
signStorage.addSign(pos);
} else {
signStorage.removeSign(pos);
}
}
});
protocol.registerClientbound(ClientboundPackets1_21_2.OPEN_SIGN_EDITOR, wrapper -> {
if (!wrapper.user().getProtocolInfo().protocolVersion().equalTo(ProtocolVersion.v1_21)) {
return;
}
final BlockPosition position = wrapper.passthrough(Types.BLOCK_POSITION1_14);
if (!wrapper.user().get(SignStorage.class).isSign(position)) {
wrapper.cancel();
}
});
protocol.registerClientbound(ClientboundPackets1_21_2.COOLDOWN, wrapper -> {
final MappingData mappingData = protocol.getMappingData();
final String itemIdentifier = wrapper.read(Types.STRING);
@@ -295,17 +406,21 @@ public final class BlockItemPacketRewriter1_21_2 extends BackwardsStructuredItem
wrapper.write(Types.VAR_INT, (int) containerId);
}
private boolean signBlockState(final int blockStateId) {
return (blockStateId >= 4302 && blockStateId <= 4589) || (blockStateId >= 4762 && blockStateId <= 5625);
}
@Override
public Item handleItemToClient(final UserConnection connection, final Item item) {
public Item handleItemToClient(final UserConnection connection, Item item) {
backupInconvertibleData(item);
super.handleItemToClient(connection, item);
item = super.handleItemToClient(connection, item);
downgradeItemData(item);
return item;
}
@Override
public Item handleItemToServer(final UserConnection connection, final Item item) {
super.handleItemToServer(connection, item);
public Item handleItemToServer(final UserConnection connection, Item item) {
item = super.handleItemToServer(connection, item);
// Handle food properties item manually here - the only protocol that has it
// The other way around it's handled by the super handleItemToClient method
@@ -347,9 +462,9 @@ public final class BlockItemPacketRewriter1_21_2 extends BackwardsStructuredItem
backupTag.put("instrument_description", instrument.value().description());
}
final HolderSet repairable = data.get(StructuredDataKey.REPAIRABLE);
final Repairable repairable = data.get(StructuredDataKey.REPAIRABLE);
if (repairable != null) {
backupTag.put("repairable", holderSetToTag(repairable));
backupTag.put("repairable", holderSetToTag(repairable.items()));
}
final Enchantable enchantable = data.get(StructuredDataKey.ENCHANTABLE);
@@ -367,9 +482,9 @@ public final class BlockItemPacketRewriter1_21_2 extends BackwardsStructuredItem
backupTag.put("use_cooldown", tag);
}
final Key itemModel = data.get(StructuredDataKey.ITEM_MODEL);
final ItemModel itemModel = data.get(StructuredDataKey.ITEM_MODEL);
if (itemModel != null) {
backupTag.putString("item_model", itemModel.original());
backupTag.putString("item_model", itemModel.key().original());
}
final Equippable equippable = data.get(StructuredDataKey.EQUIPPABLE1_21_2);
@@ -522,7 +637,7 @@ public final class BlockItemPacketRewriter1_21_2 extends BackwardsStructuredItem
}
if (backupTag.contains("repairable")) {
data.set(StructuredDataKey.REPAIRABLE, restoreHolderSet(backupTag, "repairable"));
data.set(StructuredDataKey.REPAIRABLE, new Repairable(restoreHolderSet(backupTag, "repairable")));
}
final IntTag enchantable = backupTag.getIntTag("enchantable");
@@ -539,7 +654,7 @@ public final class BlockItemPacketRewriter1_21_2 extends BackwardsStructuredItem
final String itemModel = backupTag.getString("item_model");
if (itemModel != null) {
data.set(StructuredDataKey.ITEM_MODEL, Key.of(itemModel));
data.set(StructuredDataKey.ITEM_MODEL, new ItemModel(Key.of(itemModel)));
}
final CompoundTag equippable = backupTag.getCompoundTag("equippable");
@@ -57,7 +57,7 @@ public final class ComponentRewriter1_21_2 extends JsonNBTComponentRewriter<Clie
}
removeDataComponents(componentsTag, BlockItemPacketRewriter1_21_2.NEW_DATA_TO_REMOVE);
removeDataComponents(componentsTag, StructuredDataKey.DAMAGE_RESISTANT, StructuredDataKey.LOCK); // No point in updating these
removeDataComponents(componentsTag, StructuredDataKey.DAMAGE_RESISTANT, StructuredDataKey.LOCK1_21_2); // No point in updating these
}
@Override
@@ -23,9 +23,12 @@ import com.viaversion.nbt.tag.IntTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viabackwards.ViaBackwards;
import com.viaversion.viabackwards.api.rewriters.BackwardsRegistryRewriter;
import com.viaversion.viabackwards.api.rewriters.EntityRewriter;
import com.viaversion.viabackwards.protocol.v1_21_2to1_21.Protocol1_21_2To1_21;
import com.viaversion.viabackwards.protocol.v1_21_2to1_21.storage.PlayerStorage;
import com.viaversion.viabackwards.protocol.v1_21_2to1_21.storage.SignStorage;
import com.viaversion.viaversion.api.data.entity.EntityTracker;
import com.viaversion.viaversion.api.minecraft.Holder;
import com.viaversion.viaversion.api.minecraft.Particle;
import com.viaversion.viaversion.api.minecraft.RegistryEntry;
@@ -102,7 +105,7 @@ public final class EntityPacketRewriter1_21_2 extends EntityRewriter<Clientbound
}
});
final RegistryDataRewriter registryDataRewriter = new RegistryDataRewriter(protocol);
final RegistryDataRewriter registryDataRewriter = new BackwardsRegistryRewriter(protocol);
registryDataRewriter.addEnchantmentEffectRewriter("change_item_damage", tag -> tag.putString("type", "damage_item"));
protocol.registerClientbound(ClientboundConfigurationPackets1_21.REGISTRY_DATA, wrapper -> {
final String registryKey = Key.stripMinecraftNamespace(wrapper.passthrough(Types.STRING));
@@ -172,6 +175,11 @@ public final class EntityPacketRewriter1_21_2 extends EntityRewriter<Clientbound
wrapper.passthrough(Types.VAR_INT); // Portal cooldown
wrapper.read(Types.VAR_INT); // Sea level
final EntityTracker tracker = tracker(wrapper.user());
if (tracker.currentWorld() != null && !tracker.currentWorld().equals(world)) {
wrapper.user().put(new SignStorage());
}
trackWorldDataByKey1_20_5(wrapper.user(), dimensionId, world);
});
@@ -286,8 +286,7 @@ public final class RecipeStorage implements StorableObject {
yield new Item[]{new StructuredItem(rewriteItemId(id), 1)};
}
case 3 -> {
final Item item = wrapper.read(VersionedTypes.V1_21_2.item());
protocol.getItemRewriter().handleItemToClient(wrapper.user(), item);
final Item item = protocol.getItemRewriter().handleItemToClient(wrapper.user(), wrapper.read(VersionedTypes.V1_21_2.item()));
if (item.isEmpty()) {
protocol.getLogger().warning("Empty item in recipe");
yield new Item[0];
@@ -0,0 +1,45 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viabackwards.protocol.v1_21_2to1_21.storage;
import com.viaversion.viaversion.api.connection.StorableObject;
import com.viaversion.viaversion.api.minecraft.BlockPosition;
import java.util.HashSet;
import java.util.Set;
public final class SignStorage implements StorableObject {
private final Set<BlockPosition> signs = new HashSet<>();
public void addSign(final BlockPosition position) {
signs.add(position);
}
public boolean isSign(final BlockPosition position) {
return signs.contains(position);
}
public void removeSign(final BlockPosition position) {
signs.remove(position);
}
public void removeSigns(final int chunkX, final int chunkZ) {
signs.removeIf(pos -> pos.x() >> 4 == chunkX && pos.z() >> 4 == chunkZ);
}
}
@@ -22,46 +22,45 @@ import com.viaversion.viabackwards.protocol.v1_21_2to1_21.Protocol1_21_2To1_21;
import com.viaversion.viabackwards.protocol.v1_21_2to1_21.storage.PlayerStorage;
import com.viaversion.viaversion.api.connection.ProtocolInfo;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.entity.EntityTracker;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.packet.State;
import com.viaversion.viaversion.protocol.ProtocolRunnable;
import com.viaversion.viaversion.connection.StorableObjectTask;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ServerboundPackets1_21_2;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.ClientVehicleStorage;
import io.netty.channel.Channel;
import java.util.logging.Level;
public final class PlayerPacketsTickTask extends ProtocolRunnable {
public final class PlayerPacketsTickTask extends StorableObjectTask<PlayerStorage> {
public PlayerPacketsTickTask() {
super(Protocol1_21_2To1_21.class);
super(PlayerStorage.class);
}
@Override
public void run(final UserConnection connection) {
public void run(final UserConnection connection, final PlayerStorage storableObject) {
final ProtocolInfo protocolInfo = connection.getProtocolInfo();
if (protocolInfo.getClientState() != State.PLAY || protocolInfo.getServerState() != State.PLAY) {
return;
}
final Channel channel = connection.getChannel();
channel.eventLoop().submit(() -> {
if (!channel.isActive() || protocolInfo.getClientState() != State.PLAY || protocolInfo.getServerState() != State.PLAY) {
return;
final EntityTracker entityTracker = connection.getEntityTracker(Protocol1_21_2To1_21.class);
if (!entityTracker.hasClientEntityId()) {
return;
}
try {
if (!connection.has(ClientVehicleStorage.class)) {
storableObject.tick(connection);
}
try {
if (!connection.has(ClientVehicleStorage.class)) {
final PlayerStorage playerStorage = connection.get(PlayerStorage.class);
playerStorage.tick(connection);
}
} catch (final Throwable t) {
ViaBackwards.getPlatform().getLogger().log(Level.SEVERE, "Error while sending player input packet.", t);
}
try {
final PacketWrapper clientTickEndPacket = PacketWrapper.create(ServerboundPackets1_21_2.CLIENT_TICK_END, connection);
clientTickEndPacket.sendToServer(Protocol1_21_2To1_21.class);
} catch (final Throwable t) {
ViaBackwards.getPlatform().getLogger().log(Level.SEVERE, "Error while sending client tick end packet.", t);
}
});
} catch (final Throwable t) {
ViaBackwards.getPlatform().getLogger().log(Level.SEVERE, "Error while sending player input packet.", t);
}
try {
final PacketWrapper clientTickEndPacket = PacketWrapper.create(ServerboundPackets1_21_2.CLIENT_TICK_END, connection);
clientTickEndPacket.sendToServer(Protocol1_21_2To1_21.class);
} catch (final Throwable t) {
ViaBackwards.getPlatform().getLogger().log(Level.SEVERE, "Error while sending client tick end packet.", t);
}
}
}
@@ -88,11 +88,15 @@ public final class Protocol1_21_4To1_21_2 extends BackwardsProtocol<ClientboundP
translatableRewriter.registerComponentPacket(ClientboundPackets1_21_2.SET_SUBTITLE_TEXT);
translatableRewriter.registerBossEvent(ClientboundPackets1_21_2.BOSS_EVENT);
translatableRewriter.registerComponentPacket(ClientboundPackets1_21_2.DISCONNECT);
translatableRewriter.registerComponentPacket(ClientboundConfigurationPackets1_21.DISCONNECT);
translatableRewriter.registerTabList(ClientboundPackets1_21_2.TAB_LIST);
translatableRewriter.registerSetPlayerTeam1_13(ClientboundPackets1_21_2.SET_PLAYER_TEAM);
translatableRewriter.registerPlayerCombatKill1_20(ClientboundPackets1_21_2.PLAYER_COMBAT_KILL);
translatableRewriter.registerComponentPacket(ClientboundPackets1_21_2.SYSTEM_CHAT);
translatableRewriter.registerDisguisedChat(ClientboundPackets1_21_2.DISGUISED_CHAT);
translatableRewriter.registerPlayerChat(ClientboundPackets1_21_2.PLAYER_CHAT, ChatType.TYPE);
translatableRewriter.registerSetObjective(ClientboundPackets1_21_2.SET_OBJECTIVE);
translatableRewriter.registerSetScore1_20_3(ClientboundPackets1_21_2.SET_SCORE);
translatableRewriter.registerPing();
particleRewriter.registerExplode1_21_2(ClientboundPackets1_21_2.EXPLODE);
@@ -84,8 +84,8 @@ public final class BlockItemPacketRewriter1_21_4 extends BackwardsStructuredItem
@Override
public Item handleItemToClient(final UserConnection connection, final Item item) {
super.handleItemToClient(connection, item);
public Item handleItemToClient(final UserConnection connection, Item item) {
item = super.handleItemToClient(connection, item);
final StructuredDataContainer dataContainer = item.dataContainer();
final CustomModelData1_21_4 modelData = dataContainer.get(StructuredDataKey.CUSTOM_MODEL_DATA1_21_4);
@@ -103,8 +103,8 @@ public final class BlockItemPacketRewriter1_21_4 extends BackwardsStructuredItem
}
@Override
public Item handleItemToServer(final UserConnection connection, final Item item) {
super.handleItemToServer(connection, item);
public Item handleItemToServer(final UserConnection connection, Item item) {
item = super.handleItemToServer(connection, item);
final StructuredDataContainer dataContainer = item.dataContainer();
final CompoundTag customData = dataContainer.get(StructuredDataKey.CUSTOM_DATA);
@@ -19,6 +19,7 @@ package com.viaversion.viabackwards.protocol.v1_21_4to1_21_2.rewriter;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.viabackwards.api.rewriters.BackwardsRegistryRewriter;
import com.viaversion.viabackwards.api.rewriters.EntityRewriter;
import com.viaversion.viabackwards.protocol.v1_21_4to1_21_2.Protocol1_21_4To1_21_2;
import com.viaversion.viaversion.api.connection.UserConnection;
@@ -48,7 +49,7 @@ public final class EntityPacketRewriter1_21_4 extends EntityRewriter<Clientbound
registerSetEntityData(ClientboundPackets1_21_2.SET_ENTITY_DATA);
registerRemoveEntities(ClientboundPackets1_21_2.REMOVE_ENTITIES);
final RegistryDataRewriter registryDataRewriter = new RegistryDataRewriter(protocol) {
final RegistryDataRewriter registryDataRewriter = new BackwardsRegistryRewriter(protocol) {
@Override
public RegistryEntry[] handle(final UserConnection connection, final String key, final RegistryEntry[] entries) {
final String strippedKey = Key.stripMinecraftNamespace(key);
@@ -23,6 +23,7 @@ import com.viaversion.viabackwards.api.rewriters.SoundRewriter;
import com.viaversion.viabackwards.protocol.v1_21_5to1_21_4.rewriter.BlockItemPacketRewriter1_21_5;
import com.viaversion.viabackwards.protocol.v1_21_5to1_21_4.rewriter.ComponentRewriter1_21_5;
import com.viaversion.viabackwards.protocol.v1_21_5to1_21_4.rewriter.EntityPacketRewriter1_21_5;
import com.viaversion.viabackwards.protocol.v1_21_5to1_21_4.rewriter.RegistryDataRewriter1_21_5;
import com.viaversion.viabackwards.protocol.v1_21_5to1_21_4.storage.HashedItemConverterStorage;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.Particle;
@@ -52,6 +53,7 @@ import com.viaversion.viaversion.protocols.v1_21_4to1_21_5.packet.ServerboundPac
import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPacket1_21_2;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPackets1_21_2;
import com.viaversion.viaversion.rewriter.ParticleRewriter;
import com.viaversion.viaversion.rewriter.RegistryDataRewriter;
import com.viaversion.viaversion.rewriter.StatisticsRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
import com.viaversion.viaversion.util.Key;
@@ -75,6 +77,7 @@ public final class Protocol1_21_5To1_21_4 extends BackwardsProtocol<ClientboundP
};
private final ComponentRewriter1_21_5 translatableRewriter = new ComponentRewriter1_21_5(this);
private final TagRewriter<ClientboundPacket1_21_5> tagRewriter = new TagRewriter<>(this);
private final RegistryDataRewriter registryDataRewriter = new RegistryDataRewriter1_21_5(this);
public Protocol1_21_5To1_21_4() {
super(ClientboundPacket1_21_5.class, ClientboundPacket1_21_2.class, ServerboundPacket1_21_5.class, ServerboundPacket1_21_4.class);
@@ -84,6 +87,8 @@ public final class Protocol1_21_5To1_21_4 extends BackwardsProtocol<ClientboundP
protected void registerPackets() {
super.registerPackets();
registerClientbound(ClientboundConfigurationPackets1_21.REGISTRY_DATA, registryDataRewriter::handle);
tagRewriter.registerGeneric(ClientboundPackets1_21_5.UPDATE_TAGS);
tagRewriter.registerGeneric(ClientboundConfigurationPackets1_21.UPDATE_TAGS);
@@ -100,11 +105,14 @@ public final class Protocol1_21_5To1_21_4 extends BackwardsProtocol<ClientboundP
translatableRewriter.registerComponentPacket(ClientboundPackets1_21_5.SET_SUBTITLE_TEXT);
translatableRewriter.registerBossEvent(ClientboundPackets1_21_5.BOSS_EVENT);
translatableRewriter.registerComponentPacket(ClientboundPackets1_21_5.DISCONNECT);
translatableRewriter.registerComponentPacket(ClientboundConfigurationPackets1_21.DISCONNECT);
translatableRewriter.registerTabList(ClientboundPackets1_21_5.TAB_LIST);
translatableRewriter.registerPlayerCombatKill1_20(ClientboundPackets1_21_5.PLAYER_COMBAT_KILL);
translatableRewriter.registerComponentPacket(ClientboundPackets1_21_5.SYSTEM_CHAT);
translatableRewriter.registerDisguisedChat(ClientboundPackets1_21_5.DISGUISED_CHAT);
translatableRewriter.registerPlayerInfoUpdate1_21_4(ClientboundPackets1_21_5.PLAYER_INFO_UPDATE);
translatableRewriter.registerSetObjective(ClientboundPackets1_21_5.SET_OBJECTIVE);
translatableRewriter.registerSetScore1_20_3(ClientboundPackets1_21_5.SET_SCORE);
translatableRewriter.registerPing();
particleRewriter.registerLevelParticles1_21_4(ClientboundPackets1_21_5.LEVEL_PARTICLES);
@@ -204,6 +212,11 @@ public final class Protocol1_21_5To1_21_4 extends BackwardsProtocol<ClientboundP
return itemRewriter;
}
@Override
public RegistryDataRewriter getRegistryDataRewriter() {
return registryDataRewriter;
}
@Override
public ParticleRewriter<ClientboundPacket1_21_5> getParticleRewriter() {
return particleRewriter;
@@ -67,7 +67,9 @@ import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_20_2;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_21_5;
import com.viaversion.viaversion.api.type.types.version.VersionedTypes;
import com.viaversion.viaversion.data.item.ItemHasherBase;
import com.viaversion.viaversion.libs.fastutil.ints.IntArrayList;
import com.viaversion.viaversion.libs.fastutil.ints.IntLinkedOpenHashSet;
import com.viaversion.viaversion.libs.fastutil.ints.IntList;
import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.packet.ServerboundPacket1_21_4;
import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.packet.ServerboundPackets1_21_4;
import com.viaversion.viaversion.protocols.v1_21_4to1_21_5.packet.ClientboundPacket1_21_5;
@@ -181,20 +183,37 @@ public final class BlockItemPacketRewriter1_21_5 extends BackwardsStructuredItem
protocol.registerClientbound(ClientboundPackets1_21_5.SET_EQUIPMENT, wrapper -> {
final int entityId = wrapper.passthrough(Types.VAR_INT);
final TrackedEntity trackedEntity = protocol.getEntityRewriter().tracker(wrapper.user()).entity(entityId);
// Remove saddle equipment, keep the rest
final IntList keptSlots = new IntArrayList();
final List<Item> keptItems = new ArrayList<>();
byte value;
do {
value = wrapper.passthrough(Types.BYTE);
value = wrapper.read(Types.BYTE);
final int equipmentSlot = value & 0x7F;
final Item item = wrapper.read(itemType());
if (equipmentSlot == SADDLE_EQUIPMENT_SLOT) {
// Send saddle entity data for horses
if (trackedEntity != null && trackedEntity.entityType().isOrHasParent(EntityTypes1_21_5.ABSTRACT_HORSE)) {
final Item item = wrapper.read(itemType());
sendSaddledEntityData(wrapper.user(), trackedEntity, entityId, item.identifier() == 800);
}
wrapper.cancel();
return;
} else {
keptSlots.add(equipmentSlot);
keptItems.add(handleItemToClient(wrapper.user(), item));
}
passthroughClientboundItem(wrapper);
} while (value < 0);
if (keptSlots.isEmpty()) {
wrapper.cancel();
return;
}
for (int i = 0; i < keptSlots.size(); i++) {
final int slot = keptSlots.getInt(i);
final boolean more = i < keptSlots.size() - 1;
wrapper.write(Types.BYTE, (byte) (more ? (slot | -128) : slot));
wrapper.write(mappedItemType(), keptItems.get(i));
}
});
protocol.registerClientbound(ClientboundPackets1_21_5.UPDATE_ADVANCEMENTS, wrapper -> {
@@ -298,10 +317,19 @@ public final class BlockItemPacketRewriter1_21_5 extends BackwardsStructuredItem
private void handleBlockEntity(final UserConnection connection, final BlockEntity blockEntity) {
final CompoundTag tag = blockEntity.tag();
if (tag != null && (blockEntity.typeId() == SIGN_BOCK_ENTITY_ID || blockEntity.typeId() == HANGING_SIGN_BOCK_ENTITY_ID)) {
if (tag == null) {
return;
}
if (blockEntity.typeId() == SIGN_BOCK_ENTITY_ID || blockEntity.typeId() == HANGING_SIGN_BOCK_ENTITY_ID) {
updateSignMessages(connection, tag.getCompoundTag("front_text"));
updateSignMessages(connection, tag.getCompoundTag("back_text"));
}
final Tag customName = tag.get("CustomName");
if (customName != null) {
tag.putString("CustomName", protocol.getComponentRewriter().toUglyJson(connection, customName));
}
}
private void updateSignMessages(final UserConnection connection, final CompoundTag tag) {
@@ -25,6 +25,7 @@ import com.viaversion.nbt.tag.Tag;
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.api.minecraft.data.StructuredDataKey;
import com.viaversion.viaversion.protocols.v1_21_4to1_21_5.packet.ClientboundPacket1_21_5;
import com.viaversion.viaversion.protocols.v1_21_4to1_21_5.rewriter.BlockItemPacketRewriter1_21_5;
import com.viaversion.viaversion.util.Key;
@@ -141,6 +142,9 @@ public final class ComponentRewriter1_21_5 extends NBTComponentRewriter<Clientbo
}
}
}
if (hiddenComponents.containsAll(BlockItemPacketRewriter1_21_5.HIDE_ADDITIONAL_KEYS.stream().map(StructuredDataKey::identifier).toList())) {
componentsTag.put("hide_additional_tooltip", new CompoundTag());
}
final ListTag<CompoundTag> attributeModifiers = getNamespacedCompoundTagList(componentsTag, "attribute_modifiers");
if (attributeModifiers != null) {
@@ -168,12 +172,14 @@ public final class ComponentRewriter1_21_5 extends NBTComponentRewriter<Clientbo
handleAdventureModePredicate(componentsTag, "can_break", hiddenComponents);
handleEnchantments(componentsTag, "enchantments", hiddenComponents);
handleEnchantments(componentsTag, "stored_enchantments", hiddenComponents);
removeDataComponents(componentsTag, StructuredDataKey.INSTRUMENT1_21_5, StructuredDataKey.JUKEBOX_PLAYABLE1_21_5);
}
private void updateShowInTooltip(final CompoundTag tag, final String key, final Set<String> hiddenComponents) {
final CompoundTag data = getNamespacedCompoundTag(tag, key);
if (data != null) {
data.putBoolean("show_in_tooltip", hiddenComponents.contains(key));
data.putBoolean("show_in_tooltip", !hiddenComponents.contains(key));
}
}
@@ -186,7 +192,7 @@ public final class ComponentRewriter1_21_5 extends NBTComponentRewriter<Clientbo
removeDataComponents(componentsTag, key);
final CompoundTag predicate = new CompoundTag();
predicate.put("predicates", blockPredicates);
predicate.putBoolean("show_in_tooltip", hiddenComponents.contains(key));
predicate.putBoolean("show_in_tooltip", !hiddenComponents.contains(key));
componentsTag.put(key, predicate);
}
@@ -196,7 +202,7 @@ public final class ComponentRewriter1_21_5 extends NBTComponentRewriter<Clientbo
removeNamespaced(componentsTag, key);
final CompoundTag enchantments = new CompoundTag();
enchantments.put("levels", levels);
enchantments.putBoolean("show_in_tooltip", hiddenComponents.contains(key));
enchantments.putBoolean("show_in_tooltip", !hiddenComponents.contains(key));
componentsTag.put(key, enchantments);
}
}
@@ -250,7 +256,7 @@ public final class ComponentRewriter1_21_5 extends NBTComponentRewriter<Clientbo
}
}
private String toUglyJson(final UserConnection connection, final Tag value) {
String toUglyJson(final UserConnection connection, final Tag value) {
processTag(connection, value);
return SerializerVersion.V1_21_4.toString(SerializerVersion.V1_21_4.toComponent(value));
}
@@ -17,17 +17,11 @@
*/
package com.viaversion.viabackwards.protocol.v1_21_5to1_21_4.rewriter;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viabackwards.api.rewriters.EntityRewriter;
import com.viaversion.viabackwards.protocol.v1_21_5to1_21_4.Protocol1_21_5To1_21_4;
import com.viaversion.viabackwards.protocol.v1_21_5to1_21_4.storage.HashedItemConverterStorage;
import com.viaversion.viabackwards.protocol.v1_21_5to1_21_4.storage.HorseDataStorage;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.entity.TrackedEntity;
import com.viaversion.viaversion.api.minecraft.Holder;
import com.viaversion.viaversion.api.minecraft.RegistryEntry;
import com.viaversion.viaversion.api.minecraft.WolfVariant;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_21_5;
@@ -37,22 +31,13 @@ import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.version.VersionedTypes;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundConfigurationPackets1_21;
import com.viaversion.viaversion.protocols.v1_21_4to1_21_5.packet.ClientboundPacket1_21_5;
import com.viaversion.viaversion.protocols.v1_21_4to1_21_5.packet.ClientboundPackets1_21_5;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPackets1_21_2;
import com.viaversion.viaversion.rewriter.RegistryDataRewriter;
import com.viaversion.viaversion.util.Key;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID;
public final class EntityPacketRewriter1_21_5 extends EntityRewriter<ClientboundPacket1_21_5, Protocol1_21_5To1_21_4> {
private static final Set<String> NEW_REGISTRIES = Set.of("pig_variant", "cow_variant", "frog_variant", "cat_variant",
"chicken_variant", "test_environment", "test_instance", "wolf_sound_variant");
public EntityPacketRewriter1_21_5(final Protocol1_21_5To1_21_4 protocol) {
super(protocol, protocol.mappedTypes().entityDataTypes().optionalComponentType, protocol.mappedTypes().entityDataTypes().booleanType);
}
@@ -111,69 +96,6 @@ public final class EntityPacketRewriter1_21_5 extends EntityRewriter<Clientbound
}
});
final RegistryDataRewriter registryDataRewriter = new RegistryDataRewriter(protocol) {
@Override
public RegistryEntry[] handle(final UserConnection connection, final String key, final RegistryEntry[] entries) {
final boolean trimPatternRegistry = key.equals("trim_pattern");
if (trimPatternRegistry || key.equals("trim_material")) {
updateTrim(entries, trimPatternRegistry ? "template_item" : "ingredient");
return super.handle(connection, key, entries);
}
if (key.equals("enchantment")) {
updateEnchantment(entries);
return super.handle(connection, key, entries);
}
if (!key.equals("wolf_variant")) {
return super.handle(connection, key, entries);
}
for (final RegistryEntry entry : entries) {
if (entry.tag() == null) {
continue;
}
final CompoundTag variant = (CompoundTag) entry.tag();
final CompoundTag assets = (CompoundTag) variant.remove("assets");
variant.put("wild_texture", assets.get("wild"));
variant.put("tame_texture", assets.get("tame"));
variant.put("angry_texture", assets.get("angry"));
variant.put("biomes", new ListTag<>(StringTag.class));
}
return entries;
}
private void updateTrim(final RegistryEntry[] entries, final String itemKey) {
for (final RegistryEntry entry : entries) {
if (entry.tag() == null) {
continue;
}
final CompoundTag tag = (CompoundTag) entry.tag();
tag.putString(itemKey, "stone"); // dummy ingredient
}
}
};
protocol.registerClientbound(ClientboundConfigurationPackets1_21.REGISTRY_DATA, wrapper -> {
final String registryKey = Key.stripMinecraftNamespace(wrapper.passthrough(Types.STRING));
if (NEW_REGISTRIES.contains(registryKey)) {
wrapper.cancel();
return;
}
final RegistryEntry[] entries = wrapper.read(Types.REGISTRY_ENTRY_ARRAY);
if (registryKey.equals("enchantment")) {
final List<String> identifiers = new ArrayList<>(entries.length);
for (final RegistryEntry entry : entries) {
identifiers.add(entry.key());
}
wrapper.user().get(HashedItemConverterStorage.class).setEnchantments(identifiers);
}
wrapper.write(Types.REGISTRY_ENTRY_ARRAY, registryDataRewriter.handle(wrapper.user(), registryKey, entries));
});
protocol.registerClientbound(ClientboundPackets1_21_5.LOGIN, wrapper -> {
final int entityId = wrapper.passthrough(Types.INT); // Entity id
wrapper.passthrough(Types.BOOLEAN); // Hardcore
@@ -200,7 +122,7 @@ public final class EntityPacketRewriter1_21_5 extends EntityRewriter<Clientbound
wrapper.passthrough(Types.STRING); // Team Name
final byte action = wrapper.passthrough(Types.BYTE); // Mode
if (action == 0 || action == 2) {
wrapper.passthrough(Types.TAG); // Display Name
protocol.getComponentRewriter().passthroughAndProcess(wrapper); // Display name
wrapper.passthrough(Types.BYTE); // Flags
final int nametagVisibility = wrapper.read(Types.VAR_INT);
@@ -209,26 +131,12 @@ public final class EntityPacketRewriter1_21_5 extends EntityRewriter<Clientbound
wrapper.write(Types.STRING, collision(collisionRule));
wrapper.passthrough(Types.VAR_INT); // Color
wrapper.passthrough(Types.TAG); // Prefix
wrapper.passthrough(Types.TAG); // Suffix
protocol.getComponentRewriter().passthroughAndProcess(wrapper); // Prefix
protocol.getComponentRewriter().passthroughAndProcess(wrapper); // Suffix
}
});
}
private void updateEnchantment(final RegistryEntry[] entries) {
for (final RegistryEntry entry : entries) {
if (entry.tag() == null) {
continue;
}
final CompoundTag enchantment = (CompoundTag) entry.tag();
final ListTag<StringTag> slots = enchantment.getListTag("slots", StringTag.class);
if (slots != null) {
slots.getValue().removeIf(tag -> tag.getValue().equals("saddle")); // Remove saddle slot
}
}
}
private String visibility(final int id) {
return switch (id) {
case 0 -> "always";
@@ -0,0 +1,97 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viabackwards.protocol.v1_21_5to1_21_4.rewriter;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.rewriters.BackwardsRegistryRewriter;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.RegistryEntry;
import java.util.List;
public final class RegistryDataRewriter1_21_5 extends BackwardsRegistryRewriter {
public RegistryDataRewriter1_21_5(final BackwardsProtocol<?, ?, ?, ?> protocol) {
super(protocol);
final List<String> newRegistries = List.of("pig_variant", "cow_variant", "frog_variant", "cat_variant",
"chicken_variant", "test_environment", "test_instance", "wolf_sound_variant");
for (final String registry : newRegistries) {
remove(registry);
}
}
@Override
public RegistryEntry[] handle(final UserConnection connection, final String key, final RegistryEntry[] entries) {
final boolean trimPatternRegistry = key.equals("trim_pattern");
if (trimPatternRegistry || key.equals("trim_material")) {
updateTrim(entries, trimPatternRegistry ? "template_item" : "ingredient");
return super.handle(connection, key, entries);
}
if (key.equals("enchantment")) {
updateEnchantment(entries);
return super.handle(connection, key, entries);
}
if (!key.equals("wolf_variant")) {
return super.handle(connection, key, entries);
}
for (final RegistryEntry entry : entries) {
if (entry.tag() == null) {
continue;
}
final CompoundTag variant = (CompoundTag) entry.tag();
final CompoundTag assets = (CompoundTag) variant.remove("assets");
variant.put("wild_texture", assets.get("wild"));
variant.put("tame_texture", assets.get("tame"));
variant.put("angry_texture", assets.get("angry"));
variant.put("biomes", new ListTag<>(StringTag.class));
}
return entries;
}
private void updateTrim(final RegistryEntry[] entries, final String itemKey) {
for (final RegistryEntry entry : entries) {
if (entry.tag() == null) {
continue;
}
final CompoundTag tag = (CompoundTag) entry.tag();
tag.putString(itemKey, "stone"); // dummy ingredient
}
}
private void updateEnchantment(final RegistryEntry[] entries) {
for (final RegistryEntry entry : entries) {
if (entry.tag() == null) {
continue;
}
final CompoundTag enchantment = (CompoundTag) entry.tag();
final ListTag<StringTag> slots = enchantment.getListTag("slots", StringTag.class);
if (slots != null) {
slots.getValue().removeIf(tag -> tag.getValue().equals("saddle")); // Remove saddle slot
}
}
}
}
@@ -25,26 +25,17 @@ import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.codec.CodecRegistryContext;
import com.viaversion.viaversion.codec.hash.HashFunction;
import com.viaversion.viaversion.codec.hash.HashOps;
import com.viaversion.viaversion.util.SerializerVersion;
import java.util.ArrayList;
import java.util.List;
public class HashedItemConverterStorage implements StorableObject {
private final List<String> enchantments = new ArrayList<>();
private final Hasher hasher;
public HashedItemConverterStorage(final Protocol<?, ?, ?, ?> protocol) {
final RegistryAccess registryAccess = RegistryAccess.of(this.enchantments, protocol.getMappingData());
final CodecContext context = new CodecRegistryContext(protocol, SerializerVersion.V1_21_5, SerializerVersion.V1_21_5, registryAccess, false);
final RegistryAccess registryAccess = RegistryAccess.of(protocol);
final CodecContext context = new CodecRegistryContext(protocol, registryAccess, false);
this.hasher = new HashOps(context, HashFunction.CRC32C);
}
public void setEnchantments(final List<String> enchantments) {
this.enchantments.clear();
this.enchantments.addAll(enchantments);
}
public Hasher hasher() {
return hasher; // reusable
}
@@ -19,6 +19,7 @@ package com.viaversion.viabackwards.protocol.v1_21_6to1_21_5;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viabackwards.ViaBackwards;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.data.BackwardsMappingData;
import com.viaversion.viabackwards.api.rewriters.SoundRewriter;
@@ -29,6 +30,7 @@ import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.provider.DialogViewP
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.rewriter.BlockItemPacketRewriter1_21_6;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.rewriter.ComponentRewriter1_21_6;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.rewriter.EntityPacketRewriter1_21_6;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.rewriter.RegistryDataRewriter1_21_6;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.storage.ChestDialogStorage;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.storage.ClickEvents;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.storage.RegistryAndTags;
@@ -61,10 +63,10 @@ import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ServerboundPac
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ServerboundPackets1_21_6;
import com.viaversion.viaversion.rewriter.AttributeRewriter;
import com.viaversion.viaversion.rewriter.ParticleRewriter;
import com.viaversion.viaversion.rewriter.RegistryDataRewriter;
import com.viaversion.viaversion.rewriter.StatisticsRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
import com.viaversion.viaversion.util.Key;
import com.viaversion.viaversion.util.SerializerVersion;
import static com.viaversion.viaversion.util.ProtocolUtil.packetTypeMap;
@@ -76,6 +78,7 @@ public final class Protocol1_21_6To1_21_5 extends BackwardsProtocol<ClientboundP
private final ParticleRewriter<ClientboundPacket1_21_6> particleRewriter = new ParticleRewriter<>(this);
private final NBTComponentRewriter<ClientboundPacket1_21_6> translatableRewriter = new ComponentRewriter1_21_6(this);
private final TagRewriter<ClientboundPacket1_21_6> tagRewriter = new TagRewriter<>(this);
private final RegistryDataRewriter registryDataRewriter = new RegistryDataRewriter1_21_6(this);
public Protocol1_21_6To1_21_5() {
super(ClientboundPacket1_21_6.class, ClientboundPacket1_21_5.class, ServerboundPacket1_21_6.class, ServerboundPacket1_21_5.class);
@@ -85,6 +88,8 @@ public final class Protocol1_21_6To1_21_5 extends BackwardsProtocol<ClientboundP
protected void registerPackets() {
super.registerPackets();
registerClientbound(ClientboundConfigurationPackets1_21_6.REGISTRY_DATA, registryDataRewriter::handle);
registerClientbound(ClientboundPackets1_21_6.UPDATE_TAGS, this::updateTags);
registerClientbound(ClientboundConfigurationPackets1_21_6.UPDATE_TAGS, this::updateTags);
@@ -126,12 +131,16 @@ public final class Protocol1_21_6To1_21_5 extends BackwardsProtocol<ClientboundP
translatableRewriter.registerComponentPacket(ClientboundPackets1_21_6.SET_SUBTITLE_TEXT);
translatableRewriter.registerBossEvent(ClientboundPackets1_21_6.BOSS_EVENT);
translatableRewriter.registerComponentPacket(ClientboundPackets1_21_6.DISCONNECT);
translatableRewriter.registerComponentPacket(ClientboundConfigurationPackets1_21_6.DISCONNECT);
translatableRewriter.registerTabList(ClientboundPackets1_21_6.TAB_LIST);
translatableRewriter.registerSetPlayerTeam1_21_5(ClientboundPackets1_21_6.SET_PLAYER_TEAM);
translatableRewriter.registerPlayerCombatKill1_20(ClientboundPackets1_21_6.PLAYER_COMBAT_KILL);
translatableRewriter.registerPlayerInfoUpdate1_21_4(ClientboundPackets1_21_6.PLAYER_INFO_UPDATE);
translatableRewriter.registerComponentPacket(ClientboundPackets1_21_6.SYSTEM_CHAT);
translatableRewriter.registerDisguisedChat(ClientboundPackets1_21_6.DISGUISED_CHAT);
translatableRewriter.registerPlayerChat1_21_5(ClientboundPackets1_21_6.PLAYER_CHAT);
translatableRewriter.registerSetObjective(ClientboundPackets1_21_6.SET_OBJECTIVE);
translatableRewriter.registerSetScore1_20_3(ClientboundPackets1_21_6.SET_SCORE);
translatableRewriter.registerPing();
particleRewriter.registerLevelParticles1_21_4(ClientboundPackets1_21_6.LEVEL_PARTICLES);
@@ -145,10 +154,15 @@ public final class Protocol1_21_6To1_21_5 extends BackwardsProtocol<ClientboundP
final short difficulty = wrapper.read(Types.UNSIGNED_BYTE);
wrapper.write(Types.VAR_INT, (int) difficulty);
});
registerServerbound(ServerboundPackets1_21_5.CHAT_COMMAND, this::handleClickEvents);
registerServerbound(ServerboundPackets1_21_5.CHAT_COMMAND_SIGNED, this::handleClickEvents);
// Are you sure you want to see this? This is your last chance to turn back.
registerClientbound(ClientboundPackets1_21_6.SHOW_DIALOG, null, wrapper -> {
wrapper.cancel();
if (!ViaBackwards.getConfig().dialogsViaChests()) {
return;
}
final RegistryAndTags registryAndTags = wrapper.user().get(RegistryAndTags.class);
final ServerLinks serverLinks = wrapper.user().get(ServerLinks.class);
@@ -165,6 +179,9 @@ public final class Protocol1_21_6To1_21_5 extends BackwardsProtocol<ClientboundP
});
registerClientbound(ClientboundConfigurationPackets1_21_6.SHOW_DIALOG, null, wrapper -> {
wrapper.cancel();
if (!ViaBackwards.getConfig().dialogsViaChests()) {
return;
}
final RegistryAndTags registryAndTags = wrapper.user().get(RegistryAndTags.class);
final ServerLinks serverLinks = wrapper.user().get(ServerLinks.class);
@@ -179,15 +196,6 @@ public final class Protocol1_21_6To1_21_5 extends BackwardsProtocol<ClientboundP
registerClientbound(ClientboundPackets1_21_6.SERVER_LINKS, this::storeServerLinks);
registerClientbound(ClientboundConfigurationPackets1_21_6.SERVER_LINKS, this::storeServerLinks);
registerServerbound(ServerboundPackets1_21_5.CHAT_COMMAND, wrapper -> {
final String command = wrapper.passthrough(Types.STRING);
final ClickEvents clickEvents = wrapper.user().get(ClickEvents.class);
if (clickEvents.handleChatCommand(wrapper.user(), command)) {
wrapper.cancel();
}
});
// The ones below are specific to the chest dialog view provider
registerServerbound(ServerboundPackets1_21_5.CONTAINER_CLOSE, wrapper -> {
final ChestDialogStorage storage = wrapper.user().get(ChestDialogStorage.class);
@@ -292,6 +300,10 @@ public final class Protocol1_21_6To1_21_5 extends BackwardsProtocol<ClientboundP
private void clearDialog(final PacketWrapper wrapper) {
wrapper.cancel();
if (!ViaBackwards.getConfig().dialogsViaChests()) {
return;
}
final DialogViewProvider provider = Via.getManager().getProviders().get(DialogViewProvider.class);
provider.closeDialog(wrapper.user());
}
@@ -305,7 +317,7 @@ public final class Protocol1_21_6To1_21_5 extends BackwardsProtocol<ClientboundP
final String url = wrapper.passthrough(Types.STRING);
serverLinks.storeLink(id, url);
} else {
final Tag tag = wrapper.passthrough(Types.COMPOUND_TAG);
final Tag tag = wrapper.passthrough(Types.TAG);
final String url = wrapper.passthrough(Types.STRING);
serverLinks.storeLink(tag, url);
}
@@ -313,10 +325,19 @@ public final class Protocol1_21_6To1_21_5 extends BackwardsProtocol<ClientboundP
wrapper.user().put(serverLinks);
}
private void handleClickEvents(final PacketWrapper wrapper) {
final String command = wrapper.passthrough(Types.STRING);
final ClickEvents clickEvents = wrapper.user().get(ClickEvents.class);
if (clickEvents.handleChatCommand(wrapper.user(), command)) {
wrapper.cancel();
}
}
@Override
public void init(final UserConnection user) {
addEntityTracker(user, new EntityTrackerBase(user, EntityTypes1_21_6.PLAYER));
addItemHasher(user, new ItemHasherBase(this, user, SerializerVersion.V1_21_5, SerializerVersion.V1_21_5));
addItemHasher(user, new ItemHasherBase(this, user));
user.put(new RegistryAndTags());
user.put(new ClickEvents());
}
@@ -341,6 +362,11 @@ public final class Protocol1_21_6To1_21_5 extends BackwardsProtocol<ClientboundP
return itemRewriter;
}
@Override
public RegistryDataRewriter getRegistryDataRewriter() {
return registryDataRewriter;
}
@Override
public ParticleRewriter<ClientboundPacket1_21_6> getParticleRewriter() {
return particleRewriter;
@@ -74,7 +74,7 @@ public class Button implements Widget {
for (final String event : CLICK_EVENTS) {
if (Key.stripMinecraftNamespace(type).equals(event)) {
clickEvent = actionTag;
clickEvent = actionTag.copy();
clickEvent.put("action", clickEvent.remove("type"));
return;
}
@@ -132,7 +132,7 @@ public final class Dialog implements Widget {
private void fillNoticeDialog(final CompoundTag tag) {
final CompoundTag actionTag = tag.getCompoundTag("action");
actionButton = actionTag == null ? Button.DEFAULT : actionButton;
actionButton = actionTag == null ? Button.DEFAULT : new Button(this, actionTag);
}
private void fillServerLinksDialog(final ServerLinks serverLinks, final CompoundTag tag) {
@@ -150,7 +150,7 @@ public final class Dialog implements Widget {
}
private void fillDialogList(final RegistryAndTags registryAndTags, final ServerLinks serverLinks, final CompoundTag tag) {
// Hold them as either a list of inlined, a singleton inlined, a registry entry or a tag.
// Hold them as either a list of inlined / singleton inlined, a list of registry entries / singleton entry or a tag.
ListTag<CompoundTag> dialogsTag = tag.getListTag("dialogs", CompoundTag.class);
if (dialogsTag == null) {
CompoundTag dialogTag = tag.getCompoundTag("dialogs");
@@ -159,16 +159,23 @@ public final class Dialog implements Widget {
dialogsTag.add(dialogTag);
}
ListTag<StringTag> registryDialogsTag = tag.getListTag("dialogs", StringTag.class);
StringTag registryDialogTag = tag.getStringTag("dialogs");
if (registryDialogTag != null) {
registryDialogsTag = new ListTag<>(StringTag.class);
registryDialogsTag.add(registryDialogTag);
}
if (registryDialogsTag != null) {
dialogsTag = new ListTag<>(CompoundTag.class);
final String key = registryDialogTag.getValue();
if (key.startsWith("#")) {
for (final CompoundTag entry : registryAndTags.fromRegistryKey(key.substring(1))) {
dialogsTag.add(entry);
for (final StringTag nameTag : registryDialogsTag) {
final String key = nameTag.getValue();
if (key.startsWith("#")) {
for (final CompoundTag entry : registryAndTags.fromRegistryKey(key.substring(1))) {
dialogsTag.add(entry);
}
} else {
dialogsTag.add(registryAndTags.fromRegistry(key));
}
} else {
dialogsTag.add(registryAndTags.fromRegistry(key));
}
}
}
@@ -21,7 +21,6 @@ import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.FloatTag;
import com.viaversion.nbt.tag.Tag;
import static com.viaversion.viabackwards.utils.ChatUtil.text;
import static com.viaversion.viabackwards.utils.ChatUtil.translate;
public final class NumberRangeInput implements Input {
@@ -109,6 +108,6 @@ public final class NumberRangeInput implements Input {
}
public Tag displayName() {
return translate(labelFormat, label, text(valueAsString()));
return translate(labelFormat, label, translate(valueAsString()));
}
}
@@ -19,6 +19,8 @@ package com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.provider;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viabackwards.ViaBackwards;
import com.viaversion.viabackwards.api.DialogStyleConfig;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.Protocol1_21_6To1_21_5;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.data.Button;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.data.Dialog;
@@ -52,7 +54,6 @@ import java.util.List;
import org.checkerframework.checker.nullness.qual.Nullable;
import static com.viaversion.viabackwards.utils.ChatUtil.fixStyle;
import static com.viaversion.viabackwards.utils.ChatUtil.text;
import static com.viaversion.viabackwards.utils.ChatUtil.translate;
/**
@@ -84,11 +85,18 @@ public class ChestDialogViewProvider implements DialogViewProvider {
texts.add(textWidget.label());
dialog.widgets().remove(textWidget);
} else if (!texts.isEmpty()) {
// Flush collected texts before adding the non-text widget
dialog.widgets().add(dialog.widgets().indexOf(widget), new MultiTextWidget(texts.toArray(Tag[]::new)));
texts.clear();
}
}
// Flush remaining texts if any
if (!texts.isEmpty()) {
dialog.widgets().add(new MultiTextWidget(texts.toArray(Tag[]::new)));
texts.clear();
}
final ChestDialogStorage previousStorage = connection.get(ChestDialogStorage.class);
final ChestDialogStorage storage = new ChestDialogStorage(this, dialog);
if (previousStorage != null) {
@@ -105,7 +113,7 @@ public class ChestDialogViewProvider implements DialogViewProvider {
final PacketWrapper openScreen = PacketWrapper.create(ClientboundPackets1_21_5.OPEN_SCREEN, connection);
openScreen.write(Types.VAR_INT, storage.containerId());
openScreen.write(Types.VAR_INT, 2); // Container type id
openScreen.write(Types.TAG, storage.dialog().title());
openScreen.write(Types.TAG, handleTag(connection, storage.dialog().title()));
openScreen.send(Protocol1_21_6To1_21_5.class);
updateDialog(connection, storage.dialog());
}
@@ -119,6 +127,9 @@ public class ChestDialogViewProvider implements DialogViewProvider {
}
final ChestDialogStorage storage = connection.get(ChestDialogStorage.class);
if (storage == null) {
return;
}
final PacketWrapper containerClose = PacketWrapper.create(ClientboundPackets1_21_5.CONTAINER_CLOSE, connection);
containerClose.write(Types.VAR_INT, storage.containerId());
@@ -206,8 +217,9 @@ public class ChestDialogViewProvider implements DialogViewProvider {
}
}
// Resync inventory view if the actions above didn't close the dialog.
if (connection.has(ChestDialogStorage.class) && storage.phase() == ChestDialogStorage.Phase.DIALOG_VIEW) {
// Resync inventory view if the actions above didn't close the dialog nor opened another one.
final ChestDialogStorage currentStorage = connection.get(ChestDialogStorage.class);
if (currentStorage == storage && connection.has(ChestDialogStorage.class) && storage.phase() == ChestDialogStorage.Phase.DIALOG_VIEW) {
updateDialog(connection, storage.dialog());
}
return true;
@@ -225,12 +237,14 @@ public class ChestDialogViewProvider implements DialogViewProvider {
}
protected Item createPageNavigationItem() {
final DialogStyleConfig config = ViaBackwards.getConfig().dialogStyleConfig();
return createItem(
"minecraft:arrow",
text("§9§lPage navigation"),
translate(config.pageNavigationTitle()),
"§9Left click: §6Go to next page",
"§9Right click: §6Go to previous page"
config.pageNavigationNext(),
config.pageNavigationPrevious()
);
}
@@ -251,7 +265,7 @@ public class ChestDialogViewProvider implements DialogViewProvider {
final String identifier = itemWidget.item().getString("id");
final int count = itemWidget.item().getInt("count", 1);
final Tag label = text(Key.stripMinecraftNamespace(identifier));
final Tag label = translate(Key.stripMinecraftNamespace(identifier));
final Item item = createItem(identifier, label);
item.setAmount(count);
if (itemWidget.description() != null) {
@@ -268,20 +282,24 @@ public class ChestDialogViewProvider implements DialogViewProvider {
}
protected Item getMultiTextWidget(final UserConnection connection, final MultiTextWidget multiTextWidget) {
final Tag name = handleTag(connection, multiTextWidget.labels()[0]);
final int length = multiTextWidget.labels().length;
if (length == 1) {
return createItem("minecraft:paper", name);
final List<Tag> lines = new ArrayList<>();
for (final Tag label : multiTextWidget.labels()) {
final Tag[] split = ChatUtil.split(fixStyle(label), "\n");
for (final Tag line : split) {
lines.add(handleTag(connection, line));
}
}
final Tag[] lore = new Tag[length - 1];
for (int i = 1; i < length; i++) {
lore[i - 1] = handleTag(connection, fixStyle(multiTextWidget.labels()[i]));
final Tag[] lore = new Tag[lines.size() - 1];
for (int i = 1; i < lines.size(); i++) {
lore[i - 1] = lines.get(i);
}
return createItem("minecraft:paper", name, lore);
return createItem("minecraft:paper", lines.get(0), lore);
}
protected Item getBooleanInput(final UserConnection connection, final BooleanInput booleanInput) {
final DialogStyleConfig config = ViaBackwards.getConfig().dialogStyleConfig();
final String item = booleanInput.value() ? "minecraft:lime_dye" : "minecraft:gray_dye";
final Tag[] label = ChatUtil.split(booleanInput.label(), "\n");
@@ -290,14 +308,14 @@ public class ChestDialogViewProvider implements DialogViewProvider {
return createItem(
item,
handleTag(connection, booleanInput.label()),
text("§9Left click: §6Toggle value")
translate(config.toggleValue())
);
} else {
final Tag[] lore = new Tag[label.length];
for (int i = 1; i < label.length; i++) {
lore[i - 1] = handleTag(connection, fixStyle(label[i]));
}
lore[lore.length - 1] = text("§9Left click: §6Toggle value");
lore[lore.length - 1] = translate(config.toggleValue());
return createItem(
item,
handleTag(connection, label[0]),
@@ -311,14 +329,16 @@ public class ChestDialogViewProvider implements DialogViewProvider {
}
protected Item getNumberRangeInput(final UserConnection connection, final NumberRangeInput numberRangeInput) {
final DialogStyleConfig config = ViaBackwards.getConfig().dialogStyleConfig();
final Tag label = handleTag(connection, numberRangeInput.displayName());
return createItem(
"minecraft:clock",
label,
"§9Left click: §6Increase value by " + numberRangeInput.step(),
"§9Right click: §6Decrease value by " + numberRangeInput.step(),
"§7(Value between §a" + numberRangeInput.start() + " §7and §a" + numberRangeInput.end() + "§7)"
String.format(config.increaseValue(), numberRangeInput.step()),
String.format(config.decreaseValue(), numberRangeInput.step()),
String.format(config.valueRange(), numberRangeInput.start(), numberRangeInput.end())
);
}
@@ -333,21 +353,25 @@ public class ChestDialogViewProvider implements DialogViewProvider {
}
protected Item getTextInput(final UserConnection connection, final TextInput textInput) {
final Tag currentValue = text("§7Current value: §a" + textInput.value());
final DialogStyleConfig config = ViaBackwards.getConfig().dialogStyleConfig();
final Tag currentValue = translate(String.format(config.currentValue(), textInput.value()));
if (textInput.label() == null) {
return createItem("minecraft:writable_book", currentValue);
} else {
final Tag label = handleTag(connection, textInput.label());
return createItem("minecraft:writable_book", label, currentValue, text("§9Left click: §6Edit text"));
return createItem("minecraft:writable_book", label, currentValue, translate(config.editValue()));
}
}
protected void clickTextInput(final UserConnection connection, final TextInput textInput) {
final ChestDialogStorage storage = connection.get(ChestDialogStorage.class);
openAnvilView(connection, storage, text("§7Edit text"), textInput.value(), textInput);
openAnvilView(connection, storage, translate("§7Edit text"), textInput.value(), textInput);
}
protected Item getSingleOptionInput(final UserConnection connection, final SingleOptionInput singleOptionInput) {
final DialogStyleConfig config = ViaBackwards.getConfig().dialogStyleConfig();
final Tag displayName = singleOptionInput.options()[singleOptionInput.value()].computeDisplay();
final Tag label;
if (singleOptionInput.label() != null) {
@@ -358,8 +382,8 @@ public class ChestDialogViewProvider implements DialogViewProvider {
return createItem(
"minecraft:bookshelf",
handleTag(connection, label),
"§9Left click: §6Go to next option",
"§9Right click: §6Go to previous option"
config.nextOption(),
config.previousOption()
);
}
@@ -388,7 +412,7 @@ public class ChestDialogViewProvider implements DialogViewProvider {
case "open_url" -> {
// We can't open a URL for the client, so roughly emulate by opening an Anvil containing the URL.
final String url = clickEvent.getString("url");
openAnvilView(connection, storage, text("Open URL"), url, null);
openAnvilView(connection, storage, translate("Open URL"), url, null);
}
case "run_command" -> {
// The vanilla client validates for signed argument types and has more requirements for this click event,
@@ -404,7 +428,7 @@ public class ChestDialogViewProvider implements DialogViewProvider {
case "copy_to_clipboard" -> {
// Same as above, we can't access the clipboard
final String value = clickEvent.getString("value");
openAnvilView(connection, storage, text("Copy to clipboard"), value, null);
openAnvilView(connection, storage, translate("Copy to clipboard"), value, null);
}
}
@@ -412,14 +436,16 @@ public class ChestDialogViewProvider implements DialogViewProvider {
}
protected Item createTextInputItem(final String value) {
return createItem("minecraft:paper", text(value), "§9Left click/close: §6Set text");
final DialogStyleConfig config = ViaBackwards.getConfig().dialogStyleConfig();
return createItem("minecraft:paper", translate(value), config.setText());
}
protected Item createTextCopyItem(final String value) {
return createItem("minecraft:paper", text(value), "§9Left click: §6Close");
final DialogStyleConfig config = ViaBackwards.getConfig().dialogStyleConfig();
return createItem("minecraft:paper", translate(value), config.close());
}
private void openAnvilView(
protected void openAnvilView(
final UserConnection connection,
final ChestDialogStorage storage,
final Tag title,
@@ -545,7 +571,7 @@ public class ChestDialogViewProvider implements DialogViewProvider {
* @param tag the text component as a tag, or null if no tag is present
* @return the rewritten tag, or null if the input tag was null
*/
private @Nullable Tag handleTag(final UserConnection connection, final @Nullable Tag tag) {
protected @Nullable Tag handleTag(final UserConnection connection, final @Nullable Tag tag) {
if (tag == null) {
return null;
}
@@ -589,7 +615,7 @@ public class ChestDialogViewProvider implements DialogViewProvider {
if (description.length > 0) {
final List<Tag> lore = new ArrayList<>();
for (final String s : description) {
lore.add(text(s));
lore.add(translate(s));
}
data.set(StructuredDataKey.LORE, lore.toArray(new Tag[0]));
}
@@ -20,7 +20,6 @@ package com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.rewriter;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.rewriters.text.NBTComponentRewriter;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.storage.ChestDialogStorage;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.storage.ClickEvents;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundPacket1_21_6;
@@ -42,15 +41,6 @@ public final class ComponentRewriter1_21_6 extends NBTComponentRewriter<Clientbo
final String action = clickEvent.getString("action");
final ChestDialogStorage chestDialogStorage = connection.get(ChestDialogStorage.class);
if (chestDialogStorage != null) {
// Short way out - remove when in dialog, buttons are handled separately
if ("show_dialog".equals(action) || "custom".equals(action)) {
tag.remove("click_event");
return;
}
}
// Make them run a command generated by us executing the actual logic
if ("show_dialog".equals(action)) {
final ClickEvents clickEvents = connection.get(ClickEvents.class);
@@ -17,29 +17,18 @@
*/
package com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.rewriter;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viabackwards.api.rewriters.BackwardsRegistryRewriter;
import com.viaversion.viabackwards.api.rewriters.EntityRewriter;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.Protocol1_21_6To1_21_5;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.storage.RegistryAndTags;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.RegistryEntry;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_21_6;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_21_5;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.version.VersionedTypes;
import com.viaversion.viaversion.libs.fastutil.objects.Object2ObjectArrayMap;
import com.viaversion.viaversion.libs.fastutil.objects.Object2ObjectMap;
import com.viaversion.viaversion.protocols.v1_21_4to1_21_5.packet.ClientboundPackets1_21_5;
import com.viaversion.viaversion.protocols.v1_21_4to1_21_5.packet.ServerboundPackets1_21_5;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundConfigurationPackets1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundPacket1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundPackets1_21_6;
import com.viaversion.viaversion.rewriter.RegistryDataRewriter;
import com.viaversion.viaversion.util.Key;
import com.viaversion.viaversion.util.KeyMappings;
public final class EntityPacketRewriter1_21_6 extends EntityRewriter<ClientboundPacket1_21_6, Protocol1_21_6To1_21_5> {
@@ -86,31 +75,6 @@ public final class EntityPacketRewriter1_21_6 extends EntityRewriter<Clientbound
}
});
final RegistryDataRewriter registryDataRewriter = new BackwardsRegistryRewriter(protocol) {
@Override
public RegistryEntry[] handle(final UserConnection connection, final String key, final RegistryEntry[] entries) {
if (Key.stripMinecraftNamespace(key).equals("dialog")) {
final String[] keys = new String[entries.length];
for (int i = 0; i < entries.length; i++) {
keys[i] = Key.stripMinecraftNamespace(entries[i].key());
}
final Object2ObjectMap<String, CompoundTag> dialogs = new Object2ObjectArrayMap<>();
for (final RegistryEntry entry : entries) {
if (entry.tag() instanceof final CompoundTag tag) {
dialogs.put(Key.stripMinecraftNamespace(entry.key()), tag);
}
}
final RegistryAndTags registryAndTags = connection.get(RegistryAndTags.class);
registryAndTags.storeRegistry(new KeyMappings(keys), dialogs);
}
return super.handle(connection, key, entries);
}
};
registryDataRewriter.remove("dialog"); // Tracked and now removed
protocol.registerClientbound(ClientboundConfigurationPackets1_21_6.REGISTRY_DATA, registryDataRewriter::handle);
protocol.registerServerbound(ServerboundPackets1_21_5.PLAYER_COMMAND, wrapper -> {
wrapper.passthrough(Types.VAR_INT); // Entity ID
@@ -0,0 +1,59 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.rewriter;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.rewriters.BackwardsRegistryRewriter;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.storage.RegistryAndTags;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.RegistryEntry;
import com.viaversion.viaversion.libs.fastutil.objects.Object2ObjectArrayMap;
import com.viaversion.viaversion.libs.fastutil.objects.Object2ObjectMap;
import com.viaversion.viaversion.util.Key;
import com.viaversion.viaversion.util.KeyMappings;
public final class RegistryDataRewriter1_21_6 extends BackwardsRegistryRewriter {
public RegistryDataRewriter1_21_6(final BackwardsProtocol<?, ?, ?, ?> protocol) {
super(protocol);
remove("dialog"); // Tracked and now removed
}
@Override
public RegistryEntry[] handle(final UserConnection connection, final String key, final RegistryEntry[] entries) {
if (Key.stripMinecraftNamespace(key).equals("dialog")) {
final String[] keys = new String[entries.length];
for (int i = 0; i < entries.length; i++) {
keys[i] = Key.stripMinecraftNamespace(entries[i].key());
}
final Object2ObjectMap<String, CompoundTag> dialogs = new Object2ObjectArrayMap<>();
for (final RegistryEntry entry : entries) {
if (entry.tag() instanceof final CompoundTag tag) {
dialogs.put(Key.stripMinecraftNamespace(entry.key()), tag);
}
}
final RegistryAndTags registryAndTags = connection.get(RegistryAndTags.class);
registryAndTags.storeRegistry(new KeyMappings(keys), dialogs);
}
return super.handle(connection, key, entries);
}
}
@@ -31,7 +31,6 @@ import com.viaversion.viaversion.protocols.v1_21_4to1_21_5.packet.ClientboundPac
import java.util.concurrent.atomic.AtomicInteger;
import org.checkerframework.checker.nullness.qual.Nullable;
import static com.viaversion.viabackwards.utils.ChatUtil.text;
import static com.viaversion.viabackwards.utils.ChatUtil.translate;
/**
@@ -44,7 +43,7 @@ public final class ChestDialogStorage implements StorableObject {
private static final AtomicInteger FAKE_ID_COUNTER = new AtomicInteger(MIN_FAKE_ID);
private static final Tag[] RESPONSE_BUTTON_LABELS = new Tag[]{
text(""),
translate(""),
translate("gui.waitingForResponse.button.inactive", 4),
translate("gui.waitingForResponse.button.inactive", 3),
translate("gui.waitingForResponse.button.inactive", 2),
@@ -19,6 +19,7 @@ package com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.storage;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viabackwards.ViaBackwards;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.Protocol1_21_6To1_21_5;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.data.Dialog;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.provider.DialogViewProvider;
@@ -59,6 +60,10 @@ public final class ClickEvents implements StorableObject {
public static void handleClickEvent(final UserConnection connection, final CompoundTag clickEvent) {
final String action = Key.stripMinecraftNamespace(clickEvent.getString("action"));
if ("show_dialog".equals(action)) {
if (!ViaBackwards.getConfig().dialogsViaChests()) {
return;
}
final RegistryAndTags registryAndTags = connection.get(RegistryAndTags.class);
final ServerLinks serverLinks = connection.get(ServerLinks.class);
@@ -17,22 +17,18 @@
*/
package com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.task;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.Protocol1_21_6To1_21_5;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.storage.ChestDialogStorage;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.protocol.ProtocolRunnable;
import com.viaversion.viaversion.connection.StorableObjectTask;
public final class ChestDialogViewTask extends ProtocolRunnable {
public final class ChestDialogViewTask extends StorableObjectTask<ChestDialogStorage> {
public ChestDialogViewTask() {
super(Protocol1_21_6To1_21_5.class);
super(ChestDialogStorage.class);
}
@Override
public void run(final UserConnection connection) {
final ChestDialogStorage storage = connection.get(ChestDialogStorage.class);
if (storage != null) {
storage.tick(connection);
}
public void run(final UserConnection userConnection, final ChestDialogStorage storableObject) {
storableObject.tick(userConnection);
}
}
@@ -19,6 +19,7 @@ package com.viaversion.viabackwards.protocol.v1_21_7to1_21_6;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.data.BackwardsMappingData;
import com.viaversion.viabackwards.api.rewriters.BackwardsRegistryRewriter;
import com.viaversion.viabackwards.api.rewriters.SoundRewriter;
import com.viaversion.viabackwards.api.rewriters.text.NBTComponentRewriter;
import com.viaversion.viabackwards.api.rewriters.text.TranslatableRewriter;
@@ -42,9 +43,9 @@ import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ServerboundPac
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ServerboundPackets1_21_6;
import com.viaversion.viaversion.protocols.v1_21_6to1_21_7.Protocol1_21_6To1_21_7;
import com.viaversion.viaversion.rewriter.ParticleRewriter;
import com.viaversion.viaversion.rewriter.RegistryDataRewriter;
import com.viaversion.viaversion.rewriter.StatisticsRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
import com.viaversion.viaversion.util.SerializerVersion;
import static com.viaversion.viaversion.util.ProtocolUtil.packetTypeMap;
@@ -56,6 +57,7 @@ public final class Protocol1_21_7To1_21_6 extends BackwardsProtocol<ClientboundP
private final ParticleRewriter<ClientboundPacket1_21_6> particleRewriter = new ParticleRewriter<>(this);
private final NBTComponentRewriter<ClientboundPacket1_21_6> translatableRewriter = new NBTComponentRewriter<>(this);
private final TagRewriter<ClientboundPacket1_21_6> tagRewriter = new TagRewriter<>(this);
private final RegistryDataRewriter registryDataRewriter = new BackwardsRegistryRewriter(this);
public Protocol1_21_7To1_21_6() {
super(ClientboundPacket1_21_6.class, ClientboundPacket1_21_6.class, ServerboundPacket1_21_6.class, ServerboundPacket1_21_6.class);
@@ -65,6 +67,8 @@ public final class Protocol1_21_7To1_21_6 extends BackwardsProtocol<ClientboundP
protected void registerPackets() {
super.registerPackets();
registerClientbound(ClientboundConfigurationPackets1_21_6.REGISTRY_DATA, registryDataRewriter::handle);
tagRewriter.registerGeneric(ClientboundPackets1_21_6.UPDATE_TAGS);
tagRewriter.registerGeneric(ClientboundConfigurationPackets1_21_6.UPDATE_TAGS);
@@ -80,12 +84,16 @@ public final class Protocol1_21_7To1_21_6 extends BackwardsProtocol<ClientboundP
translatableRewriter.registerComponentPacket(ClientboundPackets1_21_6.SET_SUBTITLE_TEXT);
translatableRewriter.registerBossEvent(ClientboundPackets1_21_6.BOSS_EVENT);
translatableRewriter.registerComponentPacket(ClientboundPackets1_21_6.DISCONNECT);
translatableRewriter.registerComponentPacket(ClientboundConfigurationPackets1_21_6.DISCONNECT);
translatableRewriter.registerTabList(ClientboundPackets1_21_6.TAB_LIST);
translatableRewriter.registerSetPlayerTeam1_21_5(ClientboundPackets1_21_6.SET_PLAYER_TEAM);
translatableRewriter.registerPlayerCombatKill1_20(ClientboundPackets1_21_6.PLAYER_COMBAT_KILL);
translatableRewriter.registerPlayerInfoUpdate1_21_4(ClientboundPackets1_21_6.PLAYER_INFO_UPDATE);
translatableRewriter.registerComponentPacket(ClientboundPackets1_21_6.SYSTEM_CHAT);
translatableRewriter.registerDisguisedChat(ClientboundPackets1_21_6.DISGUISED_CHAT);
translatableRewriter.registerPlayerChat1_21_5(ClientboundPackets1_21_6.PLAYER_CHAT);
translatableRewriter.registerSetObjective(ClientboundPackets1_21_6.SET_OBJECTIVE);
translatableRewriter.registerSetScore1_20_3(ClientboundPackets1_21_6.SET_SCORE);
translatableRewriter.registerPing();
particleRewriter.registerLevelParticles1_21_4(ClientboundPackets1_21_6.LEVEL_PARTICLES);
@@ -95,7 +103,7 @@ public final class Protocol1_21_7To1_21_6 extends BackwardsProtocol<ClientboundP
@Override
public void init(final UserConnection connection) {
addEntityTracker(connection, new EntityTrackerBase(connection, EntityTypes1_21_6.PLAYER));
addItemHasher(connection, new ItemHasherBase(this, connection, SerializerVersion.V1_21_6, SerializerVersion.V1_21_6));
addItemHasher(connection, new ItemHasherBase(this, connection));
}
@Override
@@ -128,6 +136,11 @@ public final class Protocol1_21_7To1_21_6 extends BackwardsProtocol<ClientboundP
return itemRewriter;
}
@Override
public RegistryDataRewriter getRegistryDataRewriter() {
return registryDataRewriter;
}
@Override
public ParticleRewriter<ClientboundPacket1_21_6> getParticleRewriter() {
return particleRewriter;
@@ -17,7 +17,6 @@
*/
package com.viaversion.viabackwards.protocol.v1_21_7to1_21_6.rewriter;
import com.viaversion.viabackwards.api.rewriters.BackwardsRegistryRewriter;
import com.viaversion.viabackwards.api.rewriters.EntityRewriter;
import com.viaversion.viabackwards.protocol.v1_21_7to1_21_6.Protocol1_21_7To1_21_6;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
@@ -25,10 +24,8 @@ import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_21_4;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_21_6;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_21_5;
import com.viaversion.viaversion.api.type.types.version.VersionedTypes;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundConfigurationPackets1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundPacket1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundPackets1_21_6;
import com.viaversion.viaversion.rewriter.RegistryDataRewriter;
public final class EntityPacketRewriter1_21_7 extends EntityRewriter<ClientboundPacket1_21_6, Protocol1_21_7To1_21_6> {
@@ -45,9 +42,6 @@ public final class EntityPacketRewriter1_21_7 extends EntityRewriter<Clientbound
registerGameEvent(ClientboundPackets1_21_6.GAME_EVENT);
registerLogin1_20_5(ClientboundPackets1_21_6.LOGIN);
registerRespawn1_20_5(ClientboundPackets1_21_6.RESPAWN);
final RegistryDataRewriter registryDataRewriter = new BackwardsRegistryRewriter(protocol);
protocol.registerClientbound(ClientboundConfigurationPackets1_21_6.REGISTRY_DATA, registryDataRewriter::handle);
}
@Override
@@ -0,0 +1,278 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viabackwards.protocol.v1_21_9to1_21_7;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.data.BackwardsMappingData;
import com.viaversion.viabackwards.api.rewriters.SoundRewriter;
import com.viaversion.viabackwards.api.rewriters.text.NBTComponentRewriter;
import com.viaversion.viabackwards.protocol.v1_21_9to1_21_7.rewriter.BlockItemPacketRewriter1_21_9;
import com.viaversion.viabackwards.protocol.v1_21_9to1_21_7.rewriter.ComponentRewriter1_21_9;
import com.viaversion.viabackwards.protocol.v1_21_9to1_21_7.rewriter.EntityPacketRewriter1_21_9;
import com.viaversion.viabackwards.protocol.v1_21_9to1_21_7.rewriter.ParticleRewriter1_21_9;
import com.viaversion.viabackwards.protocol.v1_21_9to1_21_7.rewriter.RegistryDataRewriter1_21_9;
import com.viaversion.viabackwards.protocol.v1_21_9to1_21_7.storage.DimensionScaleStorage;
import com.viaversion.viabackwards.protocol.v1_21_9to1_21_7.storage.PlayerRotationStorage;
import com.viaversion.viabackwards.protocol.v1_21_9to1_21_7.tracker.EntityTracker1_21_9;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.data.version.StructuredDataKeys1_21_5;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_21_9;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_21_5;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.packet.provider.PacketTypesProvider;
import com.viaversion.viaversion.api.protocol.packet.provider.SimplePacketTypesProvider;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.version.Types1_20_5;
import com.viaversion.viaversion.api.type.types.version.VersionedTypes;
import com.viaversion.viaversion.api.type.types.version.VersionedTypesHolder;
import com.viaversion.viaversion.data.item.ItemHasherBase;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundConfigurationPackets1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundPacket1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundPackets1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ServerboundConfigurationPackets1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ServerboundPacket1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ServerboundPackets1_21_6;
import com.viaversion.viaversion.protocols.v1_21_7to1_21_9.Protocol1_21_7To1_21_9;
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.ClientboundPacket1_21_9;
import com.viaversion.viaversion.protocols.v1_21_7to1_21_9.packet.ClientboundPackets1_21_9;
import com.viaversion.viaversion.protocols.v1_21_7to1_21_9.packet.ServerboundConfigurationPackets1_21_9;
import com.viaversion.viaversion.protocols.v1_21_7to1_21_9.packet.ServerboundPacket1_21_9;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.BundleStateTracker;
import com.viaversion.viaversion.rewriter.ParticleRewriter;
import com.viaversion.viaversion.rewriter.RegistryDataRewriter;
import com.viaversion.viaversion.rewriter.StatisticsRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
import static com.viaversion.viaversion.util.ProtocolUtil.packetTypeMap;
public final class Protocol1_21_9To1_21_7 extends BackwardsProtocol<ClientboundPacket1_21_9, ClientboundPacket1_21_6, ServerboundPacket1_21_9, ServerboundPacket1_21_6> {
public static final BackwardsMappingData MAPPINGS = new BackwardsMappingData("1.21.9", "1.21.7", Protocol1_21_7To1_21_9.class);
private final EntityPacketRewriter1_21_9 entityRewriter = new EntityPacketRewriter1_21_9(this);
private final BlockItemPacketRewriter1_21_9 itemRewriter = new BlockItemPacketRewriter1_21_9(this);
private final ParticleRewriter<ClientboundPacket1_21_9> particleRewriter = new ParticleRewriter1_21_9(this);
private final NBTComponentRewriter<ClientboundPacket1_21_9> translatableRewriter = new ComponentRewriter1_21_9(this);
private final TagRewriter<ClientboundPacket1_21_9> tagRewriter = new TagRewriter<>(this);
private final RegistryDataRewriter registryDataRewriter = new RegistryDataRewriter1_21_9(this);
public Protocol1_21_9To1_21_7() {
super(ClientboundPacket1_21_9.class, ClientboundPacket1_21_6.class, ServerboundPacket1_21_9.class, ServerboundPacket1_21_6.class);
}
@Override
protected void registerPackets() {
super.registerPackets();
registerClientbound(ClientboundConfigurationPackets1_21_9.REGISTRY_DATA, registryDataRewriter::handle);
tagRewriter.registerGeneric(ClientboundPackets1_21_9.UPDATE_TAGS);
tagRewriter.registerGeneric(ClientboundConfigurationPackets1_21_9.UPDATE_TAGS);
final SoundRewriter<ClientboundPacket1_21_9> soundRewriter = new SoundRewriter<>(this);
soundRewriter.registerSound1_19_3(ClientboundPackets1_21_9.SOUND);
soundRewriter.registerSound1_19_3(ClientboundPackets1_21_9.SOUND_ENTITY);
soundRewriter.registerStopSound(ClientboundPackets1_21_9.STOP_SOUND);
new StatisticsRewriter<>(this).register(ClientboundPackets1_21_9.AWARD_STATS);
translatableRewriter.registerOpenScreen1_14(ClientboundPackets1_21_9.OPEN_SCREEN);
translatableRewriter.registerComponentPacket(ClientboundPackets1_21_9.SET_ACTION_BAR_TEXT);
translatableRewriter.registerComponentPacket(ClientboundPackets1_21_9.SET_TITLE_TEXT);
translatableRewriter.registerComponentPacket(ClientboundPackets1_21_9.SET_SUBTITLE_TEXT);
translatableRewriter.registerBossEvent(ClientboundPackets1_21_9.BOSS_EVENT);
translatableRewriter.registerComponentPacket(ClientboundPackets1_21_9.DISCONNECT);
translatableRewriter.registerComponentPacket(ClientboundConfigurationPackets1_21_9.DISCONNECT);
translatableRewriter.registerTabList(ClientboundPackets1_21_9.TAB_LIST);
translatableRewriter.registerSetPlayerTeam1_21_5(ClientboundPackets1_21_9.SET_PLAYER_TEAM);
translatableRewriter.registerPlayerCombatKill1_20(ClientboundPackets1_21_9.PLAYER_COMBAT_KILL);
translatableRewriter.registerPlayerInfoUpdate1_21_4(ClientboundPackets1_21_9.PLAYER_INFO_UPDATE);
translatableRewriter.registerComponentPacket(ClientboundPackets1_21_9.SYSTEM_CHAT);
translatableRewriter.registerDisguisedChat(ClientboundPackets1_21_9.DISGUISED_CHAT);
translatableRewriter.registerPlayerChat1_21_5(ClientboundPackets1_21_9.PLAYER_CHAT);
translatableRewriter.registerSetObjective(ClientboundPackets1_21_9.SET_OBJECTIVE);
translatableRewriter.registerSetScore1_20_3(ClientboundPackets1_21_9.SET_SCORE);
translatableRewriter.registerPing();
particleRewriter.registerLevelParticles1_21_4(ClientboundPackets1_21_9.LEVEL_PARTICLES);
registerClientbound(ClientboundPackets1_21_9.EXPLODE, wrapper -> {
wrapper.passthrough(Types.DOUBLE); // X
wrapper.passthrough(Types.DOUBLE); // Y
wrapper.passthrough(Types.DOUBLE); // Z
wrapper.read(Types.FLOAT); // Radius
wrapper.read(Types.INT); // Affected blocks
if (wrapper.passthrough(Types.BOOLEAN)) {
wrapper.passthrough(Types.DOUBLE); // Knockback X
wrapper.passthrough(Types.DOUBLE); // Knockback Y
wrapper.passthrough(Types.DOUBLE); // Knockback Z
}
particleRewriter.passthroughParticle(wrapper); // Explosion particle
soundRewriter.soundHolderHandler().handle(wrapper);
final int blockParticles = wrapper.read(Types.VAR_INT);
for (int i = 0; i < blockParticles; i++) {
wrapper.read(particleRewriter.particleType());
wrapper.read(Types.FLOAT); // Scaling
wrapper.read(Types.FLOAT); // Speed
wrapper.read(Types.VAR_INT); // Weight
}
});
registerClientbound(ClientboundConfigurationPackets1_21_9.CODE_OF_CONDUCT, ClientboundConfigurationPackets1_21_6.SHOW_DIALOG, wrapper -> {
if (wrapper.user().getProtocolInfo().protocolVersion().olderThanOrEqualTo(ProtocolVersion.v1_21_5)) {
// TODO Remove once we implement dialogs during the configuration state in 1.21.6->1.21.5
wrapper.cancel();
final PacketWrapper acceptPacket = wrapper.create(ServerboundConfigurationPackets1_21_9.ACCEPT_CODE_OF_CONDUCT);
acceptPacket.sendToServer(Protocol1_21_9To1_21_7.class);
return;
}
final String codeOfConduct = wrapper.read(Types.STRING);
final CompoundTag tag = new CompoundTag();
tag.putString("type", "minecraft:confirmation");
tag.putString("title", translatableRewriter.mappedTranslationKey("multiplayer.codeOfConduct.title"));
final CompoundTag body = new CompoundTag();
body.putString("type", "minecraft:plain_message");
body.putString("contents", codeOfConduct);
tag.put("body", body);
final CompoundTag yes = new CompoundTag();
final CompoundTag yesLabel = new CompoundTag();
yesLabel.putString("translate", "gui.acknowledge");
yes.put("label", yesLabel);
final CompoundTag acceptAction = new CompoundTag();
acceptAction.putString("type", "minecraft:custom");
acceptAction.putString("id", "viabackwards:ack_code_of_conduct");
yes.put("action", acceptAction);
tag.put("yes", yes);
final CompoundTag no = new CompoundTag();
final CompoundTag noLabel = new CompoundTag();
noLabel.putString("translate", "menu.disconnect");
no.put("label", noLabel);
final CompoundTag disconnectAction = new CompoundTag();
disconnectAction.putString("type", "minecraft:custom");
disconnectAction.putString("id", "viabackwards:disconnect");
no.put("action", disconnectAction);
tag.put("no", no);
wrapper.write(Types.TAG, tag);
});
registerServerbound(ServerboundConfigurationPackets1_21_6.CUSTOM_CLICK_ACTION, wrapper -> {
final String id = wrapper.passthrough(Types.STRING);
if ("viabackwards:ack_code_of_conduct".equals(id)) {
wrapper.cancel();
final PacketWrapper acceptPacket = wrapper.create(ServerboundConfigurationPackets1_21_9.ACCEPT_CODE_OF_CONDUCT);
acceptPacket.sendToServer(Protocol1_21_9To1_21_7.class);
} else if ("viabackwards:disconnect".equals(id)) {
wrapper.cancel();
wrapper.user().disconnect(translatableRewriter.mappedTranslationKey("multiplayer.disconnect.code_of_conduct"));
}
});
registerServerbound(ServerboundPackets1_21_6.DEBUG_SAMPLE_SUBSCRIPTION, wrapper -> {
final int sampleType = wrapper.read(Types.VAR_INT);
if (sampleType == 0) { // TICK_TIME
wrapper.write(Types.VAR_INT, 1); // Subscription count
wrapper.write(Types.VAR_INT, 0); // Subscription registry id (DEDICATED_SERVER_TICK_TIME)
}
});
registerClientbound(ClientboundPackets1_21_9.BUNDLE_DELIMITER, wrapper -> wrapper.user().get(BundleStateTracker.class).toggleBundling());
cancelClientbound(ClientboundPackets1_21_9.DEBUG_BLOCK_VALUE);
cancelClientbound(ClientboundPackets1_21_9.DEBUG_CHUNK_VALUE);
cancelClientbound(ClientboundPackets1_21_9.DEBUG_ENTITY_VALUE);
cancelClientbound(ClientboundPackets1_21_9.DEBUG_EVENT);
cancelClientbound(ClientboundPackets1_21_9.GAME_EVENT_TEST_HIGHLIGHT_POS);
}
@Override
public void init(final UserConnection connection) {
addEntityTracker(connection, new EntityTracker1_21_9(connection, EntityTypes1_21_9.PLAYER));
addItemHasher(connection, new ItemHasherBase(this, connection));
connection.put(new PlayerRotationStorage());
connection.put(new DimensionScaleStorage());
connection.put(new BundleStateTracker());
}
@Override
public BackwardsMappingData getMappingData() {
return MAPPINGS;
}
@Override
public EntityPacketRewriter1_21_9 getEntityRewriter() {
return entityRewriter;
}
@Override
public BlockItemPacketRewriter1_21_9 getItemRewriter() {
return itemRewriter;
}
@Override
public RegistryDataRewriter getRegistryDataRewriter() {
return registryDataRewriter;
}
@Override
public ParticleRewriter<ClientboundPacket1_21_9> getParticleRewriter() {
return particleRewriter;
}
@Override
public NBTComponentRewriter<ClientboundPacket1_21_9> getComponentRewriter() {
return translatableRewriter;
}
@Override
public TagRewriter<ClientboundPacket1_21_9> getTagRewriter() {
return tagRewriter;
}
@Override
public VersionedTypesHolder types() {
return VersionedTypes.V1_21_9;
}
@Override
public Types1_20_5<StructuredDataKeys1_21_5, EntityDataTypes1_21_5> mappedTypes() {
return VersionedTypes.V1_21_6;
}
@Override
protected PacketTypesProvider<ClientboundPacket1_21_9, ClientboundPacket1_21_6, ServerboundPacket1_21_9, ServerboundPacket1_21_6> createPacketTypesProvider() {
return new SimplePacketTypesProvider<>(
packetTypeMap(unmappedClientboundPacketType, ClientboundPackets1_21_9.class, ClientboundConfigurationPackets1_21_9.class),
packetTypeMap(mappedClientboundPacketType, ClientboundPackets1_21_6.class, ClientboundConfigurationPackets1_21_6.class),
packetTypeMap(mappedServerboundPacketType, ServerboundPackets1_21_6.class, ServerboundConfigurationPackets1_21_9.class),
packetTypeMap(unmappedServerboundPacketType, ServerboundPackets1_21_6.class, ServerboundConfigurationPackets1_21_6.class)
);
}
}
@@ -0,0 +1,177 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viabackwards.protocol.v1_21_9to1_21_7.rewriter;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.viabackwards.api.rewriters.BackwardsStructuredItemRewriter;
import com.viaversion.viabackwards.protocol.v1_21_9to1_21_7.Protocol1_21_9To1_21_7;
import com.viaversion.viabackwards.protocol.v1_21_9to1_21_7.storage.DimensionScaleStorage;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.entity.EntityTracker;
import com.viaversion.viaversion.api.minecraft.ResolvableProfile;
import com.viaversion.viaversion.api.minecraft.blockentity.BlockEntity;
import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataContainer;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_21_5;
import com.viaversion.viaversion.protocols.v1_21_4to1_21_5.rewriter.RecipeDisplayRewriter1_21_5;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ServerboundPacket1_21_6;
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.ClientboundPacket1_21_9;
import com.viaversion.viaversion.protocols.v1_21_7to1_21_9.packet.ClientboundPackets1_21_9;
import com.viaversion.viaversion.rewriter.BlockRewriter;
import com.viaversion.viaversion.rewriter.RecipeDisplayRewriter;
import static com.viaversion.viaversion.protocols.v1_21_7to1_21_9.rewriter.BlockItemPacketRewriter1_21_9.downgradeData;
import static com.viaversion.viaversion.protocols.v1_21_7to1_21_9.rewriter.BlockItemPacketRewriter1_21_9.upgradeData;
public final class BlockItemPacketRewriter1_21_9 extends BackwardsStructuredItemRewriter<ClientboundPacket1_21_9, ServerboundPacket1_21_6, Protocol1_21_9To1_21_7> {
private static final int SIGN_BOCK_ENTITY_ID = 7;
private static final int HANGING_SIGN_BOCK_ENTITY_ID = 8;
public BlockItemPacketRewriter1_21_9(final Protocol1_21_9To1_21_7 protocol) {
super(protocol);
}
@Override
public void registerPackets() {
final BlockRewriter<ClientboundPacket1_21_9> blockRewriter = BlockRewriter.for1_20_2(protocol);
blockRewriter.registerBlockEvent(ClientboundPackets1_21_9.BLOCK_EVENT);
blockRewriter.registerBlockUpdate(ClientboundPackets1_21_9.BLOCK_UPDATE);
blockRewriter.registerSectionBlocksUpdate1_20(ClientboundPackets1_21_9.SECTION_BLOCKS_UPDATE);
blockRewriter.registerLevelEvent1_21(ClientboundPackets1_21_9.LEVEL_EVENT, 2001);
blockRewriter.registerLevelChunk1_19(ClientboundPackets1_21_9.LEVEL_CHUNK_WITH_LIGHT, ChunkType1_21_5::new, this::handleBlockEntity);
blockRewriter.registerBlockEntityData(ClientboundPackets1_21_9.BLOCK_ENTITY_DATA, this::handleBlockEntity);
registerSetCursorItem(ClientboundPackets1_21_9.SET_CURSOR_ITEM);
registerSetPlayerInventory(ClientboundPackets1_21_9.SET_PLAYER_INVENTORY);
registerCooldown1_21_2(ClientboundPackets1_21_9.COOLDOWN);
registerSetContent1_21_2(ClientboundPackets1_21_9.CONTAINER_SET_CONTENT);
registerSetSlot1_21_2(ClientboundPackets1_21_9.CONTAINER_SET_SLOT);
registerAdvancements1_20_3(ClientboundPackets1_21_9.UPDATE_ADVANCEMENTS);
registerMerchantOffers1_20_5(ClientboundPackets1_21_9.MERCHANT_OFFERS);
registerContainerClick1_21_5(ServerboundPackets1_21_6.CONTAINER_CLICK);
registerSetCreativeModeSlot1_21_5(ServerboundPackets1_21_6.SET_CREATIVE_MODE_SLOT);
final RecipeDisplayRewriter<ClientboundPacket1_21_9> recipeRewriter = new RecipeDisplayRewriter1_21_5<>(protocol);
recipeRewriter.registerUpdateRecipes(ClientboundPackets1_21_9.UPDATE_RECIPES);
recipeRewriter.registerRecipeBookAdd(ClientboundPackets1_21_9.RECIPE_BOOK_ADD);
recipeRewriter.registerPlaceGhostRecipe(ClientboundPackets1_21_9.PLACE_GHOST_RECIPE);
protocol.registerClientbound(ClientboundPackets1_21_9.INITIALIZE_BORDER, this::updateBorderCenter);
protocol.registerClientbound(ClientboundPackets1_21_9.SET_BORDER_CENTER, this::updateBorderCenter);
}
@Override
protected void handleItemDataComponentsToClient(final UserConnection connection, final Item item, final StructuredDataContainer container) {
super.handleItemDataComponentsToClient(connection, item, container);
downgradeData(item, container);
}
@Override
protected void handleItemDataComponentsToServer(final UserConnection connection, final Item item, final StructuredDataContainer container) {
super.handleItemDataComponentsToServer(connection, item, container);
upgradeData(item, container);
}
@Override
protected void backupInconvertibleData(final UserConnection connection, final Item item, final StructuredDataContainer dataContainer, final CompoundTag backupTag) {
super.backupInconvertibleData(connection, item, dataContainer, backupTag);
final ResolvableProfile profile = dataContainer.get(StructuredDataKey.PROFILE1_21_9);
if (profile != null) {
final CompoundTag profileTag = new CompoundTag();
if (profile.bodyTexture() != null) {
profileTag.putString("body_texture", profile.bodyTexture());
}
if (profile.capeTexture() != null) {
profileTag.putString("cape_texture", profile.capeTexture());
}
if (profile.elytraTexture() != null) {
profileTag.putString("elytra_texture", profile.elytraTexture());
}
if (profile.modelType() != null) {
profileTag.putBoolean("model", profile.modelType() == 0);
}
if (!profileTag.isEmpty()) {
backupTag.put("profile", profileTag);
}
}
}
@Override
protected void restoreBackupData(final Item item, final StructuredDataContainer container, final CompoundTag customData) {
super.restoreBackupData(item, container, customData);
if (!(customData.remove(nbtTagName("backup")) instanceof final CompoundTag backupTag)) {
return;
}
final CompoundTag profileTag = backupTag.getCompoundTag("profile");
if (profileTag != null) {
container.replace(StructuredDataKey.PROFILE1_20_5, StructuredDataKey.PROFILE1_21_9, profile -> new ResolvableProfile(
profile,
profileTag.getString("body_texture"),
profileTag.getString("cape_texture"),
profileTag.getString("elytra_texture"),
profileTag.contains("model") ? (profileTag.getBoolean("model") ? 0 : 1) : null
));
}
}
private void handleBlockEntity(final UserConnection connection, final BlockEntity blockEntity) {
final CompoundTag tag = blockEntity.tag();
if (tag == null) {
return;
}
if (blockEntity.typeId() == SIGN_BOCK_ENTITY_ID || blockEntity.typeId() == HANGING_SIGN_BOCK_ENTITY_ID) {
updateSignMessages(connection, tag.getCompoundTag("front_text"));
updateSignMessages(connection, tag.getCompoundTag("back_text"));
}
}
private void updateSignMessages(final UserConnection connection, final CompoundTag tag) {
if (tag == null) {
return;
}
final ListTag<?> messages = tag.getListTag("messages");
protocol.getComponentRewriter().processTag(connection, messages);
final ListTag<?> filteredMessages = tag.getListTag("filtered_messages");
if (filteredMessages != null) {
protocol.getComponentRewriter().processTag(connection, filteredMessages);
}
}
private void updateBorderCenter(final PacketWrapper wrapper) {
double centerX = wrapper.read(Types.DOUBLE);
double centerZ = wrapper.read(Types.DOUBLE);
final EntityTracker tracker = protocol.getEntityRewriter().tracker(wrapper.user());
if (tracker.currentDimensionId() != -1) {
final double scale = wrapper.user().get(DimensionScaleStorage.class).getScale(tracker.currentDimensionId());
centerX *= scale;
centerZ *= scale;
}
wrapper.write(Types.DOUBLE, centerX);
wrapper.write(Types.DOUBLE, centerZ);
}
}
@@ -0,0 +1,61 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viabackwards.protocol.v1_21_9to1_21_7.rewriter;
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.api.minecraft.data.StructuredDataKey;
import com.viaversion.viaversion.protocols.v1_21_7to1_21_9.packet.ClientboundPacket1_21_9;
public final class ComponentRewriter1_21_9 extends NBTComponentRewriter<ClientboundPacket1_21_9> {
public ComponentRewriter1_21_9(final BackwardsProtocol<ClientboundPacket1_21_9, ?, ?, ?> protocol) {
super(protocol);
}
@Override
protected void processCompoundTag(final UserConnection connection, final CompoundTag tag) {
super.processCompoundTag(connection, tag);
// Throw out the new object type and its properties
final String type = tag.getString("type");
if ("object".equals(type)) {
tag.putString("text", "");
tag.remove("type");
}
if (tag.remove("sprite") != null) {
tag.putString("text", "");
}
if (tag.remove("player") != null) {
tag.putString("text", "");
}
tag.remove("atlas");
}
@Override
protected void handleShowItem(final UserConnection connection, final CompoundTag itemTag, final CompoundTag componentsTag) {
super.handleShowItem(connection, itemTag, componentsTag);
if (componentsTag == null) {
return;
}
removeDataComponents(componentsTag, StructuredDataKey.ENTITY_DATA1_21_9, StructuredDataKey.BLOCK_ENTITY_DATA1_21_9);
}
}
@@ -0,0 +1,525 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viabackwards.protocol.v1_21_9to1_21_7.rewriter;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viabackwards.api.rewriters.EntityRewriter;
import com.viaversion.viabackwards.protocol.v1_21_9to1_21_7.Protocol1_21_9To1_21_7;
import com.viaversion.viabackwards.protocol.v1_21_9to1_21_7.storage.MannequinData;
import com.viaversion.viabackwards.protocol.v1_21_9to1_21_7.storage.PlayerRotationStorage;
import com.viaversion.viabackwards.protocol.v1_21_9to1_21_7.tracker.EntityTracker1_21_9;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.entity.TrackedEntity;
import com.viaversion.viaversion.api.minecraft.BlockPosition;
import com.viaversion.viaversion.api.minecraft.GameProfile;
import com.viaversion.viaversion.api.minecraft.GlobalBlockPosition;
import com.viaversion.viaversion.api.minecraft.ResolvableProfile;
import com.viaversion.viaversion.api.minecraft.Vector3d;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_21_6;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_21_9;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_21_5;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.version.VersionedTypes;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundPackets1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ServerboundPackets1_21_6;
import com.viaversion.viaversion.protocols.v1_21_7to1_21_9.packet.ClientboundPacket1_21_9;
import com.viaversion.viaversion.protocols.v1_21_7to1_21_9.packet.ClientboundPackets1_21_9;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.BundleStateTracker;
import com.viaversion.viaversion.rewriter.entitydata.EntityDataHandler;
import com.viaversion.viaversion.util.ChatColorUtil;
import com.viaversion.viaversion.util.Copyable;
import java.util.BitSet;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import org.checkerframework.checker.nullness.qual.Nullable;
public final class EntityPacketRewriter1_21_9 extends EntityRewriter<ClientboundPacket1_21_9, Protocol1_21_9To1_21_7> {
public EntityPacketRewriter1_21_9(final Protocol1_21_9To1_21_7 protocol) {
super(protocol, VersionedTypes.V1_21_9.entityDataTypes.optionalComponentType, VersionedTypes.V1_21_9.entityDataTypes.booleanType);
}
@Override
public void registerPackets() {
registerSetEntityData(ClientboundPackets1_21_9.SET_ENTITY_DATA);
registerRemoveEntities(ClientboundPackets1_21_9.REMOVE_ENTITIES);
registerPlayerAbilities(ClientboundPackets1_21_9.PLAYER_ABILITIES);
registerGameEvent(ClientboundPackets1_21_9.GAME_EVENT);
registerLogin1_20_5(ClientboundPackets1_21_9.LOGIN);
registerRespawn1_20_5(ClientboundPackets1_21_9.RESPAWN);
protocol.registerClientbound(ClientboundPackets1_21_9.ADD_ENTITY, wrapper -> {
final int entityId = wrapper.passthrough(Types.VAR_INT);
final UUID uuid = wrapper.passthrough(Types.UUID);
final int entityTypeId = wrapper.passthrough(Types.VAR_INT);
final double x = wrapper.passthrough(Types.DOUBLE);
final double y = wrapper.passthrough(Types.DOUBLE);
final double z = wrapper.passthrough(Types.DOUBLE);
final Vector3d movement = wrapper.read(Types.MOVEMENT_VECTOR);
final byte pitch = wrapper.passthrough(Types.BYTE);
final byte yaw = wrapper.passthrough(Types.BYTE);
final byte headYaw = wrapper.passthrough(Types.BYTE);
final int data = wrapper.passthrough(Types.VAR_INT);
final EntityType entityType = trackAndRewrite(wrapper, entityTypeId, entityId);
if (protocol.getMappingData() != null && entityType == EntityTypes1_21_9.FALLING_BLOCK) {
final int mappedBlockStateId = protocol.getMappingData().getNewBlockStateId(data);
wrapper.set(Types.VAR_INT, 2, mappedBlockStateId);
}
writeMovementShorts(wrapper, movement);
if (EntityTypes1_21_9.getTypeFromId(entityTypeId) == EntityTypes1_21_9.MANNEQUIN) {
final String name = randomHackyEmptyName();
final MannequinData mannequinData = new MannequinData(uuid, name);
final TrackedEntity trackedEntity = tracker(wrapper.user()).entity(entityId);
trackedEntity.data().put(mannequinData);
sendInitialPlayerInfoUpdate(wrapper.user(), mannequinData, null, new GameProfile.Property[0]);
mannequinData.setPosition(x, y, z);
mannequinData.setRotation(yaw, pitch);
mannequinData.setHeadYaw(headYaw);
}
});
// Track movement
protocol.registerClientbound(ClientboundPackets1_21_9.TELEPORT_ENTITY, this::trackMannequinTeleport);
protocol.registerClientbound(ClientboundPackets1_21_9.ENTITY_POSITION_SYNC, this::trackMannequinTeleport);
protocol.registerClientbound(ClientboundPackets1_21_9.MOVE_ENTITY_POS, wrapper -> storeMovementMannequinData(wrapper, true, false));
protocol.registerClientbound(ClientboundPackets1_21_9.MOVE_ENTITY_POS_ROT, wrapper -> storeMovementMannequinData(wrapper, true, true));
protocol.registerClientbound(ClientboundPackets1_21_9.MOVE_ENTITY_ROT, wrapper -> storeMovementMannequinData(wrapper, false, true));
protocol.registerClientbound(ClientboundPackets1_21_9.ROTATE_HEAD, wrapper -> {
final int vehicleId = wrapper.passthrough(Types.VAR_INT);
final byte headRotation = wrapper.passthrough(Types.BYTE);
final EntityTracker1_21_9 tracker = tracker(wrapper.user());
final TrackedEntity trackedEntity = tracker.entity(vehicleId);
if (trackedEntity != null && trackedEntity.hasData()) {
final MannequinData data = trackedEntity.data().get(MannequinData.class);
if (data != null) {
data.setHeadYaw(headRotation);
}
}
});
// Track passengers
protocol.registerClientbound(ClientboundPackets1_21_9.SET_PASSENGERS, wrapper -> {
final int vehicleId = wrapper.passthrough(Types.VAR_INT);
final int[] passengerIds = wrapper.passthrough(Types.VAR_INT_ARRAY_PRIMITIVE);
final EntityTracker1_21_9 tracker = tracker(wrapper.user());
final TrackedEntity trackedEntity = tracker.entity(vehicleId);
if (trackedEntity != null && trackedEntity.hasData()) {
final MannequinData data = trackedEntity.data().get(MannequinData.class);
if (data != null) {
data.setPassengers(passengerIds);
}
}
});
// Track items
protocol.registerClientbound(ClientboundPackets1_21_9.SET_EQUIPMENT, wrapper -> {
final int entityId = wrapper.passthrough(Types.VAR_INT);
final TrackedEntity trackedEntity = tracker(wrapper.user()).entity(entityId);
final MannequinData mannequinData = trackedEntity != null && trackedEntity.hasData() ? trackedEntity.data().get(MannequinData.class) : null;
byte slot;
do {
slot = wrapper.passthrough(Types.BYTE);
final Item item = protocol.getItemRewriter().handleItemToClient(wrapper.user(), wrapper.read(protocol.getItemRewriter().itemType()));
wrapper.write(protocol.getItemRewriter().mappedItemType(), item);
if (mannequinData != null) {
mannequinData.setEquipment((byte) (slot & 0x7F), item);
}
} while (slot < 0);
});
// Back to more non-mannequin things
protocol.registerClientbound(ClientboundPackets1_21_9.SET_ENTITY_MOTION, wrapper -> {
wrapper.passthrough(Types.VAR_INT); // Entity ID
writeMovementShorts(wrapper, wrapper.read(Types.MOVEMENT_VECTOR));
});
protocol.registerClientbound(ClientboundPackets1_21_9.PLAYER_ROTATION, wrapper -> {
final PlayerRotationStorage storage = wrapper.user().get(PlayerRotationStorage.class);
float yRot = wrapper.read(Types.FLOAT);
if (wrapper.read(Types.BOOLEAN)) {
yRot = storage.yaw() + yRot;
}
float xRot = wrapper.read(Types.FLOAT);
if (wrapper.read(Types.BOOLEAN)) {
xRot = storage.pitch() + xRot;
}
wrapper.write(Types.FLOAT, yRot);
wrapper.write(Types.FLOAT, xRot);
storage.setRotation(yRot, xRot); // Update after having used its previous data
});
protocol.registerClientbound(ClientboundPackets1_21_9.SET_DEFAULT_SPAWN_POSITION, wrapper -> {
final GlobalBlockPosition pos = wrapper.read(Types.GLOBAL_POSITION);
wrapper.write(Types.BLOCK_POSITION1_14, new BlockPosition(pos.x(), pos.y(), pos.z()));
wrapper.passthrough(Types.FLOAT); // Yaw
wrapper.read(Types.FLOAT); // Pitch
});
protocol.registerServerbound(ServerboundPackets1_21_6.MOVE_PLAYER_POS_ROT, wrapper -> {
wrapper.passthrough(Types.DOUBLE); // X
wrapper.passthrough(Types.DOUBLE); // Y
wrapper.passthrough(Types.DOUBLE); // Z
storePlayerRotation(wrapper);
});
protocol.registerServerbound(ServerboundPackets1_21_6.MOVE_PLAYER_ROT, this::storePlayerRotation);
}
private void trackMannequinTeleport(final PacketWrapper wrapper) {
final int entityId = wrapper.passthrough(Types.VAR_INT);
final EntityTracker1_21_9 tracker = tracker(wrapper.user());
final TrackedEntity trackedEntity = tracker.entity(entityId);
if (trackedEntity == null || !trackedEntity.hasData()) {
return;
}
final MannequinData mannequinData = trackedEntity.data().get(MannequinData.class);
if (mannequinData == null) {
return;
}
final double x = wrapper.passthrough(Types.DOUBLE);
final double y = wrapper.passthrough(Types.DOUBLE);
final double z = wrapper.passthrough(Types.DOUBLE);
wrapper.passthrough(Types.DOUBLE); // Delta movement X
wrapper.passthrough(Types.DOUBLE); // Delta movement Y
wrapper.passthrough(Types.DOUBLE); // Delta movement Z
final byte yaw = (byte) Math.floor(wrapper.passthrough(Types.FLOAT) * 256F / 360F);
final byte pitch = (byte) Math.floor(wrapper.passthrough(Types.FLOAT) * 256F / 360F);
mannequinData.setPosition(x, y, z);
mannequinData.setRotation(yaw, pitch);
}
private void storeMovementMannequinData(final PacketWrapper wrapper, final boolean position, final boolean rotation) {
final int entityId = wrapper.passthrough(Types.VAR_INT);
final TrackedEntity trackedEntity = tracker(wrapper.user()).entity(entityId);
if (trackedEntity == null || !trackedEntity.hasData()) {
return;
}
final MannequinData mannequinData = trackedEntity.data().get(MannequinData.class);
if (mannequinData == null) {
return;
}
if (position) {
final double deltaX = wrapper.passthrough(Types.SHORT) / 4096.0;
final double deltaY = wrapper.passthrough(Types.SHORT) / 4096.0;
final double deltaZ = wrapper.passthrough(Types.SHORT) / 4096.0;
mannequinData.setPosition(mannequinData.x() + deltaX, mannequinData.y() + deltaY, mannequinData.z() + deltaZ);
}
if (rotation) {
final byte yaw = wrapper.passthrough(Types.BYTE);
final byte pitch = wrapper.passthrough(Types.BYTE);
mannequinData.setRotation(yaw, pitch);
}
}
private void sendInitialPlayerInfoUpdate(final UserConnection connection, final MannequinData mannequinData, final @Nullable String nameOverride, final GameProfile.Property[] properties) {
final PacketWrapper playerInfo = PacketWrapper.create(ClientboundPackets1_21_6.PLAYER_INFO_UPDATE, connection);
final BitSet actions = new BitSet(8);
for (int i = 0; i < 8; i++) {
actions.set(i);
}
playerInfo.write(Types.PROFILE_ACTIONS_ENUM1_21_4, actions);
playerInfo.write(Types.VAR_INT, 1); // One entry
playerInfo.write(Types.UUID, mannequinData.uuid());
playerInfo.write(Types.STRING, nameOverride != null ? nameOverride : mannequinData.name());
playerInfo.write(Types.PROFILE_PROPERTY_ARRAY, properties);
playerInfo.write(Types.BOOLEAN, false); // Session info
playerInfo.write(Types.VAR_INT, 0); // Gamemode
playerInfo.write(Types.BOOLEAN, false); // Listed
playerInfo.write(Types.VAR_INT, 0); // Latency
playerInfo.write(Types.OPTIONAL_TAG, null);
playerInfo.write(Types.VAR_INT, 1000); // List order
playerInfo.write(Types.BOOLEAN, true); // Show hat
playerInfo.send(Protocol1_21_9To1_21_7.class);
sendPlayerTeamDisplayName(connection, mannequinData, mannequinData.displayName());
}
private void sendPlayerInfoDisplayNameUpdate(final UserConnection connection, final MannequinData mannequinData, @Nullable final Tag displayName) {
final PacketWrapper playerInfo = PacketWrapper.create(ClientboundPackets1_21_6.PLAYER_INFO_UPDATE, connection);
final BitSet actions = new BitSet(8);
actions.set(5);
playerInfo.write(Types.PROFILE_ACTIONS_ENUM1_21_4, actions);
playerInfo.write(Types.VAR_INT, 1);
playerInfo.write(Types.UUID, mannequinData.uuid());
playerInfo.write(Types.OPTIONAL_TAG, displayName);
playerInfo.send(Protocol1_21_9To1_21_7.class);
sendPlayerTeamDisplayName(connection, mannequinData, displayName);
}
private void sendPlayerTeamDisplayName(final UserConnection connection, final MannequinData mannequinData, final Tag displayName) {
// Send the display name as a team prefix
final Tag nonNullDisplayName = displayName != null ? displayName : new StringTag("Mannequin");
final PacketWrapper addTeam = PacketWrapper.create(ClientboundPackets1_21_6.SET_PLAYER_TEAM, connection);
addTeam.write(Types.STRING, mannequinData.name());
addTeam.write(Types.BYTE, mannequinData.hasTeam() ? (byte) 2 : 0); // Mode
addTeam.write(Types.TAG, nonNullDisplayName); // Display Name
addTeam.write(Types.BYTE, (byte) 0); // Flags
addTeam.write(Types.VAR_INT, 0); // Nametag visibility
addTeam.write(Types.VAR_INT, 0); // Collision rule
addTeam.write(Types.VAR_INT, 15); // Color
addTeam.write(Types.TAG, nonNullDisplayName); // Prefix
addTeam.write(Types.TAG, new StringTag("")); // Suffix
if (!mannequinData.hasTeam()) {
addTeam.write(Types.STRING_ARRAY, new String[]{mannequinData.name()});
}
addTeam.send(Protocol1_21_9To1_21_7.class);
}
private String randomHackyEmptyName() {
final StringBuilder builder = new StringBuilder();
// Player names cannot be updated after the initial add without fully respawning them;
// Stack random color codes to appear as an empty name, later filled with a team prefix
for (int i = 0; i < 8; i++) {
final int random = ThreadLocalRandom.current().nextInt(ChatColorUtil.ALL_CODES.length());
builder.append('§').append(ChatColorUtil.ALL_CODES.charAt(random));
}
return builder.toString();
}
private void writeMovementShorts(final PacketWrapper wrapper, final Vector3d movement) {
wrapper.write(Types.SHORT, (short) (movement.x() * 8000));
wrapper.write(Types.SHORT, (short) (movement.y() * 8000));
wrapper.write(Types.SHORT, (short) (movement.z() * 8000));
}
private void storePlayerRotation(final PacketWrapper wrapper) {
final float yaw = wrapper.passthrough(Types.FLOAT);
final float pitch = wrapper.passthrough(Types.FLOAT);
wrapper.user().get(PlayerRotationStorage.class).setRotation(yaw, pitch);
}
@Override
protected void registerRewrites() {
final EntityDataTypes1_21_5 entityDataTypes = protocol.mappedTypes().entityDataTypes();
filter().handler((event, data) -> {
int id = data.dataType().typeId();
if (id == VersionedTypes.V1_21_9.entityDataTypes.copperGolemState.typeId()
|| id == VersionedTypes.V1_21_9.entityDataTypes.weatheringCopperState.typeId()) {
event.cancel();
return;
}
if (id == VersionedTypes.V1_21_9.entityDataTypes.mannequinProfileType.typeId()) {
if (event.entityType() == null) {
event.cancel();
}
return; // Handled separately
}
if (id > VersionedTypes.V1_21_9.entityDataTypes.armadilloState.typeId()) {
id -= 2;
}
if (id >= entityDataTypes.compoundTagType.typeId()) {
id++;
}
data.setDataType(entityDataTypes.byId(id));
});
registerEntityDataTypeHandler1_20_3(
entityDataTypes.itemType,
entityDataTypes.blockStateType,
entityDataTypes.optionalBlockStateType,
entityDataTypes.particleType,
entityDataTypes.particlesType,
entityDataTypes.componentType,
entityDataTypes.optionalComponentType
);
final EntityDataHandler shoulderDataHandler = (event, data) -> {
final CompoundTag entityTag = new CompoundTag();
final Integer value = data.value();
if (value != null) {
entityTag.putInt("id", EntityTypes1_21_6.PARROT.getId());
entityTag.putInt("Variant", value);
}
data.setTypeAndValue(protocol.mappedTypes().entityDataTypes.compoundTagType, entityTag);
};
filter().type(EntityTypes1_21_9.PLAYER).index(19).handler(shoulderDataHandler);
filter().type(EntityTypes1_21_9.PLAYER).index(20).handler(shoulderDataHandler);
filter().type(EntityTypes1_21_9.PLAYER).handler((event, data) -> {
if (event.index() == 15) {
event.setIndex(18);
} else if (event.index() == 16) {
event.setIndex(17);
} else if (event.index() == 17 || event.index() == 18) {
event.setIndex(event.index() - 2); // Move hearts and score back down
}
});
filter().type(EntityTypes1_21_9.MANNEQUIN).handler((event, data) -> {
if (event.index() == 2) { // Display name
final Tag displayName = data.value();
final MannequinData mannequinData = event.trackedEntity().data().get(MannequinData.class);
mannequinData.setDisplayName(displayName);
sendPlayerInfoDisplayNameUpdate(event.user(), mannequinData, displayName);
} else if (event.index() == 17) { // Profile
final boolean isBundling = event.user().get(BundleStateTracker.class).isBundling();
if (!isBundling) {
final PacketWrapper bundleStart = PacketWrapper.create(ClientboundPackets1_21_6.BUNDLE_DELIMITER, event.user());
bundleStart.send(Protocol1_21_9To1_21_7.class);
}
final ResolvableProfile profile = data.value();
final MannequinData mannequinData = event.trackedEntity().data().get(MannequinData.class);
final UUID uuid = mannequinData.uuid();
// Remove the old entity
final PacketWrapper removeEntityPacket = PacketWrapper.create(ClientboundPackets1_21_6.REMOVE_ENTITIES, event.user());
removeEntityPacket.write(Types.VAR_INT_ARRAY_PRIMITIVE, new int[]{event.entityId()});
removeEntityPacket.send(Protocol1_21_9To1_21_7.class);
final PacketWrapper playerInfoRemove = PacketWrapper.create(ClientboundPackets1_21_6.PLAYER_INFO_REMOVE, event.user());
playerInfoRemove.write(Types.UUID_ARRAY, new UUID[]{uuid});
playerInfoRemove.send(Protocol1_21_9To1_21_7.class);
// Spawn new entity
sendInitialPlayerInfoUpdate(event.user(), mannequinData, profile.profile().name(), profile.profile().properties());
final PacketWrapper spawnEntityPacket = PacketWrapper.create(ClientboundPackets1_21_6.ADD_ENTITY, event.user());
spawnEntityPacket.write(Types.VAR_INT, event.entityId());
spawnEntityPacket.write(Types.UUID, mannequinData.uuid());
spawnEntityPacket.write(Types.VAR_INT, EntityTypes1_21_6.PLAYER.getId());
spawnEntityPacket.write(Types.DOUBLE, mannequinData.x());
spawnEntityPacket.write(Types.DOUBLE, mannequinData.y());
spawnEntityPacket.write(Types.DOUBLE, mannequinData.z());
spawnEntityPacket.write(Types.BYTE, mannequinData.pitch());
spawnEntityPacket.write(Types.BYTE, mannequinData.yaw());
spawnEntityPacket.write(Types.BYTE, mannequinData.headYaw());
spawnEntityPacket.write(Types.VAR_INT, 0); // Data
spawnEntityPacket.write(Types.SHORT, (short) 0); // Velocity X
spawnEntityPacket.write(Types.SHORT, (short) 0); // Velocity Y
spawnEntityPacket.write(Types.SHORT, (short) 0); // Velocity Z
spawnEntityPacket.send(Protocol1_21_9To1_21_7.class);
// Re-apply entity data previously set
final PacketWrapper setEntityDataPacket = PacketWrapper.create(ClientboundPackets1_21_6.SET_ENTITY_DATA, event.user());
setEntityDataPacket.write(Types.VAR_INT, event.entityId());
setEntityDataPacket.write(VersionedTypes.V1_21_6.entityDataList, mannequinData.entityData());
setEntityDataPacket.send(Protocol1_21_9To1_21_7.class);
// Re-attach all passengers
if (mannequinData.passengers() != null) {
final PacketWrapper setPassengersPacket = PacketWrapper.create(ClientboundPackets1_21_6.SET_PASSENGERS, event.user());
setPassengersPacket.write(Types.VAR_INT, event.entityId());
setPassengersPacket.write(Types.VAR_INT_ARRAY_PRIMITIVE, mannequinData.passengers());
setPassengersPacket.send(Protocol1_21_9To1_21_7.class);
}
// Put on items
if (!mannequinData.itemMap().isEmpty()) {
final PacketWrapper equipment = PacketWrapper.create(ClientboundPackets1_21_6.SET_EQUIPMENT, event.user());
equipment.write(Types.VAR_INT, event.entityId());
int i = 0;
for (final Map.Entry<Byte, Item> itemEntry : mannequinData.itemMap().entrySet()) {
final boolean more = i < mannequinData.itemMap().size() - 1;
equipment.write(Types.BYTE, more ? (byte) (itemEntry.getKey() | -128) : itemEntry.getKey());
equipment.write(protocol.getItemRewriter().mappedItemType(), itemEntry.getValue());
i++;
}
equipment.send(Protocol1_21_9To1_21_7.class);
}
if (!isBundling) {
final PacketWrapper bundleStart = PacketWrapper.create(ClientboundPackets1_21_6.BUNDLE_DELIMITER, event.user());
bundleStart.send(Protocol1_21_9To1_21_7.class);
}
event.cancel();
} else if (event.index() == 15) {
event.setIndex(18);
} else if (event.index() == 16) {
event.setIndex(17);
} else if (event.index() == 18) {
// TODO Immovable?
event.cancel();
} else if (event.index() == 19) {
event.cancel(); // Description
}
});
}
@Override
public void handleEntityData(final int entityId, final List<EntityData> dataList, final UserConnection connection) {
super.handleEntityData(entityId, dataList, connection);
final EntityTracker1_21_9 tracker = tracker(connection);
final EntityType entityType = tracker.entityType(entityId);
if (entityType == null || !entityType.isOrHasParent(EntityTypes1_21_9.MANNEQUIN)) {
return;
}
final MannequinData mannequinData = tracker.entity(entityId).data().get(MannequinData.class);
if (mannequinData == null) {
return;
}
final List<EntityData> entityData = mannequinData.entityData();
entityData.removeIf(first -> dataList.stream().anyMatch(second -> first.id() == second.id()));
for (final EntityData data : dataList) {
final Object value = data.value();
entityData.add(new EntityData(data.id(), data.dataType(), Copyable.copy(value)));
}
}
@Override
public void onMappingDataLoaded() {
mapTypes();
mapEntityTypeWithData(EntityTypes1_21_9.COPPER_GOLEM, EntityTypes1_21_9.FROG).tagName();
mapEntityTypeWithData(EntityTypes1_21_9.MANNEQUIN, EntityTypes1_21_9.PLAYER);
}
@Override
public EntityType typeFromId(final int type) {
return EntityTypes1_21_9.getTypeFromId(type);
}
}
@@ -0,0 +1,46 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viabackwards.protocol.v1_21_9to1_21_7.rewriter;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.Particle;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.protocols.v1_21_7to1_21_9.packet.ClientboundPacket1_21_9;
import com.viaversion.viaversion.rewriter.ParticleRewriter;
public final class ParticleRewriter1_21_9 extends ParticleRewriter<ClientboundPacket1_21_9> {
public ParticleRewriter1_21_9(final Protocol<ClientboundPacket1_21_9, ?, ?, ?> protocol) {
super(protocol);
}
@Override
public void rewriteParticle(final UserConnection connection, final Particle particle) {
super.rewriteParticle(connection, particle);
final String identifier = protocol.getMappingData().getParticleMappings().mappedIdentifier(particle.id());
if ("minecraft:dragon_breath".equals(identifier)) {
particle.removeArgument(0); // Power
} else if ("minecraft:flash".equals(identifier)) {
particle.removeArgument(0); // Color
} else if ("minecraft:effect".equals(identifier) || "minecraft:instant_effect".equals(identifier)) {
particle.removeArgument(1); // Power
particle.removeArgument(0); // Color
}
}
}
@@ -0,0 +1,52 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viabackwards.protocol.v1_21_9to1_21_7.rewriter;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.rewriters.BackwardsRegistryRewriter;
import com.viaversion.viabackwards.protocol.v1_21_9to1_21_7.storage.DimensionScaleStorage;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.RegistryEntry;
public final class RegistryDataRewriter1_21_9 extends BackwardsRegistryRewriter {
public RegistryDataRewriter1_21_9(final BackwardsProtocol<?, ?, ?, ?> protocol) {
super(protocol);
}
@Override
public void trackDimensionAndBiomes(final UserConnection connection, final String registryKey, final RegistryEntry[] entries) {
super.trackDimensionAndBiomes(connection, registryKey, entries);
if (!registryKey.equals("dimension_type")) {
return;
}
final DimensionScaleStorage dimensionScaleStorage = connection.get(DimensionScaleStorage.class);
for (int i = 0; i < entries.length; i++) {
final RegistryEntry entry = entries[i];
final CompoundTag dimension = (CompoundTag) entry.tag();
if (dimension == null) {
continue;
}
final double coordinateScale = dimension.getDouble("coordinate_scale", 1);
dimensionScaleStorage.setScale(i, coordinateScale);
}
}
}
@@ -0,0 +1,35 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viabackwards.protocol.v1_21_9to1_21_7.storage;
import com.viaversion.viaversion.api.connection.StorableObject;
import java.util.HashMap;
import java.util.Map;
public final class DimensionScaleStorage implements StorableObject {
private final Map<Integer, Double> dimensionScales = new HashMap<>(4);
public double getScale(final int dimensionId) {
return dimensionScales.getOrDefault(dimensionId, 1D);
}
public void setScale(final int dimensionId, final double scale) {
dimensionScales.put(dimensionId, scale);
}
}
Loaded 100 of 145 files, more files were not shown because too many files have changed in this diff. Show more