mirror of
https://github.com/ViaVersion/ViaRewind.git
synced 2026-11-04 17:00:20 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d8e4746053 | ||
|
|
82a3ee84e0 | ||
|
|
9df4d11f8c | ||
|
|
c92916a265 | ||
|
|
dc04defeb6 | ||
|
|
c7edeba340 | ||
|
|
d232bd020f | ||
|
|
2525d42666 | ||
|
|
4d51a62410 | ||
|
|
b177e048dd | ||
|
|
7577279fcb | ||
|
|
e3211f99ef | ||
|
|
d562f9745a | ||
|
|
7339df9fdb | ||
|
|
d98d5bed9b | ||
|
|
786529efbe | ||
|
|
71546a7699 | ||
|
|
9e7c853a5d | ||
|
|
315a1a0fab | ||
|
|
7a2898e44a | ||
|
|
5783fa98e9 | ||
|
|
77d9d9143e | ||
|
|
ede1920686 | ||
|
|
189249478f | ||
|
|
6c19760af6 | ||
|
|
69f8213445 | ||
|
|
f95871bdc5 | ||
|
|
7d6c75ad31 | ||
|
|
0bb7be88ff | ||
|
|
4b7264c944 | ||
|
|
db6afa5b1b | ||
|
|
02f55edb0c | ||
|
|
5ef900a61e | ||
|
|
4fe7e35f6b | ||
|
|
1af08ced41 | ||
|
|
fd1d3ed221 | ||
|
|
1d6ef8833f | ||
|
|
f2e2f18511 | ||
|
|
2adf7757f0 | ||
|
|
4dd3de2ce9 | ||
|
|
ddbdbdb1cc | ||
|
|
28b4998912 | ||
|
|
f9b0fd5c5a | ||
|
|
a676368588 | ||
|
|
966231ad1c | ||
|
|
d73c2198ea | ||
|
|
6f319932be | ||
|
|
f172de2742 | ||
|
|
ca25da9445 | ||
|
|
ea548dfd91 | ||
|
|
d0561f2e19 | ||
|
|
2c8189a447 | ||
|
|
48c9e45bcf | ||
|
|
ecb4f4bf00 | ||
|
|
6ea9377622 | ||
|
|
b789fdebb7 | ||
|
|
e7b0606e18 | ||
|
|
bf490c3805 | ||
|
|
7ca7078141 | ||
|
|
170af55f91 | ||
|
|
00d82f9f2f | ||
|
|
79ef613c15 | ||
|
|
e2fcbafc70 | ||
|
|
9ae46145e5 | ||
|
|
76f90b68b8 | ||
|
|
32a2ee6bfa | ||
|
|
04878b7e34 | ||
|
|
adccdc4b41 | ||
|
|
0accea66f2 | ||
|
|
65257be3ee | ||
|
|
880e879dce | ||
|
|
0ccc6a0923 | ||
|
|
7bff361e14 | ||
|
|
c2c28473cc | ||
|
|
048d502998 | ||
|
|
e0c1f53115 | ||
|
|
e5313a466b | ||
|
|
e30633e367 | ||
|
|
a443dd5d11 | ||
|
|
3820426bce | ||
|
|
031ae32f27 | ||
|
|
e83616139e | ||
|
|
7325b733d6 | ||
|
|
e64501eae8 | ||
|
|
2d99607c35 | ||
|
|
4d159189c0 | ||
|
|
2076294856 | ||
|
|
49f7bd22be | ||
|
|
298605874d | ||
|
|
35b94f1878 | ||
|
|
37955059c4 | ||
|
|
af4306bc81 | ||
|
|
98ca00f625 | ||
|
|
598804432b | ||
|
|
92bae0a5c4 | ||
|
|
d50b6a2f89 | ||
|
|
54cc085717 | ||
|
|
bd0d4c31b2 | ||
|
|
705c88f4b3 | ||
|
|
7306a795b9 | ||
|
|
dfdfad4bfc | ||
|
|
c87654848d |
No files matched your search
+2
-2
@@ -1,2 +1,2 @@
|
||||
github: FlorianMichael
|
||||
custom: [ 'https://florianmichael.de/donate', 'https://creeper123123321.github.io/#donate' ]
|
||||
github: florianreuth
|
||||
custom: [ 'https://florianreuth.de/donate', 'https://creeper123123321.github.io/#donate' ]
|
||||
+10
-2
@@ -5,10 +5,18 @@ updates:
|
||||
default-days: 7
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
interval: "monthly"
|
||||
groups:
|
||||
all-dependencies:
|
||||
patterns:
|
||||
- "*"
|
||||
- package-ecosystem: "github-actions"
|
||||
cooldown:
|
||||
default-days: 7
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
interval: "monthly"
|
||||
groups:
|
||||
all-dependencies:
|
||||
patterns:
|
||||
- "*"
|
||||
+13
-11
@@ -2,29 +2,31 @@ 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
|
||||
runs-on: ubuntu-26.04
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # 6.0.0
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Set up Gradle
|
||||
uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # 5.0.0
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # 5.0.0
|
||||
uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6.3.0
|
||||
with:
|
||||
cache-disabled: true
|
||||
cache-provider: basic
|
||||
- name: Set up Java
|
||||
uses: actions/setup-java@dd06d9cba3e5552c54d9f8ea23572deb30010f7c # v6.0.0
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: 17
|
||||
java-version: 25
|
||||
check-latest: true
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew build
|
||||
run: ./gradlew build --stacktrace
|
||||
- name: Upload Artifacts to GitHub
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # 5.0.0
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: Artifacts
|
||||
path: build/libs/
|
||||
if-no-files-found: error
|
||||
@@ -12,22 +12,26 @@ permissions:
|
||||
jobs:
|
||||
publish:
|
||||
if: github.repository_owner == 'ViaVersion'
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # 6.0.0
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Set up Gradle
|
||||
uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # 5.0.0
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # 5.0.0
|
||||
uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6.3.0
|
||||
with:
|
||||
cache-disabled: true
|
||||
cache-provider: basic
|
||||
- name: Set up Java
|
||||
uses: actions/setup-java@dd06d9cba3e5552c54d9f8ea23572deb30010f7c # v6.0.0
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: 17
|
||||
java-version: 25
|
||||
check-latest: true
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew build
|
||||
run: ./gradlew build --stacktrace
|
||||
- name: Publish to Hangar
|
||||
env:
|
||||
HANGAR_TOKEN: ${{ secrets.HANGAR_TOKEN }}
|
||||
|
||||
+23
-10
@@ -1,10 +1,17 @@
|
||||
import de.florianmichael.baseproject.*
|
||||
import de.florianreuth.baseproject.core.configureEmbeddedDependencies
|
||||
import de.florianreuth.baseproject.integration.branchName
|
||||
import de.florianreuth.baseproject.integration.latestCommitHash
|
||||
import de.florianreuth.baseproject.integration.latestCommitMessage
|
||||
import de.florianreuth.baseproject.setupProject
|
||||
import de.florianreuth.baseproject.setupViaPublishing
|
||||
import net.raphimc.classtokenreplacer.extension.ClassTokenReplacerExtension
|
||||
|
||||
plugins {
|
||||
`java-library`
|
||||
id("io.papermc.hangar-publish-plugin")
|
||||
id("com.modrinth.minotaur")
|
||||
id("de.florianmichael.baseproject.BaseProject")
|
||||
id("de.florianreuth.baseproject")
|
||||
id("net.raphimc.class-token-replacer") apply false
|
||||
}
|
||||
|
||||
allprojects {
|
||||
@@ -13,7 +20,6 @@ allprojects {
|
||||
setupViaPublishing()
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven("https://repo.viaversion.com")
|
||||
maven("https://repo.papermc.io/repository/maven-public")
|
||||
maven("https://maven.fabricmc.net")
|
||||
@@ -21,11 +27,22 @@ allprojects {
|
||||
|
||||
}
|
||||
|
||||
val commitHash = latestCommitHash()
|
||||
|
||||
subprojects {
|
||||
|
||||
apply(plugin = "net.raphimc.class-token-replacer")
|
||||
|
||||
dependencies {
|
||||
compileOnly("com.viaversion:viaversion:5.5.1")
|
||||
compileOnly("com.viaversion:viabackwards:5.5.1")
|
||||
compileOnly("com.viaversion:viaversion:5.12.0")
|
||||
compileOnly("com.viaversion:viabackwards:5.12.0")
|
||||
}
|
||||
|
||||
extensions.getByType<SourceSetContainer>().configureEach {
|
||||
extensions.getByType(ClassTokenReplacerExtension::class.java).apply {
|
||||
property("\${version}", project.version)
|
||||
property("\${impl_version}", "git-ViaRewind-${project.version}:${commitHash}")
|
||||
}
|
||||
}
|
||||
|
||||
tasks {
|
||||
@@ -40,11 +57,7 @@ subprojects {
|
||||
|
||||
}
|
||||
|
||||
base {
|
||||
archivesName.set("ViaRewind")
|
||||
}
|
||||
|
||||
val shade = configureShadedDependencies(false) // Only shade, don't add them as dependency
|
||||
val shade = configureEmbeddedDependencies()
|
||||
|
||||
dependencies {
|
||||
subprojects.forEach {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: ViaRewind
|
||||
main: com.viaversion.viarewind.BukkitPlugin
|
||||
authors: [ FlorianMichael/EnZaXD, Gerrygames, creeper123123321 ]
|
||||
authors: [ EnZaXD, Gerrygames, creeper123123321 ]
|
||||
version: ${version}
|
||||
description: ${description}
|
||||
website: https://viaversion.com/rewind
|
||||
|
||||
+2
-16
@@ -1,29 +1,15 @@
|
||||
import de.florianmichael.baseproject.latestCommitHash
|
||||
|
||||
plugins {
|
||||
id("net.raphimc.class-token-replacer")
|
||||
}
|
||||
|
||||
val viaProxy: Configuration by configurations.creating
|
||||
|
||||
dependencies {
|
||||
compileOnly("io.netty:netty-all:4.0.20.Final")
|
||||
compileOnly("com.google.guava:guava:17.0")
|
||||
compileOnly("com.velocitypowered:velocity-native:3.4.0-SNAPSHOT")
|
||||
|
||||
viaProxy("net.raphimc:ViaProxy:3.4.6-SNAPSHOT") {
|
||||
viaProxy("net.raphimc:ViaProxy:[3.0.0,4.0.0)") {
|
||||
isTransitive = false
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets.configureEach {
|
||||
classTokenReplacer {
|
||||
replaceInPlace.set(true)
|
||||
|
||||
property("\${version}", project.version)
|
||||
property("\${impl_version}", "git-ViaRewind-${project.version}:${latestCommitHash()}")
|
||||
}
|
||||
}
|
||||
|
||||
// Task to quickly test/debug code changes using https://github.com/ViaVersion/ViaProxy
|
||||
// For further instructions see the ViaProxy repository README
|
||||
val prepareViaProxyFiles by tasks.registering(Copy::class) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.viaversion.viarewind;
|
||||
|
||||
import com.viaversion.viarewind.api.ViaRewindPlatform;
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import java.io.File;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class ViaRewindPlatformImpl implements ViaRewindPlatform {
|
||||
|
||||
private final Logger logger;
|
||||
|
||||
public ViaRewindPlatformImpl() {
|
||||
logger = Via.getPlatform().createLogger("ViaRewind");
|
||||
init(new File(getDataFolder(), "viarewind.yml"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Logger getLogger() {
|
||||
return logger;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getDataFolder() {
|
||||
return Via.getPlatform().getDataFolder();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -36,11 +36,14 @@ public interface ViaRewindPlatform {
|
||||
String VERSION = "${version}";
|
||||
String IMPL_VERSION = "${impl_version}";
|
||||
|
||||
default void init(final File configFile) {
|
||||
init(new ViaRewindConfig(configFile, getLogger()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize ViaRewind
|
||||
*/
|
||||
default void init(final File configFile) {
|
||||
ViaRewindConfig config = new ViaRewindConfig(configFile, getLogger());
|
||||
default void init(final com.viaversion.viarewind.api.ViaRewindConfig config) {
|
||||
config.reload();
|
||||
Via.getManager().getConfigurationProvider().register(config);
|
||||
|
||||
|
||||
+157
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.viaversion.viarewind.api.compression;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
|
||||
import java.util.zip.DataFormatException;
|
||||
import java.util.zip.Deflater;
|
||||
import java.util.zip.Inflater;
|
||||
|
||||
/**
|
||||
* A ThreadLocal-based compression provider that either uses Velocity's native compression
|
||||
* or falls back to Java's built-in compression (Deflater/Inflater).
|
||||
*/
|
||||
public final class ThreadLocalCompressionProvider {
|
||||
|
||||
private static final boolean VELOCITY_NATIVES_AVAILABLE;
|
||||
|
||||
static {
|
||||
boolean velocityAvailable = false;
|
||||
try {
|
||||
Class.forName("com.velocitypowered.natives.compression.VelocityCompressor");
|
||||
velocityAvailable = true;
|
||||
} catch (final ClassNotFoundException ignored) {
|
||||
}
|
||||
VELOCITY_NATIVES_AVAILABLE = velocityAvailable;
|
||||
}
|
||||
|
||||
// ThreadLocal for Java's Deflater (used when Velocity natives are not available)
|
||||
private static final ThreadLocal<Deflater> JAVA_DEFLATER = ThreadLocal.withInitial(Deflater::new);
|
||||
|
||||
// ThreadLocal for Java's Inflater (used when Velocity natives are not available)
|
||||
private static final ThreadLocal<Inflater> JAVA_INFLATER = ThreadLocal.withInitial(Inflater::new);
|
||||
|
||||
private ThreadLocalCompressionProvider() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Compresses data from the source buffer into the destination buffer.
|
||||
*
|
||||
* @param source the source buffer containing uncompressed data
|
||||
* @param destination the destination buffer to write compressed data to
|
||||
* @throws DataFormatException if compression fails
|
||||
*/
|
||||
public static void deflate(final ByteBuf source, final ByteBuf destination) throws DataFormatException {
|
||||
if (VELOCITY_NATIVES_AVAILABLE) {
|
||||
deflateVelocity(source, destination);
|
||||
} else {
|
||||
deflateJava(source, destination);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Decompresses data from the source buffer into the destination buffer.
|
||||
*
|
||||
* @param source the source buffer containing compressed data
|
||||
* @param destination the destination buffer to write decompressed data to
|
||||
* @param expectedSize the expected size of the decompressed data
|
||||
* @throws DataFormatException if decompression fails
|
||||
*/
|
||||
public static void inflate(final ByteBuf source, final ByteBuf destination, final int expectedSize) throws DataFormatException {
|
||||
if (VELOCITY_NATIVES_AVAILABLE) {
|
||||
inflateVelocity(source, destination, expectedSize);
|
||||
} else {
|
||||
inflateJava(source, destination, expectedSize);
|
||||
}
|
||||
}
|
||||
|
||||
// Java native implementation
|
||||
|
||||
private static void deflateJava(final ByteBuf source, final ByteBuf destination) throws DataFormatException {
|
||||
ByteBuf temp = source;
|
||||
if (!source.hasArray()) {
|
||||
temp = ByteBufAllocator.DEFAULT.heapBuffer().writeBytes(source);
|
||||
} else {
|
||||
source.retain();
|
||||
}
|
||||
ByteBuf output = ByteBufAllocator.DEFAULT.heapBuffer();
|
||||
try {
|
||||
final Deflater deflater = JAVA_DEFLATER.get();
|
||||
deflater.setInput(temp.array(), temp.arrayOffset() + temp.readerIndex(), temp.readableBytes());
|
||||
deflater.finish();
|
||||
|
||||
while (!deflater.finished()) {
|
||||
output.ensureWritable(4096);
|
||||
output.writerIndex(output.writerIndex() + deflater.deflate(output.array(), output.arrayOffset() + output.writerIndex(), output.writableBytes()));
|
||||
}
|
||||
destination.writeBytes(output);
|
||||
} finally {
|
||||
output.release();
|
||||
temp.release();
|
||||
JAVA_DEFLATER.get().reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void inflateJava(final ByteBuf source, final ByteBuf destination, final int expectedSize) throws DataFormatException {
|
||||
ByteBuf temp = source;
|
||||
if (!source.hasArray()) {
|
||||
temp = ByteBufAllocator.DEFAULT.heapBuffer().writeBytes(source);
|
||||
} else {
|
||||
source.retain();
|
||||
}
|
||||
ByteBuf output = ByteBufAllocator.DEFAULT.heapBuffer(expectedSize, expectedSize);
|
||||
try {
|
||||
final Inflater inflater = JAVA_INFLATER.get();
|
||||
inflater.setInput(temp.array(), temp.arrayOffset() + temp.readerIndex(), temp.readableBytes());
|
||||
output.writerIndex(output.writerIndex() + inflater.inflate(output.array(), output.arrayOffset(), expectedSize));
|
||||
destination.writeBytes(output);
|
||||
} finally {
|
||||
output.release();
|
||||
temp.release();
|
||||
JAVA_INFLATER.get().reset();
|
||||
}
|
||||
}
|
||||
|
||||
// Velocity native implementation
|
||||
private static void deflateVelocity(final ByteBuf source, final ByteBuf destination) throws DataFormatException {
|
||||
VelocityHolder.deflate(source, destination);
|
||||
}
|
||||
|
||||
private static void inflateVelocity(final ByteBuf source, final ByteBuf destination, final int expectedSize) throws DataFormatException {
|
||||
VelocityHolder.inflate(source, destination, expectedSize);
|
||||
}
|
||||
|
||||
private static final class VelocityHolder {
|
||||
|
||||
private static final ThreadLocal<com.velocitypowered.natives.compression.VelocityCompressor> COMPRESSOR =
|
||||
ThreadLocal.withInitial(() -> com.velocitypowered.natives.util.Natives.compress.get().create(-1));
|
||||
|
||||
static void deflate(final ByteBuf source, final ByteBuf destination) throws DataFormatException {
|
||||
COMPRESSOR.get().deflate(source, destination);
|
||||
}
|
||||
|
||||
static void inflate(final ByteBuf source, final ByteBuf destination, final int expectedSize) throws DataFormatException {
|
||||
COMPRESSOR.get().inflate(source, destination, expectedSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -20,6 +20,10 @@ package com.viaversion.viarewind.api.data;
|
||||
import com.viaversion.nbt.tag.CompoundTag;
|
||||
import com.viaversion.viabackwards.api.data.BackwardsMappingData;
|
||||
import com.viaversion.viarewind.ViaRewind;
|
||||
import com.viaversion.viaversion.api.data.FullMappings;
|
||||
import com.viaversion.viaversion.api.data.LegacyFullStringMappingsBase;
|
||||
import com.viaversion.viaversion.api.data.MappingDataLoader;
|
||||
import com.viaversion.viaversion.api.data.Mappings;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class RewindMappingData extends BackwardsMappingData {
|
||||
@@ -37,4 +41,9 @@ public class RewindMappingData extends BackwardsMappingData {
|
||||
protected CompoundTag readMappingsFile(String name) {
|
||||
return RewindMappingDataLoader.INSTANCE.loadNBTFromDir(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FullMappings createFullMappings(MappingDataLoader.IdentifiersPair identifiersPair, Mappings mappings) {
|
||||
return new LegacyFullStringMappingsBase(identifiersPair, mappings);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-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.viarewind.api.minecraft;
|
||||
|
||||
import com.viaversion.viaversion.api.minecraft.chunks.ChunkSection;
|
||||
import com.viaversion.viaversion.api.minecraft.chunks.NibbleArray;
|
||||
|
||||
public class ExtendedBlockStorage {
|
||||
private final byte[] blockLSBArray = new byte[ChunkSection.SIZE];
|
||||
|
||||
private final NibbleArray blockMetadataArray = new NibbleArray(this.blockLSBArray.length);
|
||||
private final NibbleArray blockLightArray = new NibbleArray(this.blockLSBArray.length);
|
||||
|
||||
private NibbleArray blockMSBArray;
|
||||
private NibbleArray skyLightArray;
|
||||
|
||||
public ExtendedBlockStorage(final boolean skylight) {
|
||||
if (skylight) {
|
||||
this.skyLightArray = new NibbleArray(this.blockLSBArray.length);
|
||||
}
|
||||
}
|
||||
|
||||
public void setBlockId(final int x, final int y, final int z, final int value) {
|
||||
this.blockLSBArray[ChunkSection.index(x, y, z)] = (byte) (value & 255);
|
||||
if (value > 255) {
|
||||
this.getOrCreateBlockMSBArray().set(x, y, z, (value & 0xF00) >> 8);
|
||||
} else if (this.blockMSBArray != null) {
|
||||
this.blockMSBArray.set(x, y, z, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public void setBlockMetadata(final int x, final int y, final int z, final int value) {
|
||||
this.blockMetadataArray.set(x, y, z, value);
|
||||
}
|
||||
|
||||
public boolean hasBlockMSBArray() {
|
||||
return this.blockMSBArray != null;
|
||||
}
|
||||
|
||||
public byte[] getBlockLSBArray() {
|
||||
return this.blockLSBArray;
|
||||
}
|
||||
|
||||
public NibbleArray getOrCreateBlockMSBArray() {
|
||||
if (this.blockMSBArray == null) {
|
||||
return this.blockMSBArray = new NibbleArray(this.blockLSBArray.length);
|
||||
}
|
||||
return this.blockMSBArray;
|
||||
}
|
||||
|
||||
public NibbleArray getBlockMetadataArray() {
|
||||
return this.blockMetadataArray;
|
||||
}
|
||||
|
||||
public NibbleArray getBlockLightArray() {
|
||||
return this.blockLightArray;
|
||||
}
|
||||
|
||||
public NibbleArray getSkyLightArray() {
|
||||
return this.skyLightArray;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+2
-6
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -17,17 +17,13 @@
|
||||
*/
|
||||
package com.viaversion.viarewind.api.minecraft.math;
|
||||
|
||||
import com.viaversion.viarewind.protocol.v1_9to1_8.Protocol1_9To1_8;
|
||||
import com.viaversion.viarewind.protocol.v1_9to1_8.storage.EntityTracker1_9;
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.api.minecraft.Vector;
|
||||
|
||||
@Deprecated // ?????????
|
||||
public class RelativeMoveUtil {
|
||||
|
||||
public static Vector[] calculateRelativeMoves(UserConnection user, int entityId, int relX, int relY, int relZ) {
|
||||
EntityTracker1_9 tracker = user.getEntityTracker(Protocol1_9To1_8.class);
|
||||
|
||||
public static Vector[] calculateRelativeMoves(EntityTracker1_9 tracker, int entityId, int relX, int relY, int relZ) {
|
||||
int x;
|
||||
int y;
|
||||
int z;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -28,7 +28,6 @@ import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
|
||||
import com.viaversion.viaversion.api.minecraft.item.Item;
|
||||
import com.viaversion.viaversion.api.type.Type;
|
||||
import com.viaversion.viaversion.api.type.Types;
|
||||
import com.viaversion.viaversion.libs.gson.JsonElement;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -36,7 +35,6 @@ import java.util.List;
|
||||
*/
|
||||
public class RewindTypes {
|
||||
|
||||
public static final Type<JsonElement> SIGN_COMPONENT = new SignComponentType();
|
||||
public static final Type<int[]> INT_ARRAY = new IntArrayType(); // Integer array with byte as length indicator
|
||||
|
||||
public static final Type<BlockPosition> SHORT_POSITION = new PositionVarYType<>(Types.SHORT, value -> (short) value);
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-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.viarewind.api.type;
|
||||
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.api.type.Type;
|
||||
import com.viaversion.viaversion.api.type.types.ComponentType;
|
||||
import com.viaversion.viaversion.api.type.types.StringType;
|
||||
import com.viaversion.viaversion.libs.gson.JsonElement;
|
||||
import com.viaversion.viaversion.libs.gson.JsonParser;
|
||||
import com.viaversion.viaversion.libs.gson.JsonSyntaxException;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
public class SignComponentType extends ComponentType {
|
||||
|
||||
public static final Type<String> STRING = new StringType(384);
|
||||
|
||||
@Override
|
||||
public JsonElement read(final ByteBuf buffer) {
|
||||
final String string = STRING.read(buffer);
|
||||
try {
|
||||
return JsonParser.parseString(string);
|
||||
} catch (final JsonSyntaxException e) {
|
||||
if (Via.getManager().isDebug()) {
|
||||
Via.getPlatform().getLogger().severe("Error when trying to parse json: " + string);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(final ByteBuf buffer, final JsonElement value) {
|
||||
STRING.write(buffer, value.toString());
|
||||
}
|
||||
|
||||
}
|
||||
+71
-63
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -17,12 +17,13 @@
|
||||
*/
|
||||
package com.viaversion.viarewind.api.type.chunk;
|
||||
|
||||
import com.viaversion.viarewind.api.compression.ThreadLocalCompressionProvider;
|
||||
import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
|
||||
import com.viaversion.viaversion.api.minecraft.chunks.ChunkSection;
|
||||
import com.viaversion.viaversion.api.type.Type;
|
||||
import com.viaversion.viaversion.util.Pair;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.util.zip.Deflater;
|
||||
|
||||
import java.util.zip.DataFormatException;
|
||||
|
||||
|
||||
public class BulkChunkType1_7_6 extends Type<Chunk[]> {
|
||||
|
||||
@@ -38,73 +39,80 @@ public class BulkChunkType1_7_6 extends Type<Chunk[]> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuf byteBuf, Chunk[] chunks) {
|
||||
public void write(ByteBuf buffer, Chunk[] chunks) {
|
||||
final int chunkCount = chunks.length;
|
||||
final int[] chunkX = new int[chunkCount];
|
||||
final int[] chunkZ = new int[chunkCount];
|
||||
final short[] primaryBitMask = new short[chunkCount];
|
||||
final short[] additionalBitMask = new short[chunkCount];
|
||||
final int[] addBitMasks = new int[chunkCount];
|
||||
int totalSize = 0;
|
||||
boolean anySkyLight = false;
|
||||
|
||||
final byte[][] dataArrays = new byte[chunkCount][];
|
||||
int dataSize = 0;
|
||||
|
||||
for (int i = 0; i < chunkCount; i++) {
|
||||
final Chunk chunk = chunks[i];
|
||||
Pair<byte[], Short> chunkData;
|
||||
try {
|
||||
chunkData = ChunkType1_7_6.serialize(chunk);
|
||||
final byte[] data = chunkData.key();
|
||||
dataArrays[i] = data;
|
||||
dataSize += data.length;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Unable to serialize chunk", e);
|
||||
}
|
||||
chunkX[i] = chunk.getX();
|
||||
chunkZ[i] = chunk.getZ();
|
||||
primaryBitMask[i] = (short) chunk.getBitmask();
|
||||
additionalBitMask[i] = chunkData.value();
|
||||
}
|
||||
|
||||
final byte[] data = new byte[dataSize];
|
||||
int destPos = 0;
|
||||
for (final byte[] array : dataArrays) {
|
||||
System.arraycopy(array, 0, data, destPos, array.length);
|
||||
destPos += array.length;
|
||||
}
|
||||
|
||||
final Deflater deflater = new Deflater();
|
||||
byte[] compressedData;
|
||||
int compressedSize;
|
||||
try {
|
||||
deflater.setInput(data, 0, data.length);
|
||||
deflater.finish();
|
||||
compressedData = new byte[data.length];
|
||||
compressedSize = deflater.deflate(compressedData);
|
||||
} finally {
|
||||
deflater.end();
|
||||
}
|
||||
|
||||
byteBuf.writeShort(chunkCount);
|
||||
byteBuf.writeInt(compressedSize);
|
||||
|
||||
boolean skyLight = false;
|
||||
for (Chunk chunk : chunks) {
|
||||
for (ChunkSection section : chunk.getSections()) {
|
||||
if (section != null && section.getLight().hasSkyLight()) {
|
||||
skyLight = true;
|
||||
break;
|
||||
}
|
||||
if (ChunkType1_7_6.hasSkyLight(chunk)) {
|
||||
anySkyLight = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
byteBuf.writeBoolean(skyLight); // hasSkyLight
|
||||
byteBuf.writeBytes(compressedData, 0, compressedSize);
|
||||
for (int i = 0; i < chunkCount; i++) {
|
||||
Chunk chunk = chunks[i];
|
||||
addBitMasks[i] = ChunkType1_7_6.getAddBitMask(chunk);
|
||||
boolean biomes = chunk.isFullChunk() && chunk.getBiomeData() != null;
|
||||
|
||||
totalSize += ChunkType1_7_6.calcSize(
|
||||
chunk.getBitmask(),
|
||||
addBitMasks[i],
|
||||
anySkyLight,
|
||||
biomes
|
||||
);
|
||||
}
|
||||
|
||||
final ByteBuf uncompressed = buffer.alloc().buffer(totalSize);
|
||||
|
||||
try {
|
||||
for (int i = 0; i < chunkCount; i++) {
|
||||
Chunk chunk = chunks[i];
|
||||
boolean biomes = chunk.isFullChunk() && chunk.getBiomeData() != null;
|
||||
|
||||
ChunkType1_7_6.serialize(
|
||||
chunk,
|
||||
uncompressed,
|
||||
addBitMasks[i],
|
||||
anySkyLight,
|
||||
biomes
|
||||
);
|
||||
}
|
||||
|
||||
buffer.writeShort(chunkCount);
|
||||
|
||||
// Reserve 4 bytes for the compressed size
|
||||
final int sizeIndex = buffer.writerIndex();
|
||||
buffer.writeInt(0); // Placeholder for compressed size
|
||||
|
||||
buffer.writeBoolean(anySkyLight);
|
||||
|
||||
// Write compressed data directly to output buffer
|
||||
final int compressedStart = buffer.writerIndex();
|
||||
try {
|
||||
ThreadLocalCompressionProvider.deflate(uncompressed, buffer);
|
||||
} catch (DataFormatException e) {
|
||||
throw new RuntimeException("Failed to compress bulk chunk data", e);
|
||||
}
|
||||
final int compressedSize = buffer.writerIndex() - compressedStart;
|
||||
|
||||
// Go back and write the compressed size
|
||||
final int endIndex = buffer.writerIndex();
|
||||
buffer.writerIndex(sizeIndex);
|
||||
buffer.writeInt(compressedSize);
|
||||
buffer.writerIndex(endIndex);
|
||||
} finally {
|
||||
uncompressed.release();
|
||||
}
|
||||
|
||||
for (int i = 0; i < chunkCount; i++) {
|
||||
byteBuf.writeInt(chunkX[i]);
|
||||
byteBuf.writeInt(chunkZ[i]);
|
||||
byteBuf.writeShort(primaryBitMask[i]);
|
||||
byteBuf.writeShort(additionalBitMask[i]);
|
||||
Chunk chunk = chunks[i];
|
||||
buffer.writeInt(chunk.getX());
|
||||
buffer.writeInt(chunk.getZ());
|
||||
buffer.writeShort(chunk.getBitmask());
|
||||
buffer.writeShort(addBitMasks[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
+159
-132
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -17,15 +17,15 @@
|
||||
*/
|
||||
package com.viaversion.viarewind.api.type.chunk;
|
||||
|
||||
import com.viaversion.viarewind.api.minecraft.ExtendedBlockStorage;
|
||||
import com.viaversion.viarewind.api.compression.ThreadLocalCompressionProvider;
|
||||
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.type.Type;
|
||||
import com.viaversion.viaversion.util.Pair;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.io.IOException;
|
||||
import java.util.zip.Deflater;
|
||||
|
||||
import java.util.zip.DataFormatException;
|
||||
|
||||
import static com.viaversion.viaversion.api.minecraft.chunks.ChunkSection.SIZE;
|
||||
import static com.viaversion.viaversion.api.minecraft.chunks.ChunkSectionLight.LIGHT_LENGTH;
|
||||
@@ -38,143 +38,170 @@ public class ChunkType1_7_6 extends Type<Chunk> {
|
||||
super(Chunk.class);
|
||||
}
|
||||
|
||||
public static Pair<byte[], Short> serialize(final Chunk chunk) throws IOException {
|
||||
final ExtendedBlockStorage[] storageArrays = new ExtendedBlockStorage[16];
|
||||
for (int i = 0; i < storageArrays.length; i++) {
|
||||
final ChunkSection section = chunk.getSections()[i];
|
||||
if (section != null) {
|
||||
final ExtendedBlockStorage storage = storageArrays[i] = new ExtendedBlockStorage(section.getLight().hasSkyLight());
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int y = 0; y < 16; y++) {
|
||||
final int flatBlock = section.palette(PaletteType.BLOCKS).idAt(x, y, z);
|
||||
storage.setBlockId(x, y, z, flatBlock >> 4);
|
||||
storage.setBlockMetadata(x, y, z, flatBlock & 15);
|
||||
}
|
||||
}
|
||||
}
|
||||
storage.getBlockLightArray().setHandle(section.getLight().getBlockLight());
|
||||
if (section.getLight().hasSkyLight()) {
|
||||
storage.getSkyLightArray().setHandle(section.getLight().getSkyLight());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final boolean biomes = chunk.isFullChunk() && chunk.getBiomeData() != null;
|
||||
final int totalSize = calculateSize(storageArrays, chunk.getBitmask(), biomes);
|
||||
|
||||
final byte[] output = new byte[totalSize];
|
||||
int index = 0;
|
||||
|
||||
for (int i = 0; i < storageArrays.length; i++) {
|
||||
if ((chunk.getBitmask() & 1 << i) != 0) {
|
||||
final byte[] blockLSBArray = storageArrays[i].getBlockLSBArray();
|
||||
System.arraycopy(blockLSBArray, 0, output, index, blockLSBArray.length);
|
||||
index += blockLSBArray.length;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < storageArrays.length; i++) {
|
||||
if ((chunk.getBitmask() & 1 << i) != 0) {
|
||||
final byte[] blockMetadataArray = storageArrays[i].getBlockMetadataArray().getHandle();
|
||||
System.arraycopy(blockMetadataArray, 0, output, index, blockMetadataArray.length);
|
||||
index += blockMetadataArray.length;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < storageArrays.length; i++) {
|
||||
if ((chunk.getBitmask() & 1 << i) != 0) {
|
||||
final byte[] blockLightArray = storageArrays[i].getBlockLightArray().getHandle();
|
||||
System.arraycopy(blockLightArray, 0, output, index, blockLightArray.length);
|
||||
index += blockLightArray.length;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < storageArrays.length; i++) {
|
||||
if ((chunk.getBitmask() & 1 << i) != 0 && storageArrays[i].getSkyLightArray() != null) {
|
||||
final byte[] skyLightArray = storageArrays[i].getSkyLightArray().getHandle();
|
||||
System.arraycopy(skyLightArray, 0, output, index, skyLightArray.length);
|
||||
index += skyLightArray.length;
|
||||
}
|
||||
}
|
||||
|
||||
short additionalBitMask = 0;
|
||||
for (int i = 0; i < storageArrays.length; i++) {
|
||||
if ((chunk.getBitmask() & 1 << i) != 0 && storageArrays[i].hasBlockMSBArray()) {
|
||||
additionalBitMask |= (short) (1 << i);
|
||||
final byte[] blockMSBArray = storageArrays[i].getOrCreateBlockMSBArray().getHandle();
|
||||
System.arraycopy(blockMSBArray, 0, output, index, blockMSBArray.length);
|
||||
index += blockMSBArray.length;
|
||||
}
|
||||
}
|
||||
|
||||
if (biomes) {
|
||||
for (int biome : chunk.getBiomeData()) {
|
||||
output[index++] = (byte) biome;
|
||||
}
|
||||
}
|
||||
|
||||
return new Pair<>(output, additionalBitMask);
|
||||
}
|
||||
|
||||
private static int calculateSize(final ExtendedBlockStorage[] storageArrays, final int bitmask, final boolean biomes) {
|
||||
int totalSize = 0;
|
||||
for (int i = 0; i < storageArrays.length; i++) {
|
||||
if ((bitmask & 1 << i) != 0) {
|
||||
totalSize += SIZE; // Block lsb array
|
||||
totalSize += SIZE / 2; // Block metadata array
|
||||
totalSize += LIGHT_LENGTH; // Block light array
|
||||
|
||||
if (storageArrays[i].getSkyLightArray() != null) {
|
||||
totalSize += LIGHT_LENGTH;
|
||||
}
|
||||
|
||||
if (storageArrays[i].hasBlockMSBArray()) {
|
||||
totalSize += SIZE / 2; // Block msb array
|
||||
}
|
||||
}
|
||||
}
|
||||
if (biomes) {
|
||||
totalSize += 256;
|
||||
}
|
||||
return totalSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Chunk read(ByteBuf byteBuf) {
|
||||
throw new UnsupportedOperationException(); // Not needed, see https://github.com/ViaVersion/ViaLegacy/blob/main/src/main/java/net/raphimc/vialegacy/protocols/release/protocol1_8to1_7_6_10/types/Chunk1_7_6Type.java
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuf output, Chunk chunk) {
|
||||
Pair<byte[], Short> chunkData;
|
||||
try {
|
||||
chunkData = serialize(chunk);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Unable to serialize chunk", e);
|
||||
}
|
||||
final byte[] data = chunkData.key();
|
||||
final short additionalBitMask = chunkData.value();
|
||||
public void write(ByteBuf buffer, Chunk chunk) {
|
||||
final int bitmask = chunk.getBitmask();
|
||||
final int addBitmask = getAddBitMask(chunk);
|
||||
final boolean hasSkyLight = hasSkyLight(chunk);
|
||||
final boolean biomes = chunk.isFullChunk() && chunk.getBiomeData() != null;
|
||||
|
||||
final int size = calcSize(bitmask, addBitmask, hasSkyLight, biomes);
|
||||
final ByteBuf uncompressed = buffer.alloc().buffer(size);
|
||||
|
||||
final Deflater deflater = new Deflater();
|
||||
byte[] compressedData;
|
||||
int compressedSize;
|
||||
try {
|
||||
deflater.setInput(data, 0, data.length);
|
||||
deflater.finish();
|
||||
compressedData = new byte[data.length];
|
||||
compressedSize = deflater.deflate(compressedData);
|
||||
serialize(chunk, uncompressed, addBitmask, hasSkyLight, biomes);
|
||||
|
||||
buffer.writeInt(chunk.getX());
|
||||
buffer.writeInt(chunk.getZ());
|
||||
buffer.writeBoolean(chunk.isFullChunk());
|
||||
buffer.writeShort(bitmask);
|
||||
buffer.writeShort(addBitmask);
|
||||
|
||||
// Reserve 4 bytes for the compressed size
|
||||
final int sizeIndex = buffer.writerIndex();
|
||||
buffer.writeInt(0); // Placeholder for compressed size
|
||||
|
||||
// Write compressed data directly to output buffer
|
||||
final int compressedStart = buffer.writerIndex();
|
||||
try {
|
||||
ThreadLocalCompressionProvider.deflate(uncompressed, buffer);
|
||||
} catch (DataFormatException e) {
|
||||
throw new RuntimeException("Failed to compress chunk data", e);
|
||||
}
|
||||
final int compressedSize = buffer.writerIndex() - compressedStart;
|
||||
|
||||
// Go back and write the compressed size
|
||||
final int endIndex = buffer.writerIndex();
|
||||
buffer.writerIndex(sizeIndex);
|
||||
buffer.writeInt(compressedSize);
|
||||
buffer.writerIndex(endIndex);
|
||||
} finally {
|
||||
deflater.end();
|
||||
uncompressed.release();
|
||||
}
|
||||
|
||||
output.writeInt(chunk.getX());
|
||||
output.writeInt(chunk.getZ());
|
||||
output.writeBoolean(chunk.isFullChunk());
|
||||
output.writeShort(chunk.getBitmask());
|
||||
output.writeShort(additionalBitMask);
|
||||
output.writeInt(compressedSize);
|
||||
output.writeBytes(compressedData, 0, compressedSize);
|
||||
}
|
||||
|
||||
public static void serialize(Chunk chunk, ByteBuf output, int addBitmask, boolean writeSkyLight, boolean biomes) {
|
||||
final ChunkSection[] sections = chunk.getSections();
|
||||
final int bitmask = chunk.getBitmask();
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if ((bitmask & (1 << i)) != 0) {
|
||||
final ChunkSection section = sections[i];
|
||||
final DataPalette palette = section.palette(PaletteType.BLOCKS);
|
||||
for (int j = 0; j < SIZE; j++) {
|
||||
final int block = palette.idAt(j);
|
||||
output.writeByte((block >> 4) & 0xFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if ((bitmask & (1 << i)) != 0) {
|
||||
final ChunkSection section = sections[i];
|
||||
final DataPalette palette = section.palette(PaletteType.BLOCKS);
|
||||
for (int j = 0; j < ChunkSection.SIZE; j += 2) {
|
||||
final int meta1 = palette.idAt(j) & 0xF;
|
||||
final int meta2 = palette.idAt(j + 1) & 0xF;
|
||||
output.writeByte(meta1 | (meta2 << 4));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if ((bitmask & (1 << i)) != 0) {
|
||||
final byte[] blockLight = sections[i].getLight().getBlockLight();
|
||||
output.writeBytes(blockLight);
|
||||
}
|
||||
}
|
||||
|
||||
if (writeSkyLight) {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if ((bitmask & (1 << i)) != 0) {
|
||||
if (sections[i].getLight().hasSkyLight()) {
|
||||
final byte[] skyLight = sections[i].getLight().getSkyLight();
|
||||
output.writeBytes(skyLight);
|
||||
} else {
|
||||
// Write empty skylight data
|
||||
output.writeZero(LIGHT_LENGTH);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (addBitmask != 0) {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if ((bitmask & (1 << i)) != 0 && (addBitmask & (1 << i)) != 0) {
|
||||
final ChunkSection section = sections[i];
|
||||
final DataPalette palette = section.palette(PaletteType.BLOCKS);
|
||||
for (int j = 0; j < SIZE; j += 2) {
|
||||
final int add1 = (palette.idAt(j) >> 12) & 0xF;
|
||||
final int add2 = (palette.idAt(j + 1) >> 12) & 0xF;
|
||||
output.writeByte(add1 | (add2 << 4));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (biomes && chunk.getBiomeData() != null) {
|
||||
final int[] biomeData = chunk.getBiomeData();
|
||||
for (int biome : biomeData) {
|
||||
output.writeByte(biome);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int calcSize(int bitmask, int addBitmask, boolean hasSkyLight, boolean biomes) {
|
||||
int size = 0;
|
||||
int sections = Integer.bitCount(bitmask);
|
||||
|
||||
size += sections * SIZE;
|
||||
size += sections * (SIZE / 2);
|
||||
size += sections * LIGHT_LENGTH;
|
||||
|
||||
if (hasSkyLight) {
|
||||
size += sections * LIGHT_LENGTH;
|
||||
}
|
||||
|
||||
if (addBitmask != 0) {
|
||||
size += Integer.bitCount(addBitmask) * (SIZE / 2);
|
||||
}
|
||||
|
||||
if (biomes) {
|
||||
size += 256;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
public static int getAddBitMask(Chunk chunk) {
|
||||
int addBitMask = 0;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if ((chunk.getBitmask() & (1 << i)) != 0) {
|
||||
final ChunkSection section = chunk.getSections()[i];
|
||||
final DataPalette palette = section.palette(PaletteType.BLOCKS);
|
||||
for (int j = 0; j < SIZE; j++) {
|
||||
final int id = palette.idAt(j);
|
||||
if ((id >> 12) != 0) {
|
||||
addBitMask |= (1 << i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return addBitMask;
|
||||
}
|
||||
|
||||
public static boolean hasSkyLight(Chunk chunk) {
|
||||
for (ChunkSection section : chunk.getSections()) {
|
||||
if (section != null && section.getLight().hasSkyLight()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+5
-3
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -38,6 +38,7 @@ import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.storage.ScoreboardTracke
|
||||
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.storage.WorldBorderEmulator;
|
||||
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.task.WorldBorderUpdateTask;
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.api.connection.ProtocolStorables;
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.api.minecraft.ClientWorld;
|
||||
import com.viaversion.viaversion.api.platform.providers.ViaProviders;
|
||||
@@ -122,8 +123,9 @@ public class Protocol1_8To1_7_6_10 extends BackwardsProtocol<ClientboundPackets1
|
||||
|
||||
@Override
|
||||
public void init(UserConnection connection) {
|
||||
connection.addEntityTracker(this.getClass(), new EntityTracker1_8(connection));
|
||||
connection.addClientWorld(this.getClass(), new ClientWorld());
|
||||
final ProtocolStorables storables = connection.storables(this);
|
||||
storables.setEntityTracker(new EntityTracker1_8(connection));
|
||||
storables.setClientWorld(new ClientWorld());
|
||||
|
||||
connection.put(new InventoryTracker(connection));
|
||||
connection.put(new PlayerSessionStorage(connection));
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+234
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.viaversion.viarewind.protocol.v1_8to1_7_6_10.data;
|
||||
|
||||
import com.viaversion.viaversion.libs.gson.JsonArray;
|
||||
import com.viaversion.viaversion.libs.gson.JsonElement;
|
||||
import com.viaversion.viaversion.libs.gson.JsonObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ChatNewlineRewriter {
|
||||
private static final String[] STYLE_KEYS = {
|
||||
"color",
|
||||
"bold",
|
||||
"italic",
|
||||
"underlined",
|
||||
"strikethrough",
|
||||
"obfuscated",
|
||||
"clickEvent",
|
||||
"hoverEvent",
|
||||
"insertion"
|
||||
};
|
||||
|
||||
public static List<JsonObject> splitChatComponentByNewline(JsonElement element) {
|
||||
return splitChatComponentByNewline(element, new JsonObject());
|
||||
}
|
||||
|
||||
private static List<JsonObject> splitChatComponentByNewline(JsonElement element, JsonObject inheritedStyle) {
|
||||
List<JsonObject> results = new ArrayList<>();
|
||||
if (element == null || element.isJsonNull()) {
|
||||
return results;
|
||||
}
|
||||
|
||||
if (element.isJsonPrimitive()) {
|
||||
String text = element.getAsString();
|
||||
for (String part : text.split("\n", -1)) {
|
||||
JsonObject obj = inheritedStyle.deepCopy();
|
||||
obj.addProperty("text", part);
|
||||
results.add(obj);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
if (element.isJsonArray()) {
|
||||
List<JsonObject> currentLine = new ArrayList<>();
|
||||
JsonObject siblingStyle = inheritedStyle;
|
||||
boolean foundRoot = false;
|
||||
|
||||
for (JsonElement child : element.getAsJsonArray()) {
|
||||
List<JsonObject> splitParts = splitChatComponentByNewline(child, siblingStyle);
|
||||
for (int i = 0; i < splitParts.size(); i++) {
|
||||
currentLine.add(splitParts.get(i));
|
||||
if (i < splitParts.size() - 1) {
|
||||
results.add(mergeLine(currentLine));
|
||||
currentLine.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundRoot && child != null && !child.isJsonNull()) {
|
||||
siblingStyle = rootStyle(inheritedStyle, child);
|
||||
foundRoot = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!currentLine.isEmpty()) {
|
||||
results.add(mergeLine(currentLine));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
if (!element.isJsonObject()) {
|
||||
return results;
|
||||
}
|
||||
|
||||
JsonObject obj = element.getAsJsonObject();
|
||||
|
||||
// Build the style for this node: inherit first, then override with this object's style
|
||||
JsonObject currentStyle = mergeStyle(inheritedStyle, obj);
|
||||
|
||||
// Gather components in order: base text then extra array
|
||||
List<JsonElement> ordered = new ArrayList<>();
|
||||
if (obj.has("text")) {
|
||||
ordered.add(obj.get("text"));
|
||||
}
|
||||
if (obj.has("extra") && obj.get("extra").isJsonArray()) {
|
||||
for (JsonElement extra : obj.getAsJsonArray("extra")) {
|
||||
ordered.add(extra);
|
||||
}
|
||||
}
|
||||
|
||||
// If there is no text/extra, return a single object with the style
|
||||
if (ordered.isEmpty()) {
|
||||
JsonObject baseComponent = copyComponentWithoutExtra(obj, currentStyle);
|
||||
results.add(baseComponent != null ? baseComponent : currentStyle);
|
||||
return results;
|
||||
}
|
||||
|
||||
// Build lines by concatenating split pieces
|
||||
List<JsonObject> currentLine = new ArrayList<>();
|
||||
if (!obj.has("text")) {
|
||||
JsonObject baseComponent = copyComponentWithoutExtra(obj, currentStyle);
|
||||
if (baseComponent != null) {
|
||||
currentLine.add(baseComponent);
|
||||
}
|
||||
}
|
||||
for (JsonElement part : ordered) {
|
||||
if (part == null || part.isJsonNull()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (part.isJsonPrimitive()) {
|
||||
String text = part.getAsString();
|
||||
String[] split = text.split("\n", -1);
|
||||
for (int i = 0; i < split.length; i++) {
|
||||
JsonObject piece = currentStyle.deepCopy();
|
||||
piece.addProperty("text", split[i]);
|
||||
currentLine.add(piece);
|
||||
|
||||
if (i < split.length - 1) {
|
||||
results.add(mergeLine(currentLine));
|
||||
currentLine.clear();
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (part.isJsonObject() || part.isJsonArray()) {
|
||||
List<JsonObject> splitParts = splitChatComponentByNewline(part, currentStyle);
|
||||
for (int i = 0; i < splitParts.size(); i++) {
|
||||
currentLine.add(splitParts.get(i));
|
||||
if (i < splitParts.size() - 1) {
|
||||
results.add(mergeLine(currentLine));
|
||||
currentLine.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!currentLine.isEmpty()) {
|
||||
results.add(mergeLine(currentLine));
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
private static JsonObject rootStyle(JsonObject inheritedStyle, JsonElement element) {
|
||||
if (element == null || element.isJsonNull()) {
|
||||
return inheritedStyle;
|
||||
}
|
||||
if (element.isJsonObject()) {
|
||||
return mergeStyle(inheritedStyle, element.getAsJsonObject());
|
||||
}
|
||||
if (element.isJsonArray()) {
|
||||
for (JsonElement child : element.getAsJsonArray()) {
|
||||
if (child != null && !child.isJsonNull()) {
|
||||
return rootStyle(inheritedStyle, child);
|
||||
}
|
||||
}
|
||||
}
|
||||
return inheritedStyle;
|
||||
}
|
||||
|
||||
private static JsonObject mergeStyle(JsonObject inheritedStyle, JsonObject obj) {
|
||||
JsonObject currentStyle = inheritedStyle.deepCopy();
|
||||
for (String key : STYLE_KEYS) {
|
||||
if (obj.has(key)) {
|
||||
currentStyle.add(key, obj.get(key).deepCopy());
|
||||
}
|
||||
}
|
||||
return currentStyle;
|
||||
}
|
||||
|
||||
private static JsonObject copyComponentWithoutExtra(JsonObject obj, JsonObject currentStyle) {
|
||||
JsonObject component = currentStyle.deepCopy();
|
||||
for (Map.Entry<String, JsonElement> entry : obj.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
if ("extra".equals(key) || isStyleKey(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
component.add(key, entry.getValue().deepCopy());
|
||||
}
|
||||
return component.size() == currentStyle.size() ? null : component;
|
||||
}
|
||||
|
||||
private static boolean isStyleKey(String key) {
|
||||
for (String styleKey : STYLE_KEYS) {
|
||||
if (styleKey.equals(key)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static JsonObject mergeLine(List<JsonObject> lineParts) {
|
||||
if (lineParts.isEmpty()) {
|
||||
JsonObject empty = new JsonObject();
|
||||
empty.addProperty("text", "");
|
||||
return empty;
|
||||
}
|
||||
|
||||
JsonObject first = lineParts.get(0);
|
||||
if (lineParts.size() == 1) {
|
||||
return first;
|
||||
}
|
||||
|
||||
JsonObject merged = new JsonObject();
|
||||
merged.addProperty("text", "");
|
||||
|
||||
JsonArray extra = new JsonArray();
|
||||
for (JsonObject linePart : lineParts) {
|
||||
extra.add(linePart);
|
||||
}
|
||||
merged.add("extra", extra);
|
||||
return merged;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+31
-4
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -24,6 +24,7 @@ import com.viaversion.viarewind.api.type.RewindTypes;
|
||||
import com.viaversion.viarewind.protocol.v1_7_6_10to1_7_2_5.packet.ClientboundPackets1_7_2_5;
|
||||
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.Protocol1_8To1_7_6_10;
|
||||
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.rewriter.EntityPacketRewriter1_8;
|
||||
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.storage.EntityTracker1_8;
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8;
|
||||
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
|
||||
@@ -46,6 +47,8 @@ public class VirtualHologramEntity {
|
||||
private String name = null;
|
||||
private float yaw, pitch;
|
||||
private float headYaw;
|
||||
private byte flags = 0;
|
||||
private byte armorStandFlags = 0;
|
||||
private boolean small = false;
|
||||
private boolean marker = false;
|
||||
private boolean sneaking = false;
|
||||
@@ -99,8 +102,6 @@ public class VirtualHologramEntity {
|
||||
}
|
||||
|
||||
// Filter armor stand data to calculate emulation
|
||||
byte flags = 0;
|
||||
byte armorStandFlags = 0;
|
||||
for (EntityData entityData : entityDataTracker) {
|
||||
if (entityData.id() == 0 && entityData.dataType() == EntityDataTypes1_8.BYTE) {
|
||||
flags = ((Number) entityData.getValue()).byteValue();
|
||||
@@ -120,7 +121,7 @@ public class VirtualHologramEntity {
|
||||
gravity = (armorStandFlags & 0x02) == 0;
|
||||
|
||||
State prevState = currentState;
|
||||
if (invisible && name != null) {
|
||||
if (invisible && name != null && alwaysShowNametag == 1) {
|
||||
currentState = State.HOLOGRAM;
|
||||
} else if (gravity) {
|
||||
currentState = State.ZOMBIE;
|
||||
@@ -167,6 +168,18 @@ public class VirtualHologramEntity {
|
||||
} else {
|
||||
return baseOffset + (0.9875 * 2);
|
||||
}
|
||||
} else if (currentState == State.ZOMBIE_NO_GRAVITY) {
|
||||
// 1.7 ride stack offset sum: Squid (0.95 * 0.75) + Zombie (1.8 * 0.75) = 2.0625
|
||||
// By starting at -2.0625, we zero out the 1.7 passenger height so we can apply 1.8's offsets.
|
||||
double baseOffset = -2.0625;
|
||||
|
||||
if (marker) {
|
||||
// 1.8 Marker ArmorStand height is 0.0 -> mounted offset 0.0
|
||||
return baseOffset;
|
||||
} else {
|
||||
// 1.8 Normal ArmorStand height is 1.975 -> mounted offset 1.975 * 0.75 = 1.48125
|
||||
return baseOffset + 1.48125;
|
||||
}
|
||||
} else {
|
||||
return -0.4;
|
||||
}
|
||||
@@ -291,6 +304,13 @@ public class VirtualHologramEntity {
|
||||
this.entityIds = entityIds;
|
||||
}
|
||||
|
||||
for (int extraId : entityIds) {
|
||||
if (extraId != entityId) {
|
||||
((EntityTracker1_8) user.getEntityTracker(Protocol1_8To1_7_6_10.class)).setExtraHologramId(entityId, extraId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sendEntityDataUpdate(entityRewriter);
|
||||
if (entityIds == null) {
|
||||
return;
|
||||
@@ -326,6 +346,13 @@ public class VirtualHologramEntity {
|
||||
if (entityIds == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int extraId : entityIds) {
|
||||
if (extraId != entityId) {
|
||||
((EntityTracker1_8) user.getEntityTracker(Protocol1_8To1_7_6_10.class)).removeExtraHologramId(extraId);
|
||||
}
|
||||
}
|
||||
|
||||
final PacketWrapper despawn = PacketWrapper.create(ClientboundPackets1_7_2_5.REMOVE_ENTITIES, user);
|
||||
despawn.write(Types.BYTE, (byte) entityIds.length);
|
||||
for (int id : entityIds) {
|
||||
|
||||
+1
-5
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -20,7 +20,6 @@ package com.viaversion.viarewind.protocol.v1_8to1_7_6_10.provider;
|
||||
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.storage.CompressionStatusTracker;
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.api.platform.providers.Provider;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
|
||||
public abstract class CompressionHandlerProvider implements Provider {
|
||||
|
||||
@@ -28,9 +27,6 @@ public abstract class CompressionHandlerProvider implements Provider {
|
||||
|
||||
public abstract void onTransformPacket(UserConnection user);
|
||||
|
||||
public abstract ChannelHandler getEncoder(int threshold);
|
||||
|
||||
public abstract ChannelHandler getDecoder(int threshold);
|
||||
|
||||
public boolean isRemoveCompression(UserConnection user) {
|
||||
return user.get(CompressionStatusTracker.class).removeCompression;
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+8
-16
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -17,17 +17,15 @@
|
||||
*/
|
||||
package com.viaversion.viarewind.protocol.v1_8to1_7_6_10.provider.compression;
|
||||
|
||||
import com.viaversion.viarewind.api.compression.ThreadLocalCompressionProvider;
|
||||
import com.viaversion.viaversion.api.type.Types;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.DecoderException;
|
||||
import io.netty.handler.codec.MessageToMessageDecoder;
|
||||
import java.util.List;
|
||||
import java.util.zip.Inflater;
|
||||
|
||||
public class CompressionDecoder extends MessageToMessageDecoder<ByteBuf> {
|
||||
private final Inflater inflater = new Inflater();
|
||||
|
||||
private int threshold;
|
||||
|
||||
@@ -41,7 +39,9 @@ public class CompressionDecoder extends MessageToMessageDecoder<ByteBuf> {
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
|
||||
if (!in.isReadable()) return;
|
||||
if (!in.isReadable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int outLength = Types.VAR_INT.readPrimitive(in);
|
||||
if (outLength == 0) {
|
||||
@@ -55,21 +55,13 @@ public class CompressionDecoder extends MessageToMessageDecoder<ByteBuf> {
|
||||
throw new DecoderException("Badly compressed packet - size of " + outLength + " is larger than protocol maximum of " + 2097152);
|
||||
}
|
||||
|
||||
ByteBuf temp = in;
|
||||
if (!in.hasArray()) {
|
||||
temp = ByteBufAllocator.DEFAULT.heapBuffer().writeBytes(in);
|
||||
} else {
|
||||
in.retain();
|
||||
}
|
||||
ByteBuf output = ByteBufAllocator.DEFAULT.heapBuffer(outLength, outLength);
|
||||
ByteBuf output = ctx.alloc().buffer(outLength);
|
||||
try {
|
||||
this.inflater.setInput(temp.array(), temp.arrayOffset() + temp.readerIndex(), temp.readableBytes());
|
||||
output.writerIndex(output.writerIndex() + this.inflater.inflate(output.array(), output.arrayOffset(), outLength));
|
||||
ThreadLocalCompressionProvider.inflate(in, output, outLength);
|
||||
out.add(output.retain());
|
||||
} finally {
|
||||
output.release();
|
||||
temp.release();
|
||||
this.inflater.reset();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+4
-26
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -17,15 +17,13 @@
|
||||
*/
|
||||
package com.viaversion.viarewind.protocol.v1_8to1_7_6_10.provider.compression;
|
||||
|
||||
import com.viaversion.viarewind.api.compression.ThreadLocalCompressionProvider;
|
||||
import com.viaversion.viaversion.api.type.Types;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
import java.util.zip.Deflater;
|
||||
|
||||
public class CompressionEncoder extends MessageToByteEncoder<ByteBuf> {
|
||||
private final Deflater deflater = new Deflater();
|
||||
|
||||
private int threshold;
|
||||
|
||||
@@ -47,27 +45,7 @@ public class CompressionEncoder extends MessageToByteEncoder<ByteBuf> {
|
||||
}
|
||||
|
||||
Types.VAR_INT.writePrimitive(out, frameLength);
|
||||
|
||||
ByteBuf temp = in;
|
||||
if (!in.hasArray()) {
|
||||
temp = ByteBufAllocator.DEFAULT.heapBuffer().writeBytes(in);
|
||||
} else {
|
||||
in.retain();
|
||||
}
|
||||
ByteBuf output = ByteBufAllocator.DEFAULT.heapBuffer();
|
||||
try {
|
||||
this.deflater.setInput(temp.array(), temp.arrayOffset() + temp.readerIndex(), temp.readableBytes());
|
||||
deflater.finish();
|
||||
|
||||
while (!deflater.finished()) {
|
||||
output.ensureWritable(4096);
|
||||
output.writerIndex(output.writerIndex() + this.deflater.deflate(output.array(), output.arrayOffset() + output.writerIndex(), output.writableBytes()));
|
||||
}
|
||||
out.writeBytes(output);
|
||||
} finally {
|
||||
output.release();
|
||||
temp.release();
|
||||
this.deflater.reset();
|
||||
}
|
||||
ThreadLocalCompressionProvider.deflate(in, out);
|
||||
}
|
||||
|
||||
}
|
||||
+3
-12
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -23,7 +23,6 @@ import com.viaversion.viarewind.api.minecraft.netty.ForwardMessageToByteEncoder;
|
||||
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.provider.CompressionHandlerProvider;
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
|
||||
public class TrackingCompressionHandlerProvider extends CompressionHandlerProvider {
|
||||
@@ -41,7 +40,7 @@ public class TrackingCompressionHandlerProvider extends CompressionHandlerProvid
|
||||
if (encoder != null) {
|
||||
encoder.setThreshold(threshold);
|
||||
} else {
|
||||
pipeline.addBefore(Via.getManager().getInjector().getEncoderName(), compressHandlerName, getEncoder(threshold));
|
||||
pipeline.addBefore(Via.getManager().getInjector().getEncoderName(), compressHandlerName, new CompressionEncoder(threshold));
|
||||
}
|
||||
|
||||
final String decompressHandlerName = ViaRewind.getPlatform().decompressHandlerName();
|
||||
@@ -49,7 +48,7 @@ public class TrackingCompressionHandlerProvider extends CompressionHandlerProvid
|
||||
if (decoder != null) {
|
||||
decoder.setThreshold(threshold);
|
||||
} else {
|
||||
pipeline.addBefore(Via.getManager().getInjector().getDecoderName(), decompressHandlerName, getDecoder(threshold));
|
||||
pipeline.addBefore(Via.getManager().getInjector().getDecoderName(), decompressHandlerName, new CompressionDecoder(threshold));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,13 +75,5 @@ public class TrackingCompressionHandlerProvider extends CompressionHandlerProvid
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelHandler getEncoder(int threshold) {
|
||||
return new CompressionEncoder(threshold);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelHandler getDecoder(int threshold) {
|
||||
return new CompressionDecoder(threshold);
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -113,7 +113,7 @@ public class BlockItemPacketRewriter1_8 extends VRBlockItemRewriter<ClientboundP
|
||||
final Item item = wrapper.get(RewindTypes.COMPRESSED_NBT_ITEM, 0);
|
||||
playerSession.setPlayerEquipment(wrapper.user().getProtocolInfo().getUuid(), item, 8 - slot);
|
||||
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class);
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(protocol);
|
||||
if (tracker.isSpectator()) { // Spectator mode didn't exist in 1.7.10
|
||||
wrapper.cancel();
|
||||
}
|
||||
@@ -148,7 +148,7 @@ public class BlockItemPacketRewriter1_8 extends VRBlockItemRewriter<ClientboundP
|
||||
if (windowId != 0) {
|
||||
return;
|
||||
}
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class);
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(protocol);
|
||||
final UUID userId = wrapper.user().getProtocolInfo().getUuid();
|
||||
|
||||
final Item[] items = wrapper.get(RewindTypes.COMPRESSED_NBT_ITEM_ARRAY, 0);
|
||||
|
||||
+19
-14
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -76,7 +76,7 @@ public class EntityPacketRewriter1_8 extends VREntityRewriter<ClientboundPackets
|
||||
}
|
||||
}
|
||||
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class);
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(protocol);
|
||||
tracker.addPlayer(entityId, wrapper.user().getProtocolInfo().getUuid());
|
||||
|
||||
tracker.setClientEntityGameMode(wrapper.get(Types.UNSIGNED_BYTE, 0));
|
||||
@@ -275,7 +275,7 @@ public class EntityPacketRewriter1_8 extends VREntityRewriter<ClientboundPackets
|
||||
final byte pitch = wrapper.get(Types.BYTE, 1);
|
||||
final byte yaw = wrapper.get(Types.BYTE, 0);
|
||||
final byte headYaw = wrapper.get(Types.BYTE, 2);
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class);
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(protocol);
|
||||
final VirtualHologramEntity hologram = tracker.getHolograms().get(entityId);
|
||||
|
||||
hologram.setPosition(x / 32.0, y / 32.0, z / 32.0);
|
||||
@@ -314,7 +314,7 @@ public class EntityPacketRewriter1_8 extends VREntityRewriter<ClientboundPackets
|
||||
|
||||
final int entityId = wrapper.get(Types.VAR_INT, 0);
|
||||
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class);
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(protocol);
|
||||
if (gameProfile != null && gameProfile.gamemode == 3) { // Spectator mode
|
||||
for (short i = 0; i < 5; i++) {
|
||||
final PacketWrapper entityEquipment = PacketWrapper.create(ClientboundPackets1_7_2_5.SET_EQUIPPED_ITEM, wrapper.user());
|
||||
@@ -337,6 +337,11 @@ public class EntityPacketRewriter1_8 extends VREntityRewriter<ClientboundPackets
|
||||
map(Types.ENTITY_DATA_LIST1_8, RewindTypes.ENTITY_DATA_LIST1_7); // Entity data
|
||||
|
||||
handler(getTrackerAndDataHandler(RewindTypes.ENTITY_DATA_LIST1_7, EntityTypes1_8.EntityType.PLAYER));
|
||||
handler(wrapper -> {
|
||||
final int entityId = wrapper.get(Types.VAR_INT, 0);
|
||||
final EntityTracker1_8 tracker = tracker(wrapper.user());
|
||||
tracker.checkNametagVisibility(entityId);
|
||||
});
|
||||
}
|
||||
});
|
||||
protocol.registerClientbound(ClientboundPackets1_8.SET_EQUIPPED_ITEM, new PacketHandlers() {
|
||||
@@ -349,7 +354,7 @@ public class EntityPacketRewriter1_8 extends VREntityRewriter<ClientboundPackets
|
||||
handler(wrapper -> protocol.getItemRewriter().handleItemToClient(wrapper.user(), wrapper.get(RewindTypes.COMPRESSED_NBT_ITEM, 0)));
|
||||
|
||||
handler(wrapper -> {
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class);
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(protocol);
|
||||
final int id = wrapper.get(Types.INT, 0);
|
||||
|
||||
final int limit = tracker.clientEntityId() == id ? 3 : 4;
|
||||
@@ -359,7 +364,7 @@ public class EntityPacketRewriter1_8 extends VREntityRewriter<ClientboundPackets
|
||||
});
|
||||
|
||||
handler(wrapper -> {
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class);
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(protocol);
|
||||
final short slot = wrapper.get(Types.SHORT, 0);
|
||||
final UUID uuid = tracker.getPlayerUUID(wrapper.get(Types.INT, 0));
|
||||
if (uuid == null) {
|
||||
@@ -391,7 +396,7 @@ public class EntityPacketRewriter1_8 extends VREntityRewriter<ClientboundPackets
|
||||
map(Types.VAR_INT, Types.INT); // Collected Entity id
|
||||
map(Types.VAR_INT, Types.INT); // Collector Entity id
|
||||
|
||||
handler(wrapper -> wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class).removeEntity(wrapper.get(Types.INT, 0)));
|
||||
handler(wrapper -> wrapper.user().getEntityTracker(protocol).removeEntity(wrapper.get(Types.INT, 0)));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -419,7 +424,7 @@ public class EntityPacketRewriter1_8 extends VREntityRewriter<ClientboundPackets
|
||||
read(Types.BOOLEAN); // On ground
|
||||
|
||||
handler(wrapper -> {
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class);
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(protocol);
|
||||
|
||||
final VirtualHologramEntity hologram = tracker.getHolograms().get(wrapper.get(Types.INT, 0));
|
||||
if (hologram != null) {
|
||||
@@ -443,7 +448,7 @@ public class EntityPacketRewriter1_8 extends VREntityRewriter<ClientboundPackets
|
||||
read(Types.BOOLEAN); // On ground
|
||||
|
||||
handler(wrapper -> {
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class);
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(protocol);
|
||||
|
||||
final VirtualHologramEntity hologram = tracker.getHolograms().get(wrapper.get(Types.INT, 0));
|
||||
if (hologram != null) {
|
||||
@@ -469,7 +474,7 @@ public class EntityPacketRewriter1_8 extends VREntityRewriter<ClientboundPackets
|
||||
read(Types.BOOLEAN); // On ground
|
||||
|
||||
handler(wrapper -> {
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class);
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(protocol);
|
||||
|
||||
final VirtualHologramEntity hologram = tracker.getHolograms().get(wrapper.get(Types.INT, 0));
|
||||
if (hologram != null) {
|
||||
@@ -501,7 +506,7 @@ public class EntityPacketRewriter1_8 extends VREntityRewriter<ClientboundPackets
|
||||
handler(wrapper -> {
|
||||
final int entityId = wrapper.get(Types.INT, 0);
|
||||
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class);
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(protocol);
|
||||
if (tracker.entityType(entityId) == EntityTypes1_8.EntityType.ABSTRACT_MINECART) { // TODO | Realign all entities?
|
||||
int y = wrapper.get(Types.INT, 2);
|
||||
y += 12;
|
||||
@@ -532,7 +537,7 @@ public class EntityPacketRewriter1_8 extends VREntityRewriter<ClientboundPackets
|
||||
map(Types.BYTE); // Head yaw
|
||||
|
||||
handler(wrapper -> {
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class);
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(protocol);
|
||||
|
||||
final VirtualHologramEntity hologram = tracker.getHolograms().get(wrapper.get(Types.INT, 0));
|
||||
if (hologram != null) {
|
||||
@@ -554,7 +559,7 @@ public class EntityPacketRewriter1_8 extends VREntityRewriter<ClientboundPackets
|
||||
handler(wrapper -> {
|
||||
final boolean leash = wrapper.get(Types.BOOLEAN, 0);
|
||||
if (!leash) {
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class);
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(protocol);
|
||||
|
||||
final int passenger = wrapper.get(Types.INT, 0);
|
||||
final int vehicle = wrapper.get(Types.INT, 1);
|
||||
@@ -589,7 +594,7 @@ public class EntityPacketRewriter1_8 extends VREntityRewriter<ClientboundPackets
|
||||
public void register() {
|
||||
map(Types.VAR_INT, Types.INT); // Entity id
|
||||
handler(wrapper -> {
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class);
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(protocol);
|
||||
if (tracker.getHolograms().containsKey(wrapper.get(Types.INT, 0))) { // Don't handle properties for hologram emulation
|
||||
wrapper.cancel();
|
||||
return;
|
||||
|
||||
+108
-27
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -30,6 +30,7 @@ import com.viaversion.viarewind.protocol.v1_7_6_10to1_7_2_5.packet.ClientboundPa
|
||||
import com.viaversion.viarewind.protocol.v1_7_6_10to1_7_2_5.packet.ServerboundPackets1_7_2_5;
|
||||
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.Protocol1_8To1_7_6_10;
|
||||
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.data.ChatItemRewriter;
|
||||
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.data.ChatNewlineRewriter;
|
||||
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.provider.TitleRenderProvider;
|
||||
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.storage.EntityTracker1_8;
|
||||
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.storage.GameProfileStorage;
|
||||
@@ -37,6 +38,7 @@ import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.storage.InventoryTracker
|
||||
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.storage.PlayerSessionStorage;
|
||||
import com.viaversion.viarewind.utils.ChatUtil;
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.api.minecraft.BlockPosition;
|
||||
import com.viaversion.viaversion.api.minecraft.ClientWorld;
|
||||
import com.viaversion.viaversion.api.minecraft.GameProfile;
|
||||
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
|
||||
@@ -46,6 +48,8 @@ import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
|
||||
import com.viaversion.viaversion.api.rewriter.RewriterBase;
|
||||
import com.viaversion.viaversion.api.type.Types;
|
||||
import com.viaversion.viaversion.libs.gson.JsonElement;
|
||||
import com.viaversion.viaversion.libs.gson.JsonObject;
|
||||
import com.viaversion.viaversion.libs.gson.JsonPrimitive;
|
||||
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_8;
|
||||
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ServerboundPackets1_8;
|
||||
import com.viaversion.viaversion.util.ComponentUtil;
|
||||
@@ -70,13 +74,27 @@ public class PlayerPacketRewriter1_8 extends RewriterBase<Protocol1_8To1_7_6_10>
|
||||
@Override
|
||||
public void register() {
|
||||
map(Types.COMPONENT); // Chat message
|
||||
|
||||
handler(wrapper -> {
|
||||
final JsonElement json = wrapper.get(Types.COMPONENT, 0);
|
||||
ChatItemRewriter.toClient(protocol, wrapper.user(), json);
|
||||
|
||||
final int position = wrapper.read(Types.BYTE);
|
||||
|
||||
if (position == 2) { // Above hotbar
|
||||
wrapper.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
ChatItemRewriter.toClient(protocol, wrapper.user(), json);
|
||||
List<JsonObject> splitComponents = ChatNewlineRewriter.splitChatComponentByNewline(json);
|
||||
|
||||
if (splitComponents.size() > 1) {
|
||||
wrapper.cancel();
|
||||
|
||||
for (JsonObject split : splitComponents) {
|
||||
PacketWrapper newWrapper = wrapper.create(ClientboundPackets1_7_2_5.CHAT);
|
||||
newWrapper.write(Types.COMPONENT, split);
|
||||
newWrapper.send(Protocol1_8To1_7_6_10.class);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -111,13 +129,13 @@ public class PlayerPacketRewriter1_8 extends RewriterBase<Protocol1_8To1_7_6_10>
|
||||
}
|
||||
}
|
||||
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class);
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(protocol);
|
||||
tracker.setClientEntityGameMode(wrapper.get(Types.UNSIGNED_BYTE, 1));
|
||||
|
||||
final int dimension = wrapper.get(Types.INT, 0);
|
||||
|
||||
// Clear entities on dimension change and re-track player
|
||||
final ClientWorld world = wrapper.user().getClientWorld(Protocol1_8To1_7_6_10.class);
|
||||
final ClientWorld world = wrapper.user().storables(protocol).clientWorld();
|
||||
if (world.setEnvironment(dimension)) {
|
||||
tracker.clearEntities();
|
||||
tracker.addPlayer(tracker.clientEntityId(), wrapper.user().getProtocolInfo().getUuid());
|
||||
@@ -178,7 +196,7 @@ public class PlayerPacketRewriter1_8 extends RewriterBase<Protocol1_8To1_7_6_10>
|
||||
|
||||
wrapper.write(Types.BOOLEAN, playerSession.onGround);
|
||||
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class);
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(protocol);
|
||||
if (!Objects.equals(tracker.spectatingClientEntityId, tracker.clientEntityIdOrNull())) {
|
||||
wrapper.cancel();
|
||||
}
|
||||
@@ -204,7 +222,7 @@ public class PlayerPacketRewriter1_8 extends RewriterBase<Protocol1_8To1_7_6_10>
|
||||
if (wrapper.get(Types.UNSIGNED_BYTE, 0) != 3) return; // Change game mode
|
||||
int gameMode = wrapper.get(Types.FLOAT, 0).intValue();
|
||||
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class);
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(protocol);
|
||||
if (gameMode == 3 || tracker.isSpectator()) {
|
||||
UUID myId = wrapper.user().getProtocolInfo().getUuid();
|
||||
Item[] equipment = new Item[4];
|
||||
@@ -276,7 +294,7 @@ public class PlayerPacketRewriter1_8 extends RewriterBase<Protocol1_8To1_7_6_10>
|
||||
}
|
||||
|
||||
if (gamemode == 3 || gameProfile.gamemode == 3) {
|
||||
EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class);
|
||||
EntityTracker1_8 tracker = wrapper.user().getEntityTracker(protocol);
|
||||
int entityId = tracker.getPlayerEntityId(uuid);
|
||||
boolean isOwnPlayer = entityId == tracker.clientEntityId();
|
||||
if (entityId != -1) {
|
||||
@@ -429,7 +447,7 @@ public class PlayerPacketRewriter1_8 extends RewriterBase<Protocol1_8To1_7_6_10>
|
||||
wrapper.cancel();
|
||||
final int entityId = wrapper.read(Types.VAR_INT);
|
||||
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class);
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(protocol);
|
||||
if (tracker.spectatingClientEntityId != entityId) {
|
||||
tracker.setSpectating(entityId);
|
||||
}
|
||||
@@ -490,12 +508,18 @@ public class PlayerPacketRewriter1_8 extends RewriterBase<Protocol1_8To1_7_6_10>
|
||||
|
||||
protocol.registerServerbound(ServerboundPackets1_7_2_5.CHAT, wrapper -> {
|
||||
final String message = wrapper.passthrough(Types.STRING);
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class);
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(protocol);
|
||||
if (tracker.isSpectator() && message.toLowerCase().startsWith("/stp ")) { // TODO add setting
|
||||
String username = message.split(" ")[1];
|
||||
final GameProfileStorage storage = wrapper.user().get(GameProfileStorage.class);
|
||||
|
||||
final GameProfileStorage.GameProfile profile = storage.get(username, true);
|
||||
// Multiple players with the same name may exist. This will only represent
|
||||
// fake players so it's fine to just pick the first one.
|
||||
List<GameProfileStorage.GameProfile> profiles = storage.get(username, true);
|
||||
if (profiles.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
final GameProfileStorage.GameProfile profile = profiles.get(0);
|
||||
if (profile != null && profile.uuid != null) {
|
||||
wrapper.cancel();
|
||||
|
||||
@@ -513,16 +537,20 @@ public class PlayerPacketRewriter1_8 extends RewriterBase<Protocol1_8To1_7_6_10>
|
||||
map(Types.BYTE, Types.VAR_INT); // Mode
|
||||
handler(wrapper -> {
|
||||
final int mode = wrapper.get(Types.VAR_INT, 1);
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(protocol);
|
||||
final int entityId = tracker.getHologramIdWithExtra(wrapper.get(Types.VAR_INT, 0));
|
||||
final PlayerSessionStorage position = wrapper.user().get(PlayerSessionStorage.class);
|
||||
|
||||
if (entityId == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
wrapper.set(Types.VAR_INT, 0, entityId);
|
||||
|
||||
if (mode != 0) {
|
||||
return;
|
||||
}
|
||||
final int entityId = wrapper.get(Types.VAR_INT, 0);
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class);
|
||||
final PlayerSessionStorage position = wrapper.user().get(PlayerSessionStorage.class);
|
||||
|
||||
if (!tracker.getHolograms().containsKey(entityId)) {
|
||||
return;
|
||||
}
|
||||
final AABB boundingBox = tracker.getHolograms().get(entityId).getBoundingBox();
|
||||
|
||||
Vector3d pos = new Vector3d(position.getPosX(), position.getPosY() + 1.8, position.getPosZ());
|
||||
@@ -590,6 +618,16 @@ public class PlayerPacketRewriter1_8 extends RewriterBase<Protocol1_8To1_7_6_10>
|
||||
protected void register() {
|
||||
map(Types.VAR_INT); // Status
|
||||
map(RewindTypes.U_BYTE_POSITION, Types.BLOCK_POSITION1_8); // Position
|
||||
handler(wrapper -> {
|
||||
// 1.7 uses 255 as "no face"
|
||||
// 1.8 changed this to only be in the range EnumFacing range (0-5) and uses DOWN when no face is used
|
||||
// This properly rewrites invalid values to the 1.8 equivalent
|
||||
int face = wrapper.read(Types.UNSIGNED_BYTE);
|
||||
if (face > 5) {
|
||||
face = 0;
|
||||
}
|
||||
wrapper.write(Types.UNSIGNED_BYTE, (short) face);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -600,6 +638,16 @@ public class PlayerPacketRewriter1_8 extends RewriterBase<Protocol1_8To1_7_6_10>
|
||||
map(Types.BYTE); // Direction
|
||||
map(RewindTypes.COMPRESSED_NBT_ITEM, Types.ITEM1_8); // Item
|
||||
|
||||
handler(wrapper -> {
|
||||
final BlockPosition position = wrapper.get(Types.BLOCK_POSITION1_8, 0);
|
||||
final byte direction = wrapper.get(Types.BYTE, 0);
|
||||
// 1.7 serializes the Y component as an unsigned byte, turning the
|
||||
// use-in-air position from (-1, -1, -1) into (-1, 255, -1).
|
||||
// we change that back to -1 for Y like 1.8 clients
|
||||
if (position.x() == -1 && position.y() == 255 && position.z() == -1 && direction == -1) {
|
||||
wrapper.set(Types.BLOCK_POSITION1_8, 0, new BlockPosition(-1, -1, -1));
|
||||
}
|
||||
});
|
||||
handler(wrapper -> protocol.getItemRewriter().handleItemToServer(wrapper.user(), wrapper.get(Types.ITEM1_8, 0)));
|
||||
}
|
||||
});
|
||||
@@ -672,7 +720,7 @@ public class PlayerPacketRewriter1_8 extends RewriterBase<Protocol1_8To1_7_6_10>
|
||||
if (!unmount) {
|
||||
return;
|
||||
}
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class);
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(protocol);
|
||||
if (tracker.spectatingClientEntityId != tracker.clientEntityId()) {
|
||||
PacketWrapper sneakPacket = PacketWrapper.create(ServerboundPackets1_8.PLAYER_COMMAND, wrapper.user());
|
||||
sneakPacket.write(Types.VAR_INT, tracker.clientEntityId());
|
||||
@@ -752,6 +800,8 @@ public class PlayerPacketRewriter1_8 extends RewriterBase<Protocol1_8To1_7_6_10>
|
||||
}
|
||||
});
|
||||
|
||||
// 1.7.10 custom payload constructor (String, ByteBuf) uses byteBuf.array(), so it sends the whole backing array capacity, not only the written bytes
|
||||
// After reading the proper packet data we discard the remaining bytes
|
||||
protocol.registerServerbound(ServerboundPackets1_7_2_5.CUSTOM_PAYLOAD, new PacketHandlers() {
|
||||
@Override
|
||||
public void register() {
|
||||
@@ -762,7 +812,27 @@ public class PlayerPacketRewriter1_8 extends RewriterBase<Protocol1_8To1_7_6_10>
|
||||
switch (channel) {
|
||||
case "MC|TrSel": {
|
||||
wrapper.passthrough(Types.INT);
|
||||
wrapper.read(Types.REMAINING_BYTES); // unused data ???
|
||||
wrapper.read(Types.REMAINING_BYTES); // Discard remaining bytes
|
||||
break;
|
||||
}
|
||||
case "MC|AdvCdm": {
|
||||
final byte commandBlockType = wrapper.passthrough(Types.BYTE);
|
||||
if (commandBlockType == 0) { // Block
|
||||
wrapper.passthrough(Types.INT); // X
|
||||
wrapper.passthrough(Types.INT); // Y
|
||||
wrapper.passthrough(Types.INT); // Z
|
||||
} else if (commandBlockType == 1) { // Minecart
|
||||
wrapper.passthrough(Types.INT); // Entity id
|
||||
}
|
||||
wrapper.passthrough(Types.STRING); // Command
|
||||
wrapper.write(Types.BOOLEAN, true); // Track output, added in 1.8, default to true
|
||||
wrapper.read(Types.REMAINING_BYTES); // Discard remaining bytes
|
||||
break;
|
||||
}
|
||||
case "MC|Beacon": {
|
||||
wrapper.passthrough(Types.INT); // Primary effect
|
||||
wrapper.passthrough(Types.INT); // Secondary effect
|
||||
wrapper.read(Types.REMAINING_BYTES); // Discard remaining bytes
|
||||
break;
|
||||
}
|
||||
case "MC|ItemName": {
|
||||
@@ -779,17 +849,28 @@ public class PlayerPacketRewriter1_8 extends RewriterBase<Protocol1_8To1_7_6_10>
|
||||
}
|
||||
case "MC|BEdit":
|
||||
case "MC|BSign": {
|
||||
final boolean signBook = channel.equals("MC|BSign");
|
||||
final Item book = wrapper.read(RewindTypes.COMPRESSED_NBT_ITEM);
|
||||
CompoundTag tag = book.tag();
|
||||
if (tag != null && tag.contains("pages")) {
|
||||
ListTag<StringTag> pages = tag.getListTag("pages", StringTag.class);
|
||||
for (int i = 0; i < pages.size(); i++) {
|
||||
StringTag page = pages.get(i);
|
||||
String value = page.getValue();
|
||||
value = ComponentUtil.legacyToJsonString(value);
|
||||
page.setValue(value);
|
||||
wrapper.read(Types.REMAINING_BYTES); // Discard remaining bytes
|
||||
|
||||
if (book == null) {
|
||||
wrapper.write(Types.ITEM1_8, null);
|
||||
break;
|
||||
}
|
||||
|
||||
final CompoundTag tag = book.tag();
|
||||
if (signBook && tag != null && tag.contains("pages")) {
|
||||
final ListTag<StringTag> pages = tag.getListTag("pages", StringTag.class);
|
||||
if (pages != null) {
|
||||
for (int i = 0; i < pages.size(); i++) {
|
||||
final StringTag page = pages.get(i);
|
||||
String value = page.getValue();
|
||||
value = new JsonPrimitive(value).toString();
|
||||
page.setValue(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
protocol.getItemRewriter().handleItemToServer(wrapper.user(), book);
|
||||
wrapper.write(Types.ITEM1_8, book);
|
||||
break;
|
||||
}
|
||||
|
||||
+21
-2
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -19,6 +19,7 @@ package com.viaversion.viarewind.protocol.v1_8to1_7_6_10.rewriter;
|
||||
|
||||
import com.viaversion.viarewind.protocol.v1_7_6_10to1_7_2_5.packet.ClientboundPackets1_7_2_5;
|
||||
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.Protocol1_8To1_7_6_10;
|
||||
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.storage.EntityTracker1_8;
|
||||
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.storage.ScoreboardTracker;
|
||||
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
|
||||
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
|
||||
@@ -173,6 +174,7 @@ public class ScoreboardPacketRewriter1_8 extends RewriterBase<Protocol1_8To1_7_6
|
||||
}
|
||||
|
||||
final ScoreboardTracker scoreboard = wrapper.user().get(ScoreboardTracker.class);
|
||||
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(protocol);
|
||||
|
||||
final byte mode = wrapper.passthrough(Types.BYTE);
|
||||
if (mode != 0 && !scoreboard.teamExists(team)) {
|
||||
@@ -190,6 +192,10 @@ public class ScoreboardPacketRewriter1_8 extends RewriterBase<Protocol1_8To1_7_6
|
||||
if (mode == 0) {
|
||||
scoreboard.addTeam(team);
|
||||
} else if (mode == 1) {
|
||||
// Team removed, nametag visibility might have changed
|
||||
for (final String member : scoreboard.getTeamMembers(team)) {
|
||||
tracker.checkNametagVisbility(member);
|
||||
}
|
||||
scoreboard.removeTeam(team);
|
||||
}
|
||||
|
||||
@@ -198,7 +204,9 @@ public class ScoreboardPacketRewriter1_8 extends RewriterBase<Protocol1_8To1_7_6
|
||||
wrapper.passthrough(Types.STRING); // Prefix
|
||||
wrapper.passthrough(Types.STRING); // Suffix
|
||||
wrapper.passthrough(Types.BYTE); // Friendly fire
|
||||
wrapper.read(Types.STRING); // Name tag visibility
|
||||
final String nameTagVisibility = wrapper.read(Types.STRING);
|
||||
final String previousVisibility = scoreboard.getTeamNameTagVisibility(team);
|
||||
scoreboard.setTeamNameTagVisibility(team, nameTagVisibility);
|
||||
byte color = wrapper.read(Types.BYTE);
|
||||
if (mode == 2 && scoreboard.getTeamColor(team).get() != color) {
|
||||
final String sidebar = scoreboard.getColorDependentSidebar().get(color);
|
||||
@@ -209,6 +217,13 @@ public class ScoreboardPacketRewriter1_8 extends RewriterBase<Protocol1_8To1_7_6
|
||||
sidebarPacket.scheduleSend(Protocol1_8To1_7_6_10.class);
|
||||
}
|
||||
scoreboard.setTeamColor(team, color);
|
||||
|
||||
// Re-evaluate nametag visibility for all team members when visibility changes
|
||||
if (mode == 2 && !nameTagVisibility.equals(previousVisibility)) {
|
||||
for (final String member : scoreboard.getTeamMembers(team)) {
|
||||
tracker.checkNametagVisbility(member);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mode == 0 || mode == 3 || mode == 4) {
|
||||
byte color = scoreboard.getTeamColor(team).get();
|
||||
@@ -223,6 +238,8 @@ public class ScoreboardPacketRewriter1_8 extends RewriterBase<Protocol1_8To1_7_6
|
||||
continue;
|
||||
}
|
||||
scoreboard.removePlayerFromTeam(entry, team);
|
||||
// Player left team, nametag visibility may change
|
||||
tracker.checkNametagVisbility(entry);
|
||||
if (entry.equals(username)) {
|
||||
final PacketWrapper sidebarPacket = PacketWrapper.create(ClientboundPackets1_7_2_5.SET_DISPLAY_OBJECTIVE, wrapper.user());
|
||||
sidebarPacket.write(Types.BYTE, (byte) 1);
|
||||
@@ -231,6 +248,8 @@ public class ScoreboardPacketRewriter1_8 extends RewriterBase<Protocol1_8To1_7_6
|
||||
}
|
||||
} else {
|
||||
scoreboard.addPlayerToTeam(entry, team);
|
||||
// Player joined team, nametag visibility may change
|
||||
tracker.checkNametagVisbility(entry);
|
||||
if (entry.equals(username) && scoreboard.getColorDependentSidebar().containsKey(color)) {
|
||||
final PacketWrapper displayObjective = PacketWrapper.create(ClientboundPackets1_7_2_5.SET_DISPLAY_OBJECTIVE, wrapper.user());
|
||||
displayObjective.write(Types.BYTE, (byte) 1);
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -47,7 +47,7 @@ public class WorldPacketRewriter1_8 extends RewriterBase<Protocol1_8To1_7_6_10>
|
||||
@Override
|
||||
protected void registerPackets() {
|
||||
protocol.registerClientbound(ClientboundPackets1_8.LEVEL_CHUNK, wrapper -> {
|
||||
final ClientWorld world = wrapper.user().getClientWorld(Protocol1_8To1_7_6_10.class);
|
||||
final ClientWorld world = wrapper.user().storables(protocol).clientWorld();
|
||||
final Chunk chunk = wrapper.read(ChunkType1_8.forEnvironment(world.getEnvironment()));
|
||||
protocol.getItemRewriter().handleChunk(chunk);
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+127
-6
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -22,6 +22,7 @@ import com.viaversion.viarewind.protocol.v1_7_6_10to1_7_2_5.packet.ServerboundPa
|
||||
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.Protocol1_8To1_7_6_10;
|
||||
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.data.VirtualHologramEntity;
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.api.data.entity.TrackedEntity;
|
||||
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
|
||||
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8;
|
||||
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
|
||||
@@ -37,18 +38,26 @@ import com.viaversion.viaversion.libs.fastutil.objects.Object2IntMap;
|
||||
import com.viaversion.viaversion.libs.fastutil.objects.Object2IntOpenHashMap;
|
||||
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_8;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import com.viaversion.viarewind.api.minecraft.entitydata.EntityDataTypes1_7_6_10;
|
||||
import com.viaversion.viarewind.api.type.RewindTypes;
|
||||
import com.viaversion.viarewind.protocol.v1_7_6_10to1_7_2_5.packet.ClientboundPackets1_7_2_5;
|
||||
|
||||
public class EntityTracker1_8 extends EntityTrackerBase {
|
||||
|
||||
private final Int2ObjectMap<VirtualHologramEntity> holograms = new Int2ObjectArrayMap<>();
|
||||
private final Int2IntMap extraHologramIds = new Int2IntArrayMap();
|
||||
private final Int2IntMap vehicles = new Int2IntArrayMap();
|
||||
private final Int2ObjectMap<UUID> entityIdToUUID = new Int2ObjectArrayMap<>();
|
||||
private final Object2IntMap<UUID> entityUUIDToId = new Object2IntOpenHashMap<>();
|
||||
private final Int2IntMap playerNametagHiderEntities = new Int2IntArrayMap();
|
||||
|
||||
private final List<EntityData> entityData = new ArrayList<>();
|
||||
|
||||
@@ -60,35 +69,41 @@ public class EntityTracker1_8 extends EntityTrackerBase {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEntity(int id, EntityType type) {
|
||||
super.addEntity(id, type);
|
||||
public TrackedEntity addEntity(int id, EntityType type) {
|
||||
if (type == EntityTypes1_8.EntityType.ARMOR_STAND) {
|
||||
holograms.put(id, new VirtualHologramEntity(user(), id));
|
||||
}
|
||||
return super.addEntity(id, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeEntity(int entityId) {
|
||||
super.removeEntity(entityId);
|
||||
|
||||
public TrackedEntity removeEntity(int entityId) {
|
||||
final VirtualHologramEntity hologram = holograms.get(entityId);
|
||||
if (hologram != null) {
|
||||
hologram.deleteEntity();
|
||||
holograms.remove(entityId);
|
||||
}
|
||||
|
||||
if (playerNametagHiderEntities.containsKey(entityId)) {
|
||||
despawnNametagHiderEntity(entityId);
|
||||
}
|
||||
|
||||
if (entityIdToUUID.containsKey(entityId)) {
|
||||
final UUID playerId = entityIdToUUID.remove(entityId);
|
||||
|
||||
entityUUIDToId.removeInt(playerId);
|
||||
user().get(PlayerSessionStorage.class).getPlayerEquipment().remove(playerId);
|
||||
}
|
||||
return super.removeEntity(entityId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearEntities() {
|
||||
super.clearEntities();
|
||||
holograms.clear();
|
||||
extraHologramIds.clear();
|
||||
vehicles.clear();
|
||||
playerNametagHiderEntities.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -155,6 +170,11 @@ public class EntityTracker1_8 extends EntityTrackerBase {
|
||||
} else {
|
||||
vehicles.put(vehicleId, passengerId);
|
||||
}
|
||||
|
||||
// Re-evaluate nametag visibility when a player entity's passenger changes
|
||||
if (vehicleId != -1 && entityIdToUUID.containsKey(vehicleId)) {
|
||||
checkNametagVisibility(vehicleId);
|
||||
}
|
||||
}
|
||||
|
||||
protected void attachEntity(final int target) {
|
||||
@@ -185,10 +205,111 @@ public class EntityTracker1_8 extends EntityTrackerBase {
|
||||
}
|
||||
}
|
||||
|
||||
public void checkNametagVisibility(final int entityId) {
|
||||
if (!entityIdToUUID.containsKey(entityId)) {
|
||||
return;
|
||||
}
|
||||
final boolean shouldHide = isPlayerNametagHidden(entityId);
|
||||
final boolean hasServerPassenger = getPassenger(entityId) != -1;
|
||||
final boolean hasSkull = playerNametagHiderEntities.containsKey(entityId);
|
||||
|
||||
if (shouldHide && !hasServerPassenger && !hasSkull) {
|
||||
spawnNametagHiderEntity(entityId);
|
||||
} else if ((!shouldHide || hasServerPassenger) && hasSkull) {
|
||||
despawnNametagHiderEntity(entityId);
|
||||
}
|
||||
}
|
||||
|
||||
public void checkNametagVisbility(final String username) {
|
||||
final GameProfileStorage profileStorage = user().get(GameProfileStorage.class);
|
||||
final List<GameProfileStorage.GameProfile> profiles = profileStorage.get(username, false);
|
||||
|
||||
for (GameProfileStorage.GameProfile profile : profiles) {
|
||||
final int entityId = getPlayerEntityId(profile.uuid);
|
||||
if (entityId == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
checkNametagVisibility(entityId);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isPlayerNametagHidden(final int entityId) {
|
||||
final UUID uuid = entityIdToUUID.get(entityId);
|
||||
if (uuid == null) {
|
||||
return false;
|
||||
}
|
||||
final GameProfileStorage profileStorage = user().get(GameProfileStorage.class);
|
||||
final GameProfileStorage.GameProfile profile = profileStorage.get(uuid);
|
||||
if (profile == null) {
|
||||
return false;
|
||||
}
|
||||
return user().get(ScoreboardTracker.class).isNametagHidden(profile.name);
|
||||
}
|
||||
|
||||
private int getNametagHiderEntityId(final int playerEntityId) {
|
||||
return Integer.MAX_VALUE - 32000 - playerEntityId;
|
||||
}
|
||||
|
||||
private void spawnNametagHiderEntity(final int playerEntityId) {
|
||||
final int entityId = getNametagHiderEntityId(playerEntityId);
|
||||
playerNametagHiderEntities.put(playerEntityId, entityId);
|
||||
|
||||
final List<EntityData> mobData = new ArrayList<>();
|
||||
mobData.add(new EntityData(0, EntityDataTypes1_7_6_10.BYTE, (byte) 0x20));
|
||||
mobData.add(new EntityData(16, EntityDataTypes1_7_6_10.BYTE, (byte) 0));
|
||||
|
||||
final PacketWrapper spawnMob = PacketWrapper.create(ClientboundPackets1_7_2_5.ADD_MOB, user());
|
||||
spawnMob.write(Types.VAR_INT, entityId);
|
||||
spawnMob.write(Types.UNSIGNED_BYTE, (short) EntityTypes1_8.EntityType.MAGMA_CUBE.getId());
|
||||
spawnMob.write(Types.INT, 0); // X
|
||||
spawnMob.write(Types.INT, 0); // Y
|
||||
spawnMob.write(Types.INT, 0); // Z
|
||||
spawnMob.write(Types.BYTE, (byte) 0); // Yaw
|
||||
spawnMob.write(Types.BYTE, (byte) 0); // Pitch
|
||||
spawnMob.write(Types.BYTE, (byte) 0); // Head yaw
|
||||
spawnMob.write(Types.SHORT, (short) 0); // Velocity x
|
||||
spawnMob.write(Types.SHORT, (short) 0); // Velocity y
|
||||
spawnMob.write(Types.SHORT, (short) 0); // Velocity z
|
||||
spawnMob.write(RewindTypes.ENTITY_DATA_LIST1_7, mobData);
|
||||
spawnMob.scheduleSend(Protocol1_8To1_7_6_10.class);
|
||||
|
||||
final PacketWrapper attach = PacketWrapper.create(ClientboundPackets1_7_2_5.SET_ENTITY_LINK, user());
|
||||
attach.write(Types.INT, entityId);
|
||||
attach.write(Types.INT, playerEntityId);
|
||||
attach.write(Types.BOOLEAN, false);
|
||||
attach.scheduleSend(Protocol1_8To1_7_6_10.class);
|
||||
}
|
||||
|
||||
private void despawnNametagHiderEntity(final int playerEntityId) {
|
||||
if (!playerNametagHiderEntities.containsKey(playerEntityId)) return;
|
||||
final int mobId = playerNametagHiderEntities.remove(playerEntityId);
|
||||
|
||||
final PacketWrapper despawn = PacketWrapper.create(ClientboundPackets1_7_2_5.REMOVE_ENTITIES, user());
|
||||
despawn.write(Types.BYTE, (byte) 1);
|
||||
despawn.write(Types.INT, mobId);
|
||||
despawn.scheduleSend(Protocol1_8To1_7_6_10.class);
|
||||
}
|
||||
|
||||
public Int2ObjectMap<VirtualHologramEntity> getHolograms() {
|
||||
return holograms;
|
||||
}
|
||||
|
||||
public void setExtraHologramId(final int entityId, final int extraId) {
|
||||
extraHologramIds.put(extraId, entityId);
|
||||
}
|
||||
|
||||
public void removeExtraHologramId(int extraId) {
|
||||
extraHologramIds.remove(extraId);
|
||||
}
|
||||
|
||||
public int getHologramIdWithExtra(final int id) {
|
||||
if (holograms.containsKey(id)) {
|
||||
return id;
|
||||
}
|
||||
return extraHologramIds.getOrDefault(id, -1);
|
||||
}
|
||||
|
||||
public boolean isSpectator() {
|
||||
return clientEntityGameMode == 3;
|
||||
}
|
||||
|
||||
+14
-14
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -17,6 +17,10 @@
|
||||
*/
|
||||
package com.viaversion.viarewind.protocol.v1_8to1_7_6_10.storage;
|
||||
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.ListMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.viaversion.nbt.tag.CompoundTag;
|
||||
import com.viaversion.nbt.tag.ListTag;
|
||||
import com.viaversion.nbt.tag.StringTag;
|
||||
@@ -34,6 +38,7 @@ import java.util.UUID;
|
||||
|
||||
public class GameProfileStorage extends StoredObject {
|
||||
private final Map<UUID, GameProfile> properties = new HashMap<>();
|
||||
private final ListMultimap<String, GameProfile> nameToProfile = ArrayListMultimap.create();
|
||||
|
||||
public GameProfileStorage(UserConnection user) {
|
||||
super(user);
|
||||
@@ -42,6 +47,7 @@ public class GameProfileStorage extends StoredObject {
|
||||
public GameProfile put(UUID uuid, String name, String displayName, int ping, int gamemode) {
|
||||
GameProfile gameProfile = new GameProfile(uuid, name, displayName, ping, gamemode);
|
||||
properties.put(uuid, gameProfile);
|
||||
nameToProfile.put(name, gameProfile);
|
||||
return gameProfile;
|
||||
}
|
||||
|
||||
@@ -49,19 +55,9 @@ public class GameProfileStorage extends StoredObject {
|
||||
return properties.get(uuid);
|
||||
}
|
||||
|
||||
public GameProfile get(String name, boolean ignoreCase) {
|
||||
public List<GameProfile> get(String name, boolean ignoreCase) {
|
||||
if (ignoreCase) name = name.toLowerCase();
|
||||
|
||||
for (GameProfile profile : properties.values()) {
|
||||
if (profile.name == null) continue;
|
||||
|
||||
String n = ignoreCase ? profile.name.toLowerCase() : profile.name;
|
||||
|
||||
if (n.equals(name)) {
|
||||
return profile;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return nameToProfile.get(name);
|
||||
}
|
||||
|
||||
public List<GameProfile> getAllWithPrefix(String prefix, boolean ignoreCase) {
|
||||
@@ -81,7 +77,11 @@ public class GameProfileStorage extends StoredObject {
|
||||
}
|
||||
|
||||
public GameProfile remove(UUID uuid) {
|
||||
return properties.remove(uuid);
|
||||
GameProfile removedProfile = properties.remove(uuid);
|
||||
if (removedProfile != null) {
|
||||
nameToProfile.get(removedProfile.name).remove(removedProfile);
|
||||
}
|
||||
return removedProfile;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+58
-29
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -37,6 +37,7 @@ public class ScoreboardTracker extends StoredObject {
|
||||
private final HashMap<String, Byte> teamColors = new HashMap<>();
|
||||
private final HashSet<String> scoreTeamNames = new HashSet<>();
|
||||
private final HashMap<Byte, String> colorDependentSidebar = new HashMap<>();
|
||||
private final HashMap<String, String> teamNameTagVisibilities = new HashMap<>();
|
||||
private String colorIndependentSidebar;
|
||||
|
||||
public ScoreboardTracker(UserConnection user) {
|
||||
@@ -63,6 +64,7 @@ public class ScoreboardTracker extends StoredObject {
|
||||
teams.remove(team);
|
||||
scoreTeams.remove(team);
|
||||
teamColors.remove(team);
|
||||
teamNameTagVisibilities.remove(team);
|
||||
}
|
||||
|
||||
public boolean teamExists(String team) {
|
||||
@@ -98,6 +100,27 @@ public class ScoreboardTracker extends StoredObject {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public void setTeamNameTagVisibility(String team, String visibility) {
|
||||
teamNameTagVisibilities.put(team, visibility);
|
||||
}
|
||||
|
||||
public String getTeamNameTagVisibility(String team) {
|
||||
return teamNameTagVisibilities.getOrDefault(team, "always");
|
||||
}
|
||||
|
||||
public boolean isNametagHidden(String username) {
|
||||
for (Map.Entry<String, List<String>> entry : teams.entrySet()) {
|
||||
if (entry.getValue().contains(username)) {
|
||||
return "never".equalsIgnoreCase(teamNameTagVisibilities.getOrDefault(entry.getKey(), "always"));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public List<String> getTeamMembers(String team) {
|
||||
return teams.getOrDefault(team, new ArrayList<>());
|
||||
}
|
||||
|
||||
public void addObjective(String name) {
|
||||
objectives.add(name);
|
||||
}
|
||||
@@ -117,37 +140,43 @@ public class ScoreboardTracker extends StoredObject {
|
||||
public String sendTeamForScore(String score) {
|
||||
if (score.length() <= 16) return score;
|
||||
if (scoreTeams.containsKey(score)) return scoreTeams.get(score).name;
|
||||
int l = 16;
|
||||
int i = Math.min(16, score.length() - 16);
|
||||
String name = score.substring(i, i + l);
|
||||
while (scoreTeamNames.contains(name) || teams.containsKey(name)) {
|
||||
i--;
|
||||
while (score.length() - l - i > 16) {
|
||||
l--;
|
||||
if (l < 1) return score;
|
||||
i = Math.min(16, score.length() - l);
|
||||
|
||||
// Find the longest window score[i, i+l) that:
|
||||
// - is not already claimed as a team name
|
||||
// - keeps prefix (score[0,i)) at most 16 chars i <= 16
|
||||
// - keeps suffix (score[i+l, end)) at most 16 chars score.length()-l-i <= 16
|
||||
for (int l = 16; l >= 1; l--) {
|
||||
final int iMax = Math.min(16, score.length() - l);
|
||||
final int iMin = Math.max(0, score.length() - l - 16);
|
||||
for (int i = iMax; i >= iMin; i--) {
|
||||
final String name = score.substring(i, i + l);
|
||||
if (scoreTeamNames.contains(name) || teams.containsKey(name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final String prefix = score.substring(0, i);
|
||||
final String suffix = i + l >= score.length() ? "" : score.substring(i + l);
|
||||
|
||||
final ScoreTeam scoreTeam = new ScoreTeam(name, prefix, suffix);
|
||||
scoreTeams.put(score, scoreTeam);
|
||||
scoreTeamNames.add(name);
|
||||
|
||||
final PacketWrapper teamPacket = PacketWrapper.create(ClientboundPackets1_7_2_5.SET_PLAYER_TEAM, getUser());
|
||||
teamPacket.write(Types.STRING, name);
|
||||
teamPacket.write(Types.BYTE, (byte) 0);
|
||||
teamPacket.write(Types.STRING, "ViaRewind");
|
||||
teamPacket.write(Types.STRING, prefix);
|
||||
teamPacket.write(Types.STRING, suffix);
|
||||
teamPacket.write(Types.BYTE, (byte) 0);
|
||||
teamPacket.write(Types.SHORT, (short) 1);
|
||||
teamPacket.write(Types.STRING, name);
|
||||
teamPacket.send(Protocol1_8To1_7_6_10.class);
|
||||
|
||||
return name;
|
||||
}
|
||||
name = score.substring(i, i + l);
|
||||
}
|
||||
String prefix = score.substring(0, i);
|
||||
String suffix = i + l >= score.length() ? "" : score.substring(i + l);
|
||||
|
||||
ScoreTeam scoreTeam = new ScoreTeam(name, prefix, suffix);
|
||||
scoreTeams.put(score, scoreTeam);
|
||||
scoreTeamNames.add(name);
|
||||
|
||||
PacketWrapper teamPacket = PacketWrapper.create(ClientboundPackets1_7_2_5.SET_PLAYER_TEAM, getUser());
|
||||
teamPacket.write(Types.STRING, name);
|
||||
teamPacket.write(Types.BYTE, (byte) 0);
|
||||
teamPacket.write(Types.STRING, "ViaRewind");
|
||||
teamPacket.write(Types.STRING, prefix);
|
||||
teamPacket.write(Types.STRING, suffix);
|
||||
teamPacket.write(Types.BYTE, (byte) 0);
|
||||
teamPacket.write(Types.SHORT, (short) 1);
|
||||
teamPacket.write(Types.STRING, name);
|
||||
teamPacket.send(Protocol1_8To1_7_6_10.class);
|
||||
|
||||
return name;
|
||||
return score;
|
||||
}
|
||||
|
||||
public String removeTeamForScore(String score) {
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+4
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -35,6 +35,9 @@ public class WorldBorderUpdateTask implements Runnable {
|
||||
public void run() {
|
||||
for (UserConnection connection : Via.getManager().getConnectionManager().getConnections()) {
|
||||
final WorldBorderEmulator worldBorderEmulatorTracker = connection.get(WorldBorderEmulator.class);
|
||||
if (worldBorderEmulatorTracker == null) {
|
||||
continue;
|
||||
}
|
||||
if (!worldBorderEmulatorTracker.isInit()) continue;
|
||||
|
||||
final PlayerSessionStorage playerSession = connection.get(PlayerSessionStorage.class);
|
||||
|
||||
+11
-5
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -26,14 +26,17 @@ import com.viaversion.viarewind.protocol.v1_9to1_8.rewriter.PlayerPacketRewriter
|
||||
import com.viaversion.viarewind.protocol.v1_9to1_8.rewriter.WorldPacketRewriter1_9;
|
||||
import com.viaversion.viarewind.protocol.v1_9to1_8.storage.BlockPlaceDestroyTracker;
|
||||
import com.viaversion.viarewind.protocol.v1_9to1_8.storage.BossBarStorage;
|
||||
import com.viaversion.viarewind.protocol.v1_9to1_8.storage.CommandBlockStateStorage;
|
||||
import com.viaversion.viarewind.protocol.v1_9to1_8.storage.CooldownStorage;
|
||||
import com.viaversion.viarewind.protocol.v1_9to1_8.storage.EntityTracker1_9;
|
||||
import com.viaversion.viarewind.protocol.v1_9to1_8.storage.LevitationStorage;
|
||||
import com.viaversion.viarewind.protocol.v1_9to1_8.storage.PlayerPositionTracker;
|
||||
import com.viaversion.viarewind.protocol.v1_9to1_8.storage.LastTitle;
|
||||
import com.viaversion.viarewind.protocol.v1_9to1_8.storage.WindowTracker;
|
||||
import com.viaversion.viarewind.protocol.v1_9to1_8.task.CooldownIndicatorTask;
|
||||
import com.viaversion.viarewind.protocol.v1_9to1_8.task.LevitationUpdateTask;
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.api.connection.ProtocolStorables;
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.api.minecraft.ClientWorld;
|
||||
import com.viaversion.viaversion.api.platform.providers.ViaProviders;
|
||||
@@ -51,7 +54,7 @@ public class Protocol1_9To1_8 extends BackwardsProtocol<ClientboundPackets1_9, C
|
||||
public static final ValueTransformer<Double, Integer> DOUBLE_TO_INT_TIMES_32 = new ValueTransformer<>(Types.INT) {
|
||||
@Override
|
||||
public Integer transform(PacketWrapper wrapper, Double inputValue) {
|
||||
return (int) (inputValue * 32.0D);
|
||||
return (int) Math.round(inputValue * 32.0D);
|
||||
}
|
||||
};
|
||||
public static final ValueTransformer<Float, Byte> DEGREES_TO_ANGLE = new ValueTransformer<>(Types.BYTE) {
|
||||
@@ -61,7 +64,7 @@ public class Protocol1_9To1_8 extends BackwardsProtocol<ClientboundPackets1_9, C
|
||||
}
|
||||
};
|
||||
|
||||
public static final RewindMappingData MAPPINGS = new RewindMappingData("1.9.4", "1.8");
|
||||
public static final RewindMappingData MAPPINGS = new RewindMappingData("1.9", "1.8");
|
||||
|
||||
private final BlockItemPacketRewriter1_9 itemRewriter = new BlockItemPacketRewriter1_9(this);
|
||||
private final EntityPacketRewriter1_9 entityRewriter = new EntityPacketRewriter1_9(this);
|
||||
@@ -80,15 +83,18 @@ public class Protocol1_9To1_8 extends BackwardsProtocol<ClientboundPackets1_9, C
|
||||
|
||||
@Override
|
||||
public void init(UserConnection connection) {
|
||||
connection.addEntityTracker(this.getClass(), new EntityTracker1_9(connection));
|
||||
connection.addClientWorld(this.getClass(), new ClientWorld());
|
||||
final ProtocolStorables storables = connection.storables(this);
|
||||
storables.setEntityTracker(new EntityTracker1_9(connection));
|
||||
storables.setClientWorld(new ClientWorld());
|
||||
|
||||
connection.put(new WindowTracker(connection));
|
||||
connection.put(new LevitationStorage());
|
||||
connection.put(new PlayerPositionTracker());
|
||||
connection.put(new CooldownStorage());
|
||||
connection.put(new LastTitle());
|
||||
connection.put(new BlockPlaceDestroyTracker());
|
||||
connection.put(new BossBarStorage(connection));
|
||||
connection.put(new CommandBlockStateStorage());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+66
-21
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -18,21 +18,23 @@
|
||||
package com.viaversion.viarewind.protocol.v1_9to1_8.cooldown;
|
||||
|
||||
import com.viaversion.viarewind.protocol.v1_9to1_8.Protocol1_9To1_8;
|
||||
import com.viaversion.viarewind.protocol.v1_9to1_8.storage.LastTitle;
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
|
||||
import com.viaversion.viaversion.api.type.Types;
|
||||
import com.viaversion.viaversion.libs.gson.JsonPrimitive;
|
||||
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_8;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class TitleCooldownVisualization implements CooldownVisualization {
|
||||
|
||||
private static final int ACTION_SET_TITLE = 0;
|
||||
private static final int ACTION_SET_SUBTITLE = 1;
|
||||
private static final int ACTION_SET_TIMES_AND_DISPLAY = 2;
|
||||
private static final int ACTION_HIDE = 3;
|
||||
public static final int ACTION_SET_TITLE = 0;
|
||||
public static final int ACTION_SET_SUBTITLE = 1;
|
||||
public static final int ACTION_SET_TIMES_AND_DISPLAY = 2;
|
||||
public static final int ACTION_HIDE = 3;
|
||||
public static final int ACTION_RESET = 4;
|
||||
|
||||
private final UserConnection user;
|
||||
private boolean visible;
|
||||
|
||||
public TitleCooldownVisualization(UserConnection user) {
|
||||
this.user = user;
|
||||
@@ -40,28 +42,71 @@ public class TitleCooldownVisualization implements CooldownVisualization {
|
||||
|
||||
@Override
|
||||
public void show(double progress) throws Exception {
|
||||
final String text = CooldownVisualization.buildProgressText("˙", progress);
|
||||
final LastTitle title = this.user.get(LastTitle.class);
|
||||
if (this.visible && title.isVisible()) {
|
||||
this.restoreTitle(title);
|
||||
return;
|
||||
}
|
||||
|
||||
sendTitlePacket(ACTION_SET_TITLE, wrapper -> wrapper.write(Types.COMPONENT, new JsonPrimitive("")));
|
||||
sendTitlePacket(ACTION_SET_SUBTITLE, wrapper -> wrapper.write(Types.COMPONENT, new JsonPrimitive(text)));
|
||||
sendTitlePacket(ACTION_SET_TIMES_AND_DISPLAY, wrapper -> {
|
||||
wrapper.write(Types.INT, 0);
|
||||
wrapper.write(Types.INT, 2);
|
||||
wrapper.write(Types.INT, 5);
|
||||
});
|
||||
final PacketWrapper setTitle = PacketWrapper.create(ClientboundPackets1_8.SET_TITLES, user);
|
||||
setTitle.write(Types.VAR_INT, ACTION_SET_TITLE);
|
||||
setTitle.write(Types.COMPONENT, new JsonPrimitive(""));
|
||||
setTitle.send(Protocol1_9To1_8.class);
|
||||
|
||||
final PacketWrapper setSubtitle = PacketWrapper.create(ClientboundPackets1_8.SET_TITLES, user);
|
||||
setSubtitle.write(Types.VAR_INT, ACTION_SET_SUBTITLE);
|
||||
setSubtitle.write(Types.COMPONENT, new JsonPrimitive(CooldownVisualization.buildProgressText("˙", progress)));
|
||||
setSubtitle.send(Protocol1_9To1_8.class);
|
||||
|
||||
final PacketWrapper setTitleTimes = PacketWrapper.create(ClientboundPackets1_8.SET_TITLES, user);
|
||||
setTitleTimes.write(Types.VAR_INT, ACTION_SET_TIMES_AND_DISPLAY);
|
||||
setTitleTimes.write(Types.INT, 0);
|
||||
setTitleTimes.write(Types.INT, 2);
|
||||
setTitleTimes.write(Types.INT, 5);
|
||||
setTitleTimes.send(Protocol1_9To1_8.class);
|
||||
this.visible = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hide() throws Exception {
|
||||
sendTitlePacket(ACTION_HIDE, wrapper -> {
|
||||
});
|
||||
if (!this.visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
final LastTitle title = this.user.get(LastTitle.class);
|
||||
if (title.isVisible()) {
|
||||
this.restoreTitle(title);
|
||||
return;
|
||||
}
|
||||
|
||||
final PacketWrapper hideTitle = PacketWrapper.create(ClientboundPackets1_8.SET_TITLES, user);
|
||||
hideTitle.write(Types.VAR_INT, ACTION_HIDE);
|
||||
hideTitle.send(Protocol1_9To1_8.class);
|
||||
this.visible = false;
|
||||
}
|
||||
|
||||
private void sendTitlePacket(int action, Consumer<PacketWrapper> writer) {
|
||||
final PacketWrapper title = PacketWrapper.create(ClientboundPackets1_8.SET_TITLES, user);
|
||||
title.write(Types.VAR_INT, action);
|
||||
writer.accept(title);
|
||||
title.scheduleSend(Protocol1_9To1_8.class);
|
||||
private void restoreTitle(final LastTitle title) {
|
||||
final PacketWrapper setTitleTimes = PacketWrapper.create(ClientboundPackets1_8.SET_TITLES, user);
|
||||
setTitleTimes.write(Types.VAR_INT, ACTION_SET_TIMES_AND_DISPLAY);
|
||||
final int[] times = title.remainingTimes();
|
||||
setTitleTimes.write(Types.INT, times[0]);
|
||||
setTitleTimes.write(Types.INT, times[1]);
|
||||
setTitleTimes.write(Types.INT, times[2]);
|
||||
setTitleTimes.send(Protocol1_9To1_8.class);
|
||||
|
||||
if (title.subtitle() != null) {
|
||||
final PacketWrapper setSubtitle = PacketWrapper.create(ClientboundPackets1_8.SET_TITLES, user);
|
||||
setSubtitle.write(Types.VAR_INT, ACTION_SET_SUBTITLE);
|
||||
setSubtitle.write(Types.COMPONENT, title.subtitle());
|
||||
setSubtitle.send(Protocol1_9To1_8.class);
|
||||
}
|
||||
|
||||
final PacketWrapper setTitle = PacketWrapper.create(ClientboundPackets1_8.SET_TITLES, user);
|
||||
setTitle.write(Types.VAR_INT, ACTION_SET_TITLE);
|
||||
setTitle.write(Types.COMPONENT, title.title());
|
||||
setTitle.send(Protocol1_9To1_8.class);
|
||||
|
||||
this.visible = false;
|
||||
}
|
||||
|
||||
}
|
||||
+165
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.viaversion.viarewind.protocol.v1_9to1_8.data;
|
||||
|
||||
import com.viaversion.nbt.tag.CompoundTag;
|
||||
import com.viaversion.nbt.tag.NumberTag;
|
||||
import com.viaversion.nbt.tag.StringTag;
|
||||
|
||||
public final class CommandBlockState {
|
||||
|
||||
public static final int COMMAND_BLOCK_COMMAND_LIMIT = 32500;
|
||||
|
||||
private static final String IMPULSE = "IMPULSE";
|
||||
private static final String REPEAT = "REPEAT";
|
||||
private static final String CHAIN = "CHAIN";
|
||||
private static final String CONDITIONAL = "CONDITIONAL";
|
||||
private static final String UNCONDITIONAL = "UNCONDITIONAL";
|
||||
private static final String ALWAYS_ACTIVE = "ALWAYSACTIVE";
|
||||
private static final String REDSTONE = "REDSTONE";
|
||||
|
||||
private CommandBlockState() {
|
||||
}
|
||||
|
||||
public static boolean isCommandBlock(final int blockState) {
|
||||
return isImpulse(blockState) || isRepeat(blockState) || isChain(blockState);
|
||||
}
|
||||
|
||||
public static void decorateCommand(final CompoundTag tag, final int blockState) {
|
||||
if (tag == null || !isCommandBlock(blockState)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final StringTag commandTag = tag.getStringTag("Command");
|
||||
if (commandTag == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Mode mode = mode(blockState);
|
||||
final boolean conditional = (blockState & 8) != 0;
|
||||
final boolean automatic = booleanTag(tag, "auto");
|
||||
if (mode == Mode.REDSTONE && !conditional && !automatic) {
|
||||
return;
|
||||
}
|
||||
|
||||
final String prefix = mode.prefix + ' ' + (conditional ? CONDITIONAL : UNCONDITIONAL) + ' ' + (automatic ? ALWAYS_ACTIVE : REDSTONE) + ' ';
|
||||
final String command = commandTag.getValue();
|
||||
if (!parseDecoratedCommand(command).prefixed() && prefix.length() + command.length() <= COMMAND_BLOCK_COMMAND_LIMIT) {
|
||||
commandTag.setValue(prefix + command);
|
||||
}
|
||||
}
|
||||
|
||||
public static ParsedCommand parseDecoratedCommand(final String command) {
|
||||
final int first = command.indexOf(' ');
|
||||
if (first == -1) {
|
||||
return ParsedCommand.defaultState(command);
|
||||
}
|
||||
final int second = command.indexOf(' ', first + 1);
|
||||
if (second == -1) {
|
||||
return ParsedCommand.defaultState(command);
|
||||
}
|
||||
final int third = command.indexOf(' ', second + 1);
|
||||
if (third == -1) {
|
||||
return ParsedCommand.defaultState(command);
|
||||
}
|
||||
|
||||
final Mode mode = Mode.fromPrefix(command.substring(0, first));
|
||||
if (mode == null) {
|
||||
return ParsedCommand.defaultState(command);
|
||||
}
|
||||
|
||||
final String conditionalToken = command.substring(first + 1, second);
|
||||
final boolean conditional;
|
||||
if (CONDITIONAL.equalsIgnoreCase(conditionalToken)) {
|
||||
conditional = true;
|
||||
} else if (UNCONDITIONAL.equalsIgnoreCase(conditionalToken)) {
|
||||
conditional = false;
|
||||
} else {
|
||||
return ParsedCommand.defaultState(command);
|
||||
}
|
||||
|
||||
final String automaticToken = command.substring(second + 1, third);
|
||||
final boolean automatic;
|
||||
if (ALWAYS_ACTIVE.equalsIgnoreCase(automaticToken)) {
|
||||
automatic = true;
|
||||
} else if (REDSTONE.equalsIgnoreCase(automaticToken)) {
|
||||
automatic = false;
|
||||
} else {
|
||||
return ParsedCommand.defaultState(command);
|
||||
}
|
||||
|
||||
return new ParsedCommand(command.substring(third + 1), mode.serverName, conditional, automatic, true);
|
||||
}
|
||||
|
||||
private static boolean booleanTag(final CompoundTag tag, final String key) {
|
||||
final NumberTag numberTag = tag.getNumberTag(key);
|
||||
return numberTag != null && numberTag.asByte() != 0;
|
||||
}
|
||||
|
||||
private static Mode mode(final int blockState) {
|
||||
if (isRepeat(blockState)) {
|
||||
return Mode.AUTO;
|
||||
}
|
||||
if (isChain(blockState)) {
|
||||
return Mode.SEQUENCE;
|
||||
}
|
||||
return Mode.REDSTONE;
|
||||
}
|
||||
|
||||
private static boolean isImpulse(final int blockState) {
|
||||
return blockState >= 2192 && blockState <= 2207;
|
||||
}
|
||||
|
||||
private static boolean isRepeat(final int blockState) {
|
||||
return blockState >= 3360 && blockState <= 3375;
|
||||
}
|
||||
|
||||
private static boolean isChain(final int blockState) {
|
||||
return blockState >= 3376 && blockState <= 3391;
|
||||
}
|
||||
|
||||
public record ParsedCommand(String command, String mode, boolean conditional, boolean automatic, boolean prefixed) {
|
||||
|
||||
private static ParsedCommand defaultState(final String command) {
|
||||
return new ParsedCommand(command, Mode.REDSTONE.serverName, false, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
private enum Mode {
|
||||
REDSTONE(IMPULSE, "REDSTONE"),
|
||||
AUTO(REPEAT, "AUTO"),
|
||||
SEQUENCE(CHAIN, "SEQUENCE");
|
||||
|
||||
private final String prefix;
|
||||
private final String serverName;
|
||||
|
||||
Mode(final String prefix, final String serverName) {
|
||||
this.prefix = prefix;
|
||||
this.serverName = serverName;
|
||||
}
|
||||
|
||||
private static Mode fromPrefix(final String prefix) {
|
||||
for (final Mode mode : values()) {
|
||||
if (mode.prefix.equalsIgnoreCase(prefix)) {
|
||||
return mode;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+101
-5
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -19,6 +19,7 @@ package com.viaversion.viarewind.protocol.v1_9to1_8.rewriter;
|
||||
|
||||
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.StringTag;
|
||||
import com.viaversion.nbt.tag.Tag;
|
||||
@@ -26,8 +27,11 @@ import com.viaversion.viabackwards.api.rewriters.LegacyEnchantmentRewriter;
|
||||
import com.viaversion.viarewind.api.rewriter.VRBlockItemRewriter;
|
||||
import com.viaversion.viarewind.protocol.v1_9to1_8.Protocol1_9To1_8;
|
||||
import com.viaversion.viarewind.protocol.v1_9to1_8.data.PotionIdMappings1_8;
|
||||
import com.viaversion.viarewind.protocol.v1_9to1_8.storage.CommandBlockStateStorage;
|
||||
import com.viaversion.viarewind.protocol.v1_9to1_8.storage.WindowTracker;
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.api.minecraft.BlockChangeRecord;
|
||||
import com.viaversion.viaversion.api.minecraft.BlockPosition;
|
||||
import com.viaversion.viaversion.api.minecraft.item.Item;
|
||||
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
|
||||
import com.viaversion.viaversion.api.type.Types;
|
||||
@@ -59,8 +63,26 @@ public class BlockItemPacketRewriter1_9 extends VRBlockItemRewriter<ClientboundP
|
||||
|
||||
@Override
|
||||
protected void registerPackets() {
|
||||
registerBlockChange(ClientboundPackets1_9.BLOCK_UPDATE);
|
||||
registerMultiBlockChange(ClientboundPackets1_9.CHUNK_BLOCKS_UPDATE);
|
||||
protocol.registerClientbound(ClientboundPackets1_9.BLOCK_UPDATE, wrapper -> {
|
||||
final BlockPosition position = wrapper.passthrough(Types.BLOCK_POSITION1_8);
|
||||
final int blockState = wrapper.passthrough(Types.VAR_INT);
|
||||
wrapper.user().get(CommandBlockStateStorage.class).storeOrRemove(position, blockState);
|
||||
wrapper.set(Types.VAR_INT, 0, handleBlockId(blockState));
|
||||
});
|
||||
|
||||
protocol.registerClientbound(ClientboundPackets1_9.CHUNK_BLOCKS_UPDATE, wrapper -> {
|
||||
final int chunkX = wrapper.passthrough(Types.INT);
|
||||
final int chunkZ = wrapper.passthrough(Types.INT);
|
||||
final BlockChangeRecord[] records = wrapper.passthrough(Types.BLOCK_CHANGE_ARRAY);
|
||||
final CommandBlockStateStorage storage = wrapper.user().get(CommandBlockStateStorage.class);
|
||||
|
||||
for (BlockChangeRecord record : records) {
|
||||
final int blockState = record.getBlockId();
|
||||
final BlockPosition position = new BlockPosition((chunkX << 4) + record.getSectionX(), record.getY(), (chunkZ << 4) + record.getSectionZ());
|
||||
storage.storeOrRemove(position, blockState);
|
||||
record.setBlockId(handleBlockId(blockState));
|
||||
}
|
||||
});
|
||||
registerSetCreativeModeSlot(ServerboundPackets1_8.SET_CREATIVE_MODE_SLOT);
|
||||
|
||||
protocol.registerClientbound(ClientboundPackets1_9.CONTAINER_CLOSE, wrapper -> {
|
||||
@@ -78,8 +100,12 @@ public class BlockItemPacketRewriter1_9 extends VRBlockItemRewriter<ClientboundP
|
||||
protocol.registerClientbound(ClientboundPackets1_9.OPEN_SCREEN, wrapper -> {
|
||||
final short windowId = wrapper.passthrough(Types.UNSIGNED_BYTE);
|
||||
final String windowType = wrapper.passthrough(Types.STRING);
|
||||
wrapper.passthrough(Types.COMPONENT); // title
|
||||
final short slotCount = wrapper.passthrough(Types.UNSIGNED_BYTE);
|
||||
|
||||
wrapper.user().get(WindowTracker.class).put(windowId, windowType);
|
||||
final WindowTracker tracker = wrapper.user().get(WindowTracker.class);
|
||||
tracker.put(windowId, windowType);
|
||||
tracker.openWindow(windowId, windowType, slotCount);
|
||||
});
|
||||
|
||||
protocol.registerClientbound(ClientboundPackets1_9.CONTAINER_SET_CONTENT, wrapper -> {
|
||||
@@ -115,10 +141,49 @@ public class BlockItemPacketRewriter1_9 extends VRBlockItemRewriter<ClientboundP
|
||||
final Item item = wrapper.passthrough(Types.ITEM1_8);
|
||||
|
||||
handleItemToClient(wrapper.user(), item);
|
||||
if (windowId == -2) {
|
||||
// 1.8 has no window -2 (set a player-inv slot by raw index, ignoring the open container) — retarget it.
|
||||
final WindowTracker tracker = wrapper.user().get(WindowTracker.class);
|
||||
final short openWindow = tracker.openWindowId();
|
||||
if (openWindow != 0) {
|
||||
// Foreign container open: 1.8 only applies player-inv changes through it (main=size.., hotbar=size+27..).
|
||||
final int size = tracker.openWindowSize();
|
||||
final int containerSlot;
|
||||
if (slot >= 0 && slot <= 8) {
|
||||
containerSlot = size + 27 + slot;
|
||||
} else if (slot >= 9 && slot <= 35) {
|
||||
containerSlot = size + slot - 9;
|
||||
} else { // armor/offhand: no slot in a foreign container
|
||||
wrapper.cancel();
|
||||
return;
|
||||
}
|
||||
wrapper.set(Types.BYTE, 0, (byte) openWindow);
|
||||
wrapper.set(Types.SHORT, 0, (short) containerSlot);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise window 0 with the menu slot.
|
||||
final int windowSlot;
|
||||
if (slot >= 0 && slot <= 8) {
|
||||
windowSlot = slot + 36;
|
||||
} else if (slot >= 9 && slot <= 35) {
|
||||
windowSlot = slot;
|
||||
} else if (slot >= 36 && slot <= 39) {
|
||||
windowSlot = 44 - slot;
|
||||
} else { // offhand/body/saddle: no 1.8 equivalent
|
||||
wrapper.cancel();
|
||||
return;
|
||||
}
|
||||
wrapper.set(Types.BYTE, 0, (byte) 0);
|
||||
wrapper.set(Types.SHORT, 0, (short) windowSlot);
|
||||
return;
|
||||
}
|
||||
|
||||
if (windowId == 0 && slot == 45) {
|
||||
wrapper.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
final WindowTracker windowTracker = wrapper.user().get(WindowTracker.class);
|
||||
final String windowType = windowTracker.get(windowId);
|
||||
if (windowType != null && windowType.equalsIgnoreCase("minecraft:brewing_stand")) {
|
||||
@@ -194,6 +259,7 @@ public class BlockItemPacketRewriter1_9 extends VRBlockItemRewriter<ClientboundP
|
||||
@Override
|
||||
public Item handleItemToClient(UserConnection connection, Item item) {
|
||||
if (item == null) return null;
|
||||
final int originalId = item.identifier();
|
||||
super.handleItemToClient(connection, item);
|
||||
|
||||
CompoundTag tag = item.tag();
|
||||
@@ -280,6 +346,32 @@ public class BlockItemPacketRewriter1_9 extends VRBlockItemRewriter<ClientboundP
|
||||
});
|
||||
}
|
||||
|
||||
// Colors the fake leather armor for an elytra gray
|
||||
if (originalId == 443) {
|
||||
if (tag == null) {
|
||||
item.setTag(tag = new CompoundTag());
|
||||
}
|
||||
CompoundTag display = tag.getCompoundTag("display");
|
||||
if (display == null) {
|
||||
tag.put("display", display = new CompoundTag());
|
||||
}
|
||||
display.put("color", new IntTag(0x737373)); // Gray
|
||||
tag.put(nbtTagName() + "|noDisplay", new ByteTag(true));
|
||||
}
|
||||
|
||||
// Makes the fake banner for a shield brown if it has no banner patterns
|
||||
if (originalId == 442) {
|
||||
final CompoundTag blockEntityTag = tag == null ? null : tag.getCompoundTag("BlockEntityTag");
|
||||
final ListTag<CompoundTag> patterns = blockEntityTag == null ? null : blockEntityTag.getListTag("Patterns", CompoundTag.class);
|
||||
if (patterns == null || patterns.isEmpty()) {
|
||||
item.setData((short) 3); // Brown
|
||||
if (tag == null) {
|
||||
item.setTag(tag = new CompoundTag());
|
||||
}
|
||||
tag.put(nbtTagName() + "|noData", new ByteTag(true));
|
||||
}
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
@@ -304,7 +396,8 @@ public class BlockItemPacketRewriter1_9 extends VRBlockItemRewriter<ClientboundP
|
||||
item.setData((short) 0);
|
||||
}
|
||||
|
||||
if (item.identifier() == 373 && (tag == null || !tag.contains("Potion"))) { // Potions
|
||||
if (item.identifier() == 373) { // Potions
|
||||
// Restore the splash id even when a Potion tag is present (e.g. items re-sent by a creative mode client)
|
||||
if (item.data() >= 16384) {
|
||||
item.setIdentifier(438);
|
||||
item.setData((short) (item.data() - 8192));
|
||||
@@ -322,6 +415,9 @@ public class BlockItemPacketRewriter1_9 extends VRBlockItemRewriter<ClientboundP
|
||||
if (tag == null) {
|
||||
return item;
|
||||
}
|
||||
if (tag.remove(nbtTagName() + "|noData") != null) {
|
||||
item.setData((short) 0);
|
||||
}
|
||||
final Tag noDisplayTag = tag.remove(nbtTagName() + "|noDisplay");
|
||||
if (noDisplayTag != null) {
|
||||
tag.remove("display");
|
||||
|
||||
+108
-22
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -68,7 +68,7 @@ public class EntityPacketRewriter1_9 extends VREntityRewriter<ClientboundPackets
|
||||
final int dimension = wrapper.passthrough(Types.BYTE);
|
||||
|
||||
trackPlayer(wrapper.user(), entityId);
|
||||
final ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_9To1_8.class);
|
||||
final ClientWorld clientWorld = wrapper.user().storables(protocol).clientWorld();
|
||||
clientWorld.setEnvironment(dimension);
|
||||
});
|
||||
protocol.registerClientbound(ClientboundPackets1_9.SET_ENTITY_DATA, wrapper -> {
|
||||
@@ -134,11 +134,24 @@ public class EntityPacketRewriter1_9 extends VREntityRewriter<ClientboundPackets
|
||||
}
|
||||
}
|
||||
|
||||
if (data > 0) {
|
||||
wrapper.passthrough(Types.SHORT); // Velocity x
|
||||
wrapper.passthrough(Types.SHORT); // Velocity y
|
||||
wrapper.passthrough(Types.SHORT); // Velocity z
|
||||
} else {
|
||||
if (type.is(EntityTypes1_9.EntityType.POTION) && data > 0) {
|
||||
// 1.8 clients read the potion type from the object data, but newer versions only
|
||||
// send it in the entity data - the next packet. Held until then, see handleEntityData
|
||||
wrapper.cancel();
|
||||
final int x = wrapper.get(Types.INT, 0);
|
||||
final int y = wrapper.get(Types.INT, 1);
|
||||
final int z = wrapper.get(Types.INT, 2);
|
||||
final byte pitch = wrapper.get(Types.BYTE, 1);
|
||||
final byte yaw = wrapper.get(Types.BYTE, 2);
|
||||
final short velocityX = wrapper.passthrough(Types.SHORT);
|
||||
final short velocityY = wrapper.passthrough(Types.SHORT);
|
||||
final short velocityZ = wrapper.passthrough(Types.SHORT);
|
||||
final EntityTracker1_9 tracker = tracker(wrapper.user());
|
||||
tracker.getPendingPotions().put(entityId, new EntityTracker1_9.PendingPotionEntity(x, y, z, pitch, yaw, velocityX, velocityY, velocityZ));
|
||||
return;
|
||||
}
|
||||
|
||||
if (data <= 0) {
|
||||
final short velocityX = wrapper.read(Types.SHORT);
|
||||
final short velocityY = wrapper.read(Types.SHORT);
|
||||
final short velocityZ = wrapper.read(Types.SHORT);
|
||||
@@ -164,7 +177,7 @@ public class EntityPacketRewriter1_9 extends VREntityRewriter<ClientboundPackets
|
||||
map(Types.SHORT); // Count
|
||||
handler(wrapper -> {
|
||||
final int entityId = wrapper.get(Types.VAR_INT, 0);
|
||||
wrapper.user().getEntityTracker(Protocol1_9To1_8.class).addEntity(entityId, EntityTypes1_9.EntityType.EXPERIENCE_ORB);
|
||||
wrapper.user().getEntityTracker(protocol).addEntity(entityId, EntityTypes1_9.EntityType.EXPERIENCE_ORB);
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -179,7 +192,7 @@ public class EntityPacketRewriter1_9 extends VREntityRewriter<ClientboundPackets
|
||||
map(Types.DOUBLE, Protocol1_9To1_8.DOUBLE_TO_INT_TIMES_32); // Z
|
||||
handler(wrapper -> {
|
||||
final int entityId = wrapper.get(Types.VAR_INT, 0);
|
||||
wrapper.user().getEntityTracker(Protocol1_9To1_8.class).addEntity(entityId, EntityTypes1_9.EntityType.LIGHTNING_BOLT);
|
||||
wrapper.user().getEntityTracker(protocol).addEntity(entityId, EntityTypes1_9.EntityType.LIGHTNING_BOLT);
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -216,7 +229,7 @@ public class EntityPacketRewriter1_9 extends VREntityRewriter<ClientboundPackets
|
||||
map(Types.BYTE, Types.UNSIGNED_BYTE); // Direction
|
||||
handler(wrapper -> {
|
||||
final int entityId = wrapper.get(Types.VAR_INT, 0);
|
||||
wrapper.user().getEntityTracker(Protocol1_9To1_8.class).addEntity(entityId, EntityTypes1_9.EntityType.PAINTING);
|
||||
wrapper.user().getEntityTracker(protocol).addEntity(entityId, EntityTypes1_9.EntityType.PAINTING);
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -259,7 +272,7 @@ public class EntityPacketRewriter1_9 extends VREntityRewriter<ClientboundPackets
|
||||
final int deltaY = wrapper.read(Types.SHORT);
|
||||
final int deltaZ = wrapper.read(Types.SHORT);
|
||||
|
||||
final Vector[] moves = RelativeMoveUtil.calculateRelativeMoves(wrapper.user(), entityId, deltaX, deltaY, deltaZ);
|
||||
final Vector[] moves = RelativeMoveUtil.calculateRelativeMoves(tracker(wrapper.user()), entityId, deltaX, deltaY, deltaZ);
|
||||
|
||||
wrapper.write(Types.BYTE, (byte) moves[0].blockX());
|
||||
wrapper.write(Types.BYTE, (byte) moves[0].blockY());
|
||||
@@ -285,7 +298,7 @@ public class EntityPacketRewriter1_9 extends VREntityRewriter<ClientboundPackets
|
||||
final int deltaY = wrapper.read(Types.SHORT);
|
||||
final int deltaZ = wrapper.read(Types.SHORT);
|
||||
|
||||
final Vector[] moves = RelativeMoveUtil.calculateRelativeMoves(wrapper.user(), entityId, deltaX, deltaY, deltaZ);
|
||||
final Vector[] moves = RelativeMoveUtil.calculateRelativeMoves(tracker(wrapper.user()), entityId, deltaX, deltaY, deltaZ);
|
||||
|
||||
wrapper.write(Types.BYTE, (byte) moves[0].blockX());
|
||||
wrapper.write(Types.BYTE, (byte) moves[0].blockY());
|
||||
@@ -295,7 +308,7 @@ public class EntityPacketRewriter1_9 extends VREntityRewriter<ClientboundPackets
|
||||
final byte pitch = wrapper.passthrough(Types.BYTE);
|
||||
final boolean onGround = wrapper.passthrough(Types.BOOLEAN);
|
||||
|
||||
com.viaversion.viaversion.api.minecraft.entities.EntityType type = wrapper.user().getEntityTracker(Protocol1_9To1_8.class).entityType(entityId);
|
||||
com.viaversion.viaversion.api.minecraft.entities.EntityType type = wrapper.user().getEntityTracker(protocol).entityType(entityId);
|
||||
if (type == EntityTypes1_9.EntityType.BOAT) {
|
||||
yaw -= 64;
|
||||
wrapper.set(Types.BYTE, 3, yaw);
|
||||
@@ -317,7 +330,7 @@ public class EntityPacketRewriter1_9 extends VREntityRewriter<ClientboundPackets
|
||||
|
||||
protocol.registerClientbound(ClientboundPackets1_9.MOVE_ENTITY_ROT, wrapper -> {
|
||||
final int entityId = wrapper.passthrough(Types.VAR_INT);
|
||||
final com.viaversion.viaversion.api.minecraft.entities.EntityType type = wrapper.user().getEntityTracker(Protocol1_9To1_8.class).entityType(entityId);
|
||||
final com.viaversion.viaversion.api.minecraft.entities.EntityType type = wrapper.user().getEntityTracker(protocol).entityType(entityId);
|
||||
if (type == EntityTypes1_9.EntityType.BOAT) {
|
||||
byte yaw = wrapper.read(Types.BYTE);
|
||||
yaw -= 64;
|
||||
@@ -329,7 +342,7 @@ public class EntityPacketRewriter1_9 extends VREntityRewriter<ClientboundPackets
|
||||
@Override
|
||||
public void register() {
|
||||
handler(wrapper -> {
|
||||
final EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_9To1_8.class);
|
||||
final EntityTracker1_9 tracker = wrapper.user().getEntityTracker(protocol);
|
||||
final Integer vehicle = tracker.getVehicle(tracker.clientEntityId());
|
||||
if (vehicle == null) {
|
||||
wrapper.cancel();
|
||||
@@ -360,7 +373,7 @@ public class EntityPacketRewriter1_9 extends VREntityRewriter<ClientboundPackets
|
||||
}
|
||||
|
||||
final int entityId = wrapper.get(Types.VAR_INT, 0);
|
||||
final EntityType type = wrapper.user().getEntityTracker(Protocol1_9To1_8.class).entityType(entityId);
|
||||
final EntityType type = wrapper.user().getEntityTracker(protocol).entityType(entityId);
|
||||
if (type == EntityTypes1_9.EntityType.BOAT) {
|
||||
byte yaw = wrapper.get(Types.BYTE, 0);
|
||||
yaw -= 64;
|
||||
@@ -379,7 +392,7 @@ public class EntityPacketRewriter1_9 extends VREntityRewriter<ClientboundPackets
|
||||
if (effectId > 23) { // Throw away new effects
|
||||
wrapper.cancel();
|
||||
}
|
||||
final EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_9To1_8.class);
|
||||
final EntityTracker1_9 tracker = wrapper.user().getEntityTracker(protocol);
|
||||
if (effectId == 25 && entityId == tracker.clientEntityId()) {
|
||||
wrapper.user().get(LevitationStorage.class).setActive(false);
|
||||
}
|
||||
@@ -416,7 +429,7 @@ public class EntityPacketRewriter1_9 extends VREntityRewriter<ClientboundPackets
|
||||
protocol.registerClientbound(ClientboundPackets1_9.SET_PASSENGERS, null, wrapper -> {
|
||||
wrapper.cancel();
|
||||
|
||||
final EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_9To1_8.class);
|
||||
final EntityTracker1_9 tracker = wrapper.user().getEntityTracker(protocol);
|
||||
final int vehicle = wrapper.read(Types.VAR_INT);
|
||||
final IntList oldPassengers = tracker.getPassengers(vehicle);
|
||||
|
||||
@@ -444,6 +457,19 @@ public class EntityPacketRewriter1_9 extends VREntityRewriter<ClientboundPackets
|
||||
}
|
||||
});
|
||||
|
||||
protocol.registerClientbound(ClientboundPackets1_9.SET_ENTITY_MOTION, wrapper -> {
|
||||
final int entityId = wrapper.passthrough(Types.VAR_INT);
|
||||
final EntityTracker1_9 tracker = tracker(wrapper.user());
|
||||
final EntityTracker1_9.PendingPotionEntity pending = tracker.getPendingPotions().get(entityId);
|
||||
if (pending != null) {
|
||||
wrapper.cancel();
|
||||
final short velocityX = wrapper.read(Types.SHORT);
|
||||
final short velocityY = wrapper.read(Types.SHORT);
|
||||
final short velocityZ = wrapper.read(Types.SHORT);
|
||||
tracker.getPendingPotions().put(entityId, pending.withVelocity(velocityX, velocityY, velocityZ));
|
||||
}
|
||||
});
|
||||
|
||||
protocol.registerClientbound(ClientboundPackets1_9.TELEPORT_ENTITY, new PacketHandlers() {
|
||||
@Override
|
||||
public void register() {
|
||||
@@ -457,7 +483,19 @@ public class EntityPacketRewriter1_9 extends VREntityRewriter<ClientboundPackets
|
||||
handler(wrapper -> {
|
||||
final int entityId = wrapper.get(Types.VAR_INT, 0);
|
||||
|
||||
final EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_9To1_8.class);
|
||||
final EntityTracker1_9 tracker = wrapper.user().getEntityTracker(protocol);
|
||||
final EntityTracker1_9.PendingPotionEntity pending = tracker.getPendingPotions().get(entityId);
|
||||
if (pending != null) {
|
||||
wrapper.cancel();
|
||||
final int x = wrapper.get(Types.INT, 0);
|
||||
final int y = wrapper.get(Types.INT, 1);
|
||||
final int z = wrapper.get(Types.INT, 2);
|
||||
final byte yaw = wrapper.get(Types.BYTE, 0);
|
||||
final byte pitch = wrapper.get(Types.BYTE, 1);
|
||||
tracker.getPendingPotions().put(entityId, pending.withPosition(x, y, z, pitch, yaw));
|
||||
return;
|
||||
}
|
||||
|
||||
if (tracker.entityType(entityId) == EntityTypes1_9.EntityType.BOAT) {
|
||||
byte yaw = wrapper.get(Types.BYTE, 0);
|
||||
yaw -= 64;
|
||||
@@ -475,7 +513,7 @@ public class EntityPacketRewriter1_9 extends VREntityRewriter<ClientboundPackets
|
||||
protocol.registerClientbound(ClientboundPackets1_9.UPDATE_ATTRIBUTES, wrapper -> {
|
||||
final int entityId = wrapper.passthrough(Types.VAR_INT);
|
||||
|
||||
final EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_9To1_8.class);
|
||||
final EntityTracker1_9 tracker = wrapper.user().getEntityTracker(protocol);
|
||||
final boolean player = entityId == tracker.clientEntityId();
|
||||
|
||||
// Throw away new attributes and track attack speed
|
||||
@@ -522,7 +560,7 @@ public class EntityPacketRewriter1_9 extends VREntityRewriter<ClientboundPackets
|
||||
if (effectId > 23) { // Throw away new effects
|
||||
wrapper.cancel();
|
||||
}
|
||||
final EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_9To1_8.class);
|
||||
final EntityTracker1_9 tracker = wrapper.user().getEntityTracker(protocol);
|
||||
if (effectId == 25 && entityId == tracker.clientEntityId()) {
|
||||
final LevitationStorage levitation = wrapper.user().get(LevitationStorage.class);
|
||||
levitation.setActive(true);
|
||||
@@ -541,10 +579,56 @@ public class EntityPacketRewriter1_9 extends VREntityRewriter<ClientboundPackets
|
||||
filter().handler(this::handleEntityData);
|
||||
}
|
||||
|
||||
private void sendDelayedPotionSpawn(final EntityDataHandlerEvent event, final EntityTracker1_9 tracker, final Item item) {
|
||||
final EntityTracker1_9.PendingPotionEntity spawn = tracker.getPendingPotions().remove(event.entityId());
|
||||
if (spawn == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Item converted = protocol.getItemRewriter().handleItemToClient(event.user(), item);
|
||||
short data = converted == null ? 0 : converted.data();
|
||||
if (data <= 0) {
|
||||
data = 16384; // Unmapped potion, at least display a splash bottle
|
||||
}
|
||||
|
||||
final PacketWrapper addEntity = PacketWrapper.create(ClientboundPackets1_8.ADD_ENTITY, event.user());
|
||||
addEntity.write(Types.VAR_INT, event.entityId());
|
||||
addEntity.write(Types.BYTE, (byte) EntityTypes1_9.ObjectType.POTION.getId());
|
||||
addEntity.write(Types.INT, spawn.x());
|
||||
addEntity.write(Types.INT, spawn.y());
|
||||
addEntity.write(Types.INT, spawn.z());
|
||||
addEntity.write(Types.BYTE, spawn.pitch());
|
||||
addEntity.write(Types.BYTE, spawn.yaw());
|
||||
addEntity.write(Types.INT, (int) data);
|
||||
addEntity.write(Types.SHORT, spawn.velocityX());
|
||||
addEntity.write(Types.SHORT, spawn.velocityY());
|
||||
addEntity.write(Types.SHORT, spawn.velocityZ());
|
||||
addEntity.send(Protocol1_9To1_8.class); // Before the entity data is sent
|
||||
|
||||
// 1.8 clients never apply a potion spawn's velocity - vanilla servers send it in a separate
|
||||
// velocity packet after the spawn, so do the same
|
||||
final PacketWrapper setEntityMotion = PacketWrapper.create(ClientboundPackets1_8.SET_ENTITY_MOTION, event.user());
|
||||
setEntityMotion.write(Types.VAR_INT, event.entityId());
|
||||
setEntityMotion.write(Types.SHORT, spawn.velocityX());
|
||||
setEntityMotion.write(Types.SHORT, spawn.velocityY());
|
||||
setEntityMotion.write(Types.SHORT, spawn.velocityZ());
|
||||
setEntityMotion.send(Protocol1_9To1_8.class);
|
||||
}
|
||||
|
||||
private void handleEntityData(EntityDataHandlerEvent event, EntityData entityData) {
|
||||
final EntityTracker1_9 tracker = tracker(event.user());
|
||||
if (event.entityType() == EntityTypes1_9.EntityType.POTION && entityData.value() instanceof Item potionItem) {
|
||||
// No 1.8 equivalent; supplies the object data of the held-back spawn. Matched by value type as the index is version dependent
|
||||
this.sendDelayedPotionSpawn(event, tracker, potionItem);
|
||||
event.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
if (entityData.id() == EntityDataIndex1_9.ENTITY_STATUS.getIndex()) {
|
||||
tracker.getStatus().put(event.entityId(), (Byte) entityData.value());
|
||||
if (tracker.isHandActive(event.entityId())) {
|
||||
entityData.setValue((byte) ((byte) entityData.value() | 1 << STATUS_USE_BIT));
|
||||
}
|
||||
}
|
||||
final EntityDataIndex1_9 metaIndex = EntityDataIndex1_8.searchIndex(event.entityType(), entityData.id());
|
||||
if (metaIndex == null) {
|
||||
@@ -554,8 +638,10 @@ public class EntityPacketRewriter1_9 extends VREntityRewriter<ClientboundPackets
|
||||
}
|
||||
if (metaIndex.getOldType() == null || metaIndex.getNewType() == null) {
|
||||
if (metaIndex == EntityDataIndex1_9.PLAYER_HAND) { // Player eating/aiming/drinking
|
||||
final boolean handActive = (((byte) entityData.value()) & 1 << HAND_ACTIVE_BIT) != 0;
|
||||
tracker.setHandActive(event.entityId(), handActive);
|
||||
byte status = (byte) tracker.getStatus().getOrDefault(event.entityId(), 0);
|
||||
if ((((byte) entityData.value()) & 1 << HAND_ACTIVE_BIT) != 0) {
|
||||
if (handActive) {
|
||||
status = (byte) (status | 1 << STATUS_USE_BIT);
|
||||
} else {
|
||||
status = (byte) (status & ~(1 << STATUS_USE_BIT));
|
||||
|
||||
+96
-23
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -21,13 +21,14 @@ import com.viaversion.nbt.tag.CompoundTag;
|
||||
import com.viaversion.nbt.tag.ListTag;
|
||||
import com.viaversion.nbt.tag.StringTag;
|
||||
import com.viaversion.viarewind.ViaRewind;
|
||||
import com.viaversion.viarewind.api.type.RewindTypes;
|
||||
import com.viaversion.viarewind.protocol.v1_9to1_8.Protocol1_9To1_8;
|
||||
import com.viaversion.viarewind.protocol.v1_9to1_8.data.CommandBlockState;
|
||||
import com.viaversion.viarewind.protocol.v1_9to1_8.provider.InventoryProvider;
|
||||
import com.viaversion.viarewind.protocol.v1_9to1_8.storage.BlockPlaceDestroyTracker;
|
||||
import com.viaversion.viarewind.protocol.v1_9to1_8.storage.BossBarStorage;
|
||||
import com.viaversion.viarewind.protocol.v1_9to1_8.storage.CooldownStorage;
|
||||
import com.viaversion.viarewind.protocol.v1_9to1_8.storage.EntityTracker1_9;
|
||||
import com.viaversion.viarewind.protocol.v1_9to1_8.storage.LastTitle;
|
||||
import com.viaversion.viarewind.protocol.v1_9to1_8.storage.PlayerPositionTracker;
|
||||
import com.viaversion.viarewind.utils.ChatUtil;
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
@@ -43,7 +44,6 @@ import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
|
||||
import com.viaversion.viaversion.api.rewriter.RewriterBase;
|
||||
import com.viaversion.viaversion.api.type.Types;
|
||||
import com.viaversion.viaversion.libs.gson.JsonElement;
|
||||
import com.viaversion.viaversion.libs.gson.JsonParser;
|
||||
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_8;
|
||||
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_9;
|
||||
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ServerboundPackets1_8;
|
||||
@@ -53,6 +53,12 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.viaversion.viarewind.protocol.v1_9to1_8.cooldown.TitleCooldownVisualization.ACTION_HIDE;
|
||||
import static com.viaversion.viarewind.protocol.v1_9to1_8.cooldown.TitleCooldownVisualization.ACTION_RESET;
|
||||
import static com.viaversion.viarewind.protocol.v1_9to1_8.cooldown.TitleCooldownVisualization.ACTION_SET_SUBTITLE;
|
||||
import static com.viaversion.viarewind.protocol.v1_9to1_8.cooldown.TitleCooldownVisualization.ACTION_SET_TIMES_AND_DISPLAY;
|
||||
import static com.viaversion.viarewind.protocol.v1_9to1_8.cooldown.TitleCooldownVisualization.ACTION_SET_TITLE;
|
||||
|
||||
public class PlayerPacketRewriter1_9 extends RewriterBase<Protocol1_9To1_8> {
|
||||
|
||||
public PlayerPacketRewriter1_9(Protocol1_9To1_8 protocol) {
|
||||
@@ -107,6 +113,26 @@ public class PlayerPacketRewriter1_9 extends RewriterBase<Protocol1_9To1_8> {
|
||||
|
||||
protocol.cancelClientbound(ClientboundPackets1_9.COOLDOWN);
|
||||
|
||||
protocol.registerClientbound(ClientboundPackets1_9.SET_TITLES, wrapper -> {
|
||||
final int action = wrapper.passthrough(Types.VAR_INT);
|
||||
if (action == ACTION_SET_TITLE) {
|
||||
final JsonElement title = wrapper.passthrough(Types.COMPONENT);
|
||||
wrapper.user().get(LastTitle.class).setTitle(title);
|
||||
} else if (action == ACTION_SET_SUBTITLE) {
|
||||
final JsonElement subtitle = wrapper.passthrough(Types.COMPONENT);
|
||||
wrapper.user().get(LastTitle.class).setSubtitle(subtitle);
|
||||
} else if (action == ACTION_SET_TIMES_AND_DISPLAY) {
|
||||
final int fadeIn = wrapper.passthrough(Types.INT);
|
||||
final int stay = wrapper.passthrough(Types.INT);
|
||||
final int fadeOut = wrapper.passthrough(Types.INT);
|
||||
wrapper.user().get(LastTitle.class).setTimes(fadeIn, stay, fadeOut);
|
||||
} else if (action == ACTION_HIDE) {
|
||||
wrapper.user().get(LastTitle.class).hide();
|
||||
} else if (action == ACTION_RESET) {
|
||||
wrapper.user().get(LastTitle.class).reset();
|
||||
}
|
||||
});
|
||||
|
||||
protocol.registerClientbound(ClientboundPackets1_9.CUSTOM_PAYLOAD, new PacketHandlers() {
|
||||
@Override
|
||||
public void register() {
|
||||
@@ -133,8 +159,7 @@ public class PlayerPacketRewriter1_9 extends RewriterBase<Protocol1_9To1_8> {
|
||||
map(Types.BYTE); // Relative arguments
|
||||
handler(wrapper -> {
|
||||
final PlayerPositionTracker pos = wrapper.user().get(PlayerPositionTracker.class);
|
||||
|
||||
pos.setConfirmId(wrapper.read(Types.VAR_INT));
|
||||
final int teleportId = wrapper.read(Types.VAR_INT);
|
||||
|
||||
byte flags = wrapper.get(Types.BYTE, 0);
|
||||
double x = wrapper.get(Types.DOUBLE, 0);
|
||||
@@ -143,7 +168,11 @@ public class PlayerPacketRewriter1_9 extends RewriterBase<Protocol1_9To1_8> {
|
||||
float yaw = wrapper.get(Types.FLOAT, 0);
|
||||
float pitch = wrapper.get(Types.FLOAT, 1);
|
||||
|
||||
wrapper.set(Types.BYTE, 0, (byte) 0);
|
||||
// 1.8 supports the rotation-relative flags (0x08/0x10) natively, and resolving them here
|
||||
// would snap the camera to the tracked rotation, which lags the client's live look. Keep
|
||||
// them on the wire and only resolve the position bits (native 1.8 servers use zero-delta
|
||||
// rotation-relative teleports to leave the camera untouched).
|
||||
wrapper.set(Types.BYTE, 0, (byte) (flags & 0x18));
|
||||
|
||||
if (flags != 0) {
|
||||
if ((flags & 0x01) != 0) {
|
||||
@@ -159,18 +188,17 @@ public class PlayerPacketRewriter1_9 extends RewriterBase<Protocol1_9To1_8> {
|
||||
wrapper.set(Types.DOUBLE, 2, z);
|
||||
}
|
||||
if ((flags & 0x08) != 0) {
|
||||
yaw += pos.getYaw();
|
||||
wrapper.set(Types.FLOAT, 0, yaw);
|
||||
yaw += pos.getYaw(); // tracked estimate only; the wire keeps the delta
|
||||
}
|
||||
if ((flags & 0x10) != 0) {
|
||||
pitch += pos.getPitch();
|
||||
wrapper.set(Types.FLOAT, 1, pitch);
|
||||
}
|
||||
}
|
||||
|
||||
pos.setPos(x, y, z);
|
||||
pos.setYaw(yaw);
|
||||
pos.setPitch(pitch);
|
||||
pos.queueTeleport(teleportId, x, y, z, pos.getYaw(), pos.getPitch(), (flags & 0x18) != 0);
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -180,11 +208,11 @@ public class PlayerPacketRewriter1_9 extends RewriterBase<Protocol1_9To1_8> {
|
||||
public void register() {
|
||||
map(Types.INT); // Dimension
|
||||
handler(wrapper -> {
|
||||
final ClientWorld world = wrapper.user().getClientWorld(Protocol1_9To1_8.class);
|
||||
final ClientWorld world = wrapper.user().storables(protocol).clientWorld();
|
||||
final int dimension = wrapper.get(Types.INT, 0);
|
||||
|
||||
if (world.setEnvironment(dimension)) {
|
||||
final EntityTracker tracker = wrapper.user().getEntityTracker(Protocol1_9To1_8.class);
|
||||
final EntityTracker tracker = wrapper.user().getEntityTracker(protocol);
|
||||
tracker.clearEntities();
|
||||
wrapper.user().get(BossBarStorage.class).reset();
|
||||
}
|
||||
@@ -203,7 +231,7 @@ public class PlayerPacketRewriter1_9 extends RewriterBase<Protocol1_9To1_8> {
|
||||
return;
|
||||
}
|
||||
|
||||
final EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_9To1_8.class);
|
||||
final EntityTracker1_9 tracker = wrapper.user().getEntityTracker(protocol);
|
||||
final int entityId = wrapper.passthrough(Types.VAR_INT);
|
||||
wrapper.passthrough(Types.INT); // Killer id
|
||||
|
||||
@@ -273,7 +301,7 @@ public class PlayerPacketRewriter1_9 extends RewriterBase<Protocol1_9To1_8> {
|
||||
handler(wrapper -> {
|
||||
wrapper.user().get(PlayerPositionTracker.class).sendAnimations();
|
||||
|
||||
final EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_9To1_8.class);
|
||||
final EntityTracker1_9 tracker = wrapper.user().getEntityTracker(protocol);
|
||||
if (tracker.isInsideVehicle(tracker.clientEntityId())) {
|
||||
wrapper.cancel();
|
||||
}
|
||||
@@ -291,7 +319,7 @@ public class PlayerPacketRewriter1_9 extends RewriterBase<Protocol1_9To1_8> {
|
||||
handler(wrapper -> {
|
||||
final PlayerPositionTracker storage = wrapper.user().get(PlayerPositionTracker.class);
|
||||
storage.sendAnimations();
|
||||
if (storage.getConfirmId() != -1) {
|
||||
if (storage.hasPendingTeleports()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -311,7 +339,7 @@ public class PlayerPacketRewriter1_9 extends RewriterBase<Protocol1_9To1_8> {
|
||||
handler(wrapper -> {
|
||||
final PlayerPositionTracker storage = wrapper.user().get(PlayerPositionTracker.class);
|
||||
storage.sendAnimations();
|
||||
if (storage.getConfirmId() != -1) {
|
||||
if (storage.hasPendingTeleports()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -333,13 +361,26 @@ public class PlayerPacketRewriter1_9 extends RewriterBase<Protocol1_9To1_8> {
|
||||
|
||||
final PlayerPositionTracker storage = wrapper.user().get(PlayerPositionTracker.class);
|
||||
storage.sendAnimations();
|
||||
if (storage.getConfirmId() != -1) {
|
||||
if (storage.getPosX() == x && storage.getPosY() == y && storage.getPosZ() == z && storage.getYaw() == yaw && storage.getPitch() == pitch) {
|
||||
final PlayerPositionTracker.PendingTeleport teleport = storage.peekTeleport();
|
||||
if (teleport != null) {
|
||||
// 1.7 uses resynced hitbox minY for y however this can have small floating point error due to the calculations it does to get there on teleport confirm
|
||||
// This Y error gets propagated from 1.7 to 1.8 to 1.9 which causes teleport confirmation to not properly be detected
|
||||
// This fixes it similarly to how anticheats detect teleports: https://github.com/GrimAnticheat/Grim/blob/67aa3a9483a9b2a6987d594092697b4104c781f0/common/src/main/java/ac/grim/grimac/manager/SetbackTeleportUtil.java#L315
|
||||
boolean closeEnoughY = Math.abs(teleport.y() - y) <= 1e-7;
|
||||
// A view-relative teleport keeps its rotation deltas on the wire, so the client applies them
|
||||
// to its own live look and echoes that - match on position only and adopt the echoed rotation
|
||||
final boolean rotationMatches = teleport.viewRelative() || (teleport.yaw() == yaw && teleport.pitch() == pitch);
|
||||
|
||||
if (teleport.x() == x && closeEnoughY && teleport.z() == z && rotationMatches) {
|
||||
final PacketWrapper confirmTeleport = PacketWrapper.create(ServerboundPackets1_9.ACCEPT_TELEPORTATION, wrapper.user());
|
||||
confirmTeleport.write(Types.VAR_INT, storage.getConfirmId());
|
||||
confirmTeleport.write(Types.VAR_INT, teleport.id());
|
||||
confirmTeleport.sendToServer(Protocol1_9To1_8.class);
|
||||
|
||||
storage.setConfirmId(-1);
|
||||
if (teleport.viewRelative()) {
|
||||
storage.setYaw(yaw);
|
||||
storage.setPitch(pitch);
|
||||
}
|
||||
storage.confirmTeleport();
|
||||
}
|
||||
} else {
|
||||
storage.setPos(x, y, z);
|
||||
@@ -430,7 +471,7 @@ public class PlayerPacketRewriter1_9 extends RewriterBase<Protocol1_9To1_8> {
|
||||
final float sideways = wrapper.passthrough(Types.FLOAT);
|
||||
final float forward = wrapper.passthrough(Types.FLOAT);
|
||||
|
||||
final EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_9To1_8.class);
|
||||
final EntityTracker1_9 tracker = wrapper.user().getEntityTracker(protocol);
|
||||
final Integer vehicle = tracker.getVehicle(tracker.clientEntityId());
|
||||
|
||||
if (vehicle != null && tracker.entityType(vehicle) == EntityTypes1_9.EntityType.BOAT) {
|
||||
@@ -447,7 +488,7 @@ public class PlayerPacketRewriter1_9 extends RewriterBase<Protocol1_9To1_8> {
|
||||
map(Types.BLOCK_POSITION1_8); // Position
|
||||
handler(wrapper -> {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
final JsonElement json = wrapper.read(RewindTypes.SIGN_COMPONENT);
|
||||
final JsonElement json = wrapper.read(Types.COMPONENT);
|
||||
if (!json.isJsonPrimitive()) {
|
||||
throw new IllegalStateException("Invalid sign text: " + StringUtil.forLogging(json));
|
||||
}
|
||||
@@ -480,7 +521,7 @@ public class PlayerPacketRewriter1_9 extends RewriterBase<Protocol1_9To1_8> {
|
||||
final short flags = wrapper.get(Types.UNSIGNED_BYTE, 0);
|
||||
|
||||
final PacketWrapper updateSkin = PacketWrapper.create(ClientboundPackets1_8.SET_ENTITY_DATA, wrapper.user());
|
||||
updateSkin.write(Types.VAR_INT, wrapper.user().getEntityTracker(Protocol1_9To1_8.class).clientEntityId());
|
||||
updateSkin.write(Types.VAR_INT, wrapper.user().getEntityTracker(protocol).clientEntityId());
|
||||
|
||||
final List<EntityData> entityData = new ArrayList<>();
|
||||
entityData.add(new EntityData(10, EntityDataTypes1_8.BYTE, (byte) flags));
|
||||
@@ -524,7 +565,39 @@ public class PlayerPacketRewriter1_9 extends RewriterBase<Protocol1_9To1_8> {
|
||||
pageTag.setValue(ChatUtil.jsonToLegacy(value));
|
||||
}
|
||||
} else if (channel.equals("MC|AdvCdm")) {
|
||||
wrapper.set(Types.STRING, 0, "MC|AdvCmd");
|
||||
final byte type = wrapper.read(Types.BYTE);
|
||||
if (type == 0) {
|
||||
final int x = wrapper.read(Types.INT);
|
||||
final int y = wrapper.read(Types.INT);
|
||||
final int z = wrapper.read(Types.INT);
|
||||
final CommandBlockState.ParsedCommand command = CommandBlockState.parseDecoratedCommand(wrapper.read(Types.STRING));
|
||||
final boolean trackOutput = wrapper.read(Types.BOOLEAN);
|
||||
if (command.prefixed()) {
|
||||
wrapper.set(Types.STRING, 0, "MC|AutoCmd");
|
||||
wrapper.write(Types.INT, x);
|
||||
wrapper.write(Types.INT, y);
|
||||
wrapper.write(Types.INT, z);
|
||||
wrapper.write(Types.STRING, command.command());
|
||||
wrapper.write(Types.BOOLEAN, trackOutput);
|
||||
wrapper.write(Types.STRING, command.mode());
|
||||
wrapper.write(Types.BOOLEAN, command.conditional());
|
||||
wrapper.write(Types.BOOLEAN, command.automatic());
|
||||
} else {
|
||||
wrapper.set(Types.STRING, 0, "MC|AdvCmd");
|
||||
wrapper.write(Types.BYTE, type);
|
||||
wrapper.write(Types.INT, x);
|
||||
wrapper.write(Types.INT, y);
|
||||
wrapper.write(Types.INT, z);
|
||||
wrapper.write(Types.STRING, command.command());
|
||||
wrapper.write(Types.BOOLEAN, trackOutput);
|
||||
}
|
||||
} else {
|
||||
wrapper.set(Types.STRING, 0, "MC|AdvCmd");
|
||||
wrapper.write(Types.BYTE, type);
|
||||
wrapper.passthrough(Types.INT); // Entity id
|
||||
wrapper.passthrough(Types.STRING); // Command
|
||||
wrapper.passthrough(Types.BOOLEAN); // Track output
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+47
-5
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -22,7 +22,9 @@ import com.viaversion.nbt.tag.StringTag;
|
||||
import com.viaversion.nbt.tag.Tag;
|
||||
import com.viaversion.viarewind.ViaRewind;
|
||||
import com.viaversion.viarewind.protocol.v1_9to1_8.Protocol1_9To1_8;
|
||||
import com.viaversion.viarewind.protocol.v1_9to1_8.data.CommandBlockState;
|
||||
import com.viaversion.viarewind.protocol.v1_9to1_8.data.EffectIdMappings1_8;
|
||||
import com.viaversion.viarewind.protocol.v1_9to1_8.storage.CommandBlockStateStorage;
|
||||
import com.viaversion.viaversion.api.minecraft.BlockPosition;
|
||||
import com.viaversion.viaversion.api.minecraft.Environment;
|
||||
import com.viaversion.viaversion.api.minecraft.chunks.BaseChunk;
|
||||
@@ -57,6 +59,12 @@ public class WorldPacketRewriter1_9 extends RewriterBase<Protocol1_9To1_8> {
|
||||
map(Types.NAMED_COMPOUND_TAG); // Tag
|
||||
handler(wrapper -> {
|
||||
final CompoundTag tag = wrapper.get(Types.NAMED_COMPOUND_TAG, 0);
|
||||
final short action = wrapper.get(Types.UNSIGNED_BYTE, 0);
|
||||
|
||||
if (action == 2) {
|
||||
final BlockPosition position = wrapper.get(Types.BLOCK_POSITION1_8, 0);
|
||||
CommandBlockState.decorateCommand(tag, wrapper.user().get(CommandBlockStateStorage.class).state(position));
|
||||
}
|
||||
|
||||
if (tag.remove("SpawnData") instanceof CompoundTag spawnData) {
|
||||
final Tag id = spawnData.remove("id");
|
||||
@@ -92,9 +100,12 @@ public class WorldPacketRewriter1_9 extends RewriterBase<Protocol1_9To1_8> {
|
||||
String name = wrapper.get(Types.STRING, 0);
|
||||
name = protocol.getMappingData().getMappedNamedSound(name);
|
||||
if (name == null) {
|
||||
wrapper.cancel();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
if (!name.isEmpty()) {
|
||||
wrapper.set(Types.STRING, 0, name);
|
||||
} else {
|
||||
wrapper.cancel();
|
||||
}
|
||||
});
|
||||
read(Types.VAR_INT); // Sound category
|
||||
@@ -110,10 +121,12 @@ public class WorldPacketRewriter1_9 extends RewriterBase<Protocol1_9To1_8> {
|
||||
@Override
|
||||
public void register() {
|
||||
handler(wrapper -> {
|
||||
final Environment environment = wrapper.user().getClientWorld(Protocol1_9To1_8.class).getEnvironment();
|
||||
final Environment environment = wrapper.user().storables(protocol).clientWorld().getEnvironment();
|
||||
final CommandBlockStateStorage commandBlockStates = wrapper.user().get(CommandBlockStateStorage.class);
|
||||
|
||||
final int chunkX = wrapper.read(Types.INT);
|
||||
final int chunkZ = wrapper.read(Types.INT);
|
||||
commandBlockStates.unloadChunk(chunkX, chunkZ);
|
||||
|
||||
wrapper.write(ChunkType1_8.forEnvironment(environment), new BaseChunk(chunkX, chunkZ, true, false, 0, new ChunkSection[16], null, new ArrayList<>()));
|
||||
});
|
||||
@@ -124,9 +137,24 @@ public class WorldPacketRewriter1_9 extends RewriterBase<Protocol1_9To1_8> {
|
||||
@Override
|
||||
public void register() {
|
||||
handler(wrapper -> {
|
||||
final Environment environment = wrapper.user().getClientWorld(Protocol1_9To1_8.class).getEnvironment();
|
||||
final Environment environment = wrapper.user().storables(protocol).clientWorld().getEnvironment();
|
||||
final CommandBlockStateStorage commandBlockStates = wrapper.user().get(CommandBlockStateStorage.class);
|
||||
|
||||
Chunk chunk = wrapper.read(ChunkType1_9_1.forEnvironment(environment));
|
||||
final Chunk originalChunk = chunk;
|
||||
|
||||
chunk.getBlockEntities().forEach(nbt -> {
|
||||
if (!nbt.contains("x") || !nbt.contains("y") || !nbt.contains("z")) {
|
||||
return;
|
||||
}
|
||||
|
||||
final BlockPosition position = new BlockPosition((int) nbt.get("x").getValue(), (int) nbt.get("y").getValue(), (int) nbt.get("z").getValue());
|
||||
final int blockState = blockStateAt(originalChunk, position);
|
||||
if (CommandBlockState.isCommandBlock(blockState)) {
|
||||
commandBlockStates.storeOrRemove(position, blockState);
|
||||
CommandBlockState.decorateCommand(nbt, blockState);
|
||||
}
|
||||
});
|
||||
|
||||
for (ChunkSection section : chunk.getSections()) {
|
||||
if (section == null) continue;
|
||||
@@ -267,4 +295,18 @@ public class WorldPacketRewriter1_9 extends RewriterBase<Protocol1_9To1_8> {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static int blockStateAt(final Chunk chunk, final BlockPosition position) {
|
||||
final int sectionY = position.y() >> 4;
|
||||
if (sectionY < 0 || sectionY >= chunk.getSections().length) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
final ChunkSection section = chunk.getSections()[sectionY];
|
||||
if (section == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return section.palette(PaletteType.BLOCKS).idAt(position.x() & 0xF, position.y() & 0xF, position.z() & 0xF);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.viaversion.viarewind.protocol.v1_9to1_8.storage;
|
||||
|
||||
import com.viaversion.viarewind.protocol.v1_9to1_8.data.CommandBlockState;
|
||||
import com.viaversion.viaversion.api.connection.StorableObject;
|
||||
import com.viaversion.viaversion.api.minecraft.BlockPosition;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
public final class CommandBlockStateStorage implements StorableObject {
|
||||
|
||||
private final Map<BlockPosition, Integer> commandBlockStates = new HashMap<>();
|
||||
|
||||
public void storeOrRemove(final BlockPosition position, final int blockState) {
|
||||
if (CommandBlockState.isCommandBlock(blockState)) {
|
||||
commandBlockStates.put(position, blockState);
|
||||
} else {
|
||||
commandBlockStates.remove(position);
|
||||
}
|
||||
}
|
||||
|
||||
public int state(final BlockPosition position) {
|
||||
return commandBlockStates.getOrDefault(position, -1);
|
||||
}
|
||||
|
||||
public void unloadChunk(final int chunkX, final int chunkZ) {
|
||||
final Iterator<BlockPosition> iterator = commandBlockStates.keySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
final BlockPosition position = iterator.next();
|
||||
if (position.x() >> 4 == chunkX && position.z() >> 4 == chunkZ) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+39
-3
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -18,6 +18,7 @@
|
||||
package com.viaversion.viarewind.protocol.v1_9to1_8.storage;
|
||||
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.api.data.entity.TrackedEntity;
|
||||
import com.viaversion.viaversion.api.minecraft.Vector;
|
||||
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_9;
|
||||
import com.viaversion.viaversion.data.entity.EntityTrackerBase;
|
||||
@@ -27,6 +28,8 @@ import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectMap;
|
||||
import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import com.viaversion.viaversion.libs.fastutil.ints.IntArrayList;
|
||||
import com.viaversion.viaversion.libs.fastutil.ints.IntList;
|
||||
import com.viaversion.viaversion.libs.fastutil.ints.IntOpenHashSet;
|
||||
import com.viaversion.viaversion.libs.fastutil.ints.IntSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -35,20 +38,24 @@ public class EntityTracker1_9 extends EntityTrackerBase {
|
||||
private final Int2ObjectMap<IntList> vehicles = new Int2ObjectOpenHashMap<>();
|
||||
private final Int2ObjectMap<Vector> offsets = new Int2ObjectOpenHashMap<>();
|
||||
private final Int2IntMap status = new Int2IntOpenHashMap();
|
||||
private final IntSet handActive = new IntOpenHashSet();
|
||||
private final Int2ObjectMap<PendingPotionEntity> pendingPotions = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
public EntityTracker1_9(UserConnection connection) {
|
||||
super(connection, EntityTypes1_9.EntityType.PLAYER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeEntity(int id) {
|
||||
public TrackedEntity removeEntity(int id) {
|
||||
vehicles.remove(id);
|
||||
offsets.remove(id);
|
||||
status.remove(id);
|
||||
handActive.remove(id);
|
||||
pendingPotions.remove(id);
|
||||
|
||||
vehicles.forEach((vehicle, passengers) -> passengers.rem(id));
|
||||
vehicles.int2ObjectEntrySet().removeIf(entry -> entry.getValue().isEmpty());
|
||||
super.removeEntity(id);
|
||||
return super.removeEntity(id);
|
||||
}
|
||||
|
||||
public void resetEntityOffset(final int id) {
|
||||
@@ -88,4 +95,33 @@ public class EntityTracker1_9 extends EntityTrackerBase {
|
||||
public Int2IntMap getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public boolean isHandActive(final int id) {
|
||||
return handActive.contains(id);
|
||||
}
|
||||
|
||||
public void setHandActive(final int id, final boolean active) {
|
||||
if (active) {
|
||||
handActive.add(id);
|
||||
} else {
|
||||
handActive.remove(id);
|
||||
}
|
||||
}
|
||||
|
||||
public Int2ObjectMap<PendingPotionEntity> getPendingPotions() {
|
||||
return pendingPotions;
|
||||
}
|
||||
|
||||
public record PendingPotionEntity(int x, int y, int z, byte pitch, byte yaw, short velocityX, short velocityY, short velocityZ) {
|
||||
|
||||
public PendingPotionEntity withPosition(final int x, final int y, final int z, final byte pitch, final byte yaw) {
|
||||
return new PendingPotionEntity(x, y, z, pitch, yaw, velocityX, velocityY, velocityZ);
|
||||
}
|
||||
|
||||
public PendingPotionEntity withVelocity(final short velocityX, final short velocityY, final short velocityZ) {
|
||||
return new PendingPotionEntity(x, y, z, pitch, yaw, velocityX, velocityY, velocityZ);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.viaversion.viarewind.protocol.v1_9to1_8.storage;
|
||||
|
||||
import com.viaversion.viaversion.api.connection.StorableObject;
|
||||
import com.viaversion.viaversion.libs.gson.JsonElement;
|
||||
|
||||
public final class LastTitle implements StorableObject {
|
||||
|
||||
private JsonElement title;
|
||||
private JsonElement subtitle;
|
||||
|
||||
private long visibleSince;
|
||||
private long visibleUntil;
|
||||
|
||||
private int fadeIn;
|
||||
private int stay;
|
||||
private int fadeOut;
|
||||
|
||||
public LastTitle() {
|
||||
this.reset();
|
||||
}
|
||||
|
||||
public void setTitle(final JsonElement title) {
|
||||
this.title = title;
|
||||
|
||||
final long now = System.currentTimeMillis();
|
||||
this.visibleSince = now;
|
||||
this.visibleUntil = now + titleLength();
|
||||
}
|
||||
|
||||
public void setSubtitle(final JsonElement subtitle) {
|
||||
this.subtitle = subtitle;
|
||||
}
|
||||
|
||||
public void setTimes(final int fadeIn, final int stay, final int fadeOut) {
|
||||
this.fadeIn = fadeIn;
|
||||
this.stay = stay;
|
||||
this.fadeOut = fadeOut;
|
||||
|
||||
if (this.visibleUntil > System.currentTimeMillis()) {
|
||||
final long now = System.currentTimeMillis();
|
||||
this.visibleSince = now;
|
||||
this.visibleUntil = now + titleLength();
|
||||
}
|
||||
}
|
||||
|
||||
public void hide() {
|
||||
this.visibleSince = 0;
|
||||
this.visibleUntil = 0;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
this.hide();
|
||||
|
||||
this.fadeIn = 10;
|
||||
this.stay = 70;
|
||||
this.fadeOut = 20;
|
||||
}
|
||||
|
||||
public boolean isVisible() {
|
||||
return this.title != null && this.visibleUntil > System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public JsonElement title() {
|
||||
return this.title;
|
||||
}
|
||||
|
||||
public JsonElement subtitle() {
|
||||
return this.subtitle;
|
||||
}
|
||||
|
||||
public int[] remainingTimes() {
|
||||
final int fullLength = Math.max(0, this.fadeIn + this.stay + this.fadeOut);
|
||||
final int elapsed = (int) Math.min(fullLength, Math.max(0, (System.currentTimeMillis() - this.visibleSince) / 50L));
|
||||
if (elapsed < this.fadeIn) {
|
||||
return new int[]{this.fadeIn - elapsed, this.stay, this.fadeOut};
|
||||
}
|
||||
|
||||
final int titleEnd = this.fadeIn + this.stay;
|
||||
if (elapsed < titleEnd) {
|
||||
return new int[]{0, titleEnd - elapsed, this.fadeOut};
|
||||
}
|
||||
|
||||
return new int[]{0, 0, fullLength - elapsed};
|
||||
}
|
||||
|
||||
private long titleLength() {
|
||||
return Math.max(0, this.fadeIn + this.stay + this.fadeOut) * 50L;
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+17
-6
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -26,10 +26,10 @@ import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
public class PlayerPositionTracker implements StorableObject {
|
||||
|
||||
private final Queue<PacketWrapper> animations = new ConcurrentLinkedQueue<>();
|
||||
private final Queue<PendingTeleport> pendingTeleports = new ConcurrentLinkedQueue<>();
|
||||
private double posX, posY, posZ;
|
||||
private float yaw, pitch;
|
||||
private boolean onGround;
|
||||
private int confirmId = -1;
|
||||
|
||||
public void setPos(double x, double y, double z) {
|
||||
this.posX = x;
|
||||
@@ -84,12 +84,23 @@ public class PlayerPositionTracker implements StorableObject {
|
||||
this.onGround = onGround;
|
||||
}
|
||||
|
||||
public int getConfirmId() {
|
||||
return this.confirmId;
|
||||
public boolean hasPendingTeleports() {
|
||||
return !this.pendingTeleports.isEmpty();
|
||||
}
|
||||
|
||||
public void setConfirmId(int confirmId) {
|
||||
this.confirmId = confirmId;
|
||||
public void queueTeleport(final int id, final double x, final double y, final double z, final float yaw, final float pitch, final boolean viewRelative) {
|
||||
this.pendingTeleports.add(new PendingTeleport(id, x, y, z, yaw, pitch, viewRelative));
|
||||
}
|
||||
|
||||
public PendingTeleport peekTeleport() {
|
||||
return this.pendingTeleports.peek();
|
||||
}
|
||||
|
||||
public void confirmTeleport() {
|
||||
this.pendingTeleports.poll();
|
||||
}
|
||||
|
||||
public record PendingTeleport(int id, double x, double y, double z, float yaw, float pitch, boolean viewRelative) {
|
||||
}
|
||||
|
||||
}
|
||||
+39
-6
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -38,6 +38,9 @@ public class WindowTracker extends StoredObject {
|
||||
private final HashMap<Short, Item[]> brewingItems = new HashMap<>();
|
||||
private final Map<Short, Short> enchantmentProperties = new HashMap<>();
|
||||
|
||||
private short openWindowId = 0;
|
||||
private int openWindowSize = 0; // Translated client container slots, excluding the player inventory
|
||||
|
||||
public WindowTracker(UserConnection user) {
|
||||
super(user);
|
||||
}
|
||||
@@ -52,11 +55,11 @@ public class WindowTracker extends StoredObject {
|
||||
openWindow.write(Types.UNSIGNED_BYTE, windowId);
|
||||
openWindow.write(Types.STRING, "minecraft:brewing_stand");
|
||||
|
||||
TextComponent title = new StringComponent().
|
||||
append(new TranslationComponent("container.brewing")).
|
||||
append(new StringComponent(": " + TextFormatting.DARK_GRAY)).
|
||||
append(new StringComponent(amount + " " + TextFormatting.DARK_RED)).
|
||||
append(new TranslationComponent("item.blazePowder.name", TextFormatting.DARK_RED));
|
||||
TextComponent title = new StringComponent()
|
||||
.append(new TranslationComponent("container.brewing"))
|
||||
.append(new StringComponent(": ").formatted(TextFormatting.DARK_GRAY))
|
||||
.append(new StringComponent(amount + " ").formatted(TextFormatting.DARK_RED))
|
||||
.append(new TranslationComponent("item.blazePowder.name").formatted(TextFormatting.DARK_RED));
|
||||
|
||||
openWindow.write(Types.COMPONENT, TextComponentSerializer.V1_8.serializeJson(title));
|
||||
openWindow.write(Types.UNSIGNED_BYTE, (short) 420);
|
||||
@@ -83,6 +86,36 @@ public class WindowTracker extends StoredObject {
|
||||
public void remove(short windowId) {
|
||||
types.remove(windowId);
|
||||
brewingItems.remove(windowId);
|
||||
if (windowId == openWindowId) {
|
||||
openWindowId = 0;
|
||||
openWindowSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void openWindow(final short windowId, final String windowType, final int slotCount) {
|
||||
openWindowId = windowId;
|
||||
|
||||
// The client only uses the packet's slot count when constructing dynamic inventories.
|
||||
// Fixed menus construct their own slots; use the translated 1.8 layout for those.
|
||||
openWindowSize = switch (windowType) {
|
||||
case "minecraft:furnace", "minecraft:villager", "minecraft:anvil" -> 3;
|
||||
case "minecraft:brewing_stand" -> 4;
|
||||
case "minecraft:beacon" -> 1;
|
||||
case "minecraft:dispenser", "minecraft:dropper" -> 9;
|
||||
case "minecraft:enchanting_table" -> 2;
|
||||
case "minecraft:crafting_table" -> 10;
|
||||
case "minecraft:hopper" -> slotCount;
|
||||
case "EntityHorse" -> slotCount > 2 ? 17 : 2;
|
||||
default -> slotCount / 9 * 9;
|
||||
};
|
||||
}
|
||||
|
||||
public short openWindowId() {
|
||||
return openWindowId;
|
||||
}
|
||||
|
||||
public int openWindowSize() {
|
||||
return openWindowSize;
|
||||
}
|
||||
|
||||
public Item[] getBrewingItems(short windowId) {
|
||||
|
||||
+6
-2
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -26,7 +26,11 @@ public class CooldownIndicatorTask implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
for (UserConnection connection : Via.getManager().getConnectionManager().getConnections()) {
|
||||
connection.get(CooldownStorage.class).tick(connection);
|
||||
final CooldownStorage cooldown = connection.get(CooldownStorage.class);
|
||||
if (cooldown == null) {
|
||||
continue;
|
||||
}
|
||||
cooldown.tick(connection);
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
-2
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -36,12 +36,15 @@ public class LevitationUpdateTask implements Runnable {
|
||||
}
|
||||
for (UserConnection connection : Via.getManager().getConnectionManager().getConnections()) {
|
||||
final LevitationStorage levitation = connection.get(LevitationStorage.class);
|
||||
if (levitation == null) {
|
||||
continue;
|
||||
}
|
||||
if (!levitation.isActive()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final PacketWrapper velocityPacket = PacketWrapper.create(ClientboundPackets1_8.SET_ENTITY_MOTION, connection);
|
||||
velocityPacket.write(Types.VAR_INT, connection.getEntityTracker(Protocol1_9To1_8.class).clientEntityId());
|
||||
velocityPacket.write(Types.VAR_INT, connection.storables(Protocol1_9To1_8.class).entityTracker().clientEntityId());
|
||||
velocityPacket.write(Types.SHORT, (short) 0);
|
||||
velocityPacket.write(Types.SHORT, (short) ((levitation.getAmplifier() + 1) * 360));
|
||||
velocityPacket.write(Types.SHORT, (short) 0);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -49,7 +49,7 @@ public class ChatUtil {
|
||||
try {
|
||||
return jsonToLegacy(JsonParser.parseString(json));
|
||||
} catch (Exception e) {
|
||||
if (!Via.getConfig().isSuppressConversionWarnings()) {
|
||||
if (Via.getConfig().logTextComponentConversionErrors()) {
|
||||
ViaRewind.getPlatform().getLogger().log(Level.WARNING, "Could not convert component to legacy text: " + json, e);
|
||||
}
|
||||
}
|
||||
@@ -71,7 +71,7 @@ public class ChatUtil {
|
||||
}
|
||||
return legacy;
|
||||
} catch (Exception ex) {
|
||||
if (!Via.getConfig().isSuppressConversionWarnings()) {
|
||||
if (Via.getConfig().logTextComponentConversionErrors()) {
|
||||
ViaRewind.getPlatform().getLogger().log(Level.WARNING, "Could not convert component to legacy text: " + component, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,6 +126,7 @@
|
||||
},
|
||||
"180": {
|
||||
"id": "128",
|
||||
"data": "-1",
|
||||
"name": "1.8 Red Sandstone Stairs"
|
||||
},
|
||||
"181": {
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
|
||||
* Copyright (C) 2018-2025 ViaVersion and contributors
|
||||
* Copyright (C) 2018-2026 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
Loaded 100 of 110 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user